From 3bb48adff303282418d071e1cba645329acc3bcb Mon Sep 17 00:00:00 2001 From: Valtteri Harmainen Date: Sat, 5 Oct 2024 16:07:45 +0300 Subject: [PATCH 01/68] Enable type-code-renewal --- webapp/src/cljc/lipas/data/types.cljc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/webapp/src/cljc/lipas/data/types.cljc b/webapp/src/cljc/lipas/data/types.cljc index 01c6c182c..806ca2098 100644 --- a/webapp/src/cljc/lipas/data/types.cljc +++ b/webapp/src/cljc/lipas/data/types.cljc @@ -3,22 +3,22 @@ namespace hosts a controlled place to roll-out the changes." (:require [lipas.data.types-old :as old] - #_[lipas.data.types-new :as new] + [lipas.data.types-new :as new] [lipas.utils :as utils])) (def main-categories - old/main-categories) + new/main-categories) (def sub-categories - old/sub-categories) + new/sub-categories) -(def all old/all) +(def all new/all) (def active (reduce-kv (fn [m k v] (if (not= "active" (:status v)) (dissoc m k) m)) all all)) (def unknown - old/unknown) + new/unknown) (def by-main-category (group-by :main-category (vals active))) (def by-sub-category (group-by :sub-category (vals active))) From 188c1c85c5f6217a4566b54b233de8fa9702a340 Mon Sep 17 00:00:00 2001 From: Valtteri Harmainen Date: Thu, 10 Oct 2024 21:30:41 +0300 Subject: [PATCH 02/68] Fix --- webapp/src/cljc/lipas/data/prop_types_new.cljc | 1 - webapp/src/cljc/lipas/data/types_new.cljc | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/webapp/src/cljc/lipas/data/prop_types_new.cljc b/webapp/src/cljc/lipas/data/prop_types_new.cljc index a0f43b79c..e4f9fbcaa 100644 --- a/webapp/src/cljc/lipas/data/prop_types_new.cljc +++ b/webapp/src/cljc/lipas/data/prop_types_new.cljc @@ -134,7 +134,6 @@ :se "T.ex. lux-mängd eller annan förtydligande information" :en "E.g. lux amount or other specifying information"}}) - ;; Update :weight-lifting-spots-count name and description (assoc-in [:weight-lifting-spots-count :name] {:fi "Painonnostopaikat/nostolavat lkm" diff --git a/webapp/src/cljc/lipas/data/types_new.cljc b/webapp/src/cljc/lipas/data/types_new.cljc index 364facafc..25f4c4396 100644 --- a/webapp/src/cljc/lipas/data/types_new.cljc +++ b/webapp/src/cljc/lipas/data/types_new.cljc @@ -150,8 +150,9 @@ (assoc-in [1130 :props :fitness-stairs-length-m] {:priority 0}) ;; 1140 Parkour-alue - (assoc-in [1140 :props :highest-drop-m] {:priority 0}) + (assoc-in [1140 :props :highest-obstacle-m] {:priority 0}) (assoc-in [1140 :props :climbing-wall?] {:priority 0}) + (assoc-in [1140 :props :lighting-info] {:priority 0}) ;; 1150 skeitti/rullaluistelupaikka (assoc-in [1150 :description :fi] "Rullaluistelua, skeittausta, potkulautailua varten varustettu paikka. Ominaisuustiedoissa tarkemmat tiedot kohteesta.") From 0bdccfa563ab6e70b1e530bab4991c7d6010bd1b Mon Sep 17 00:00:00 2001 From: Valtteri Harmainen Date: Sat, 12 Oct 2024 17:56:40 +0300 Subject: [PATCH 03/68] Enable also new prop_types ... --- webapp/src/cljc/lipas/data/prop_types.cljc | 2 +- webapp/src/cljc/lipas/data/prop_types_new.cljc | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/webapp/src/cljc/lipas/data/prop_types.cljc b/webapp/src/cljc/lipas/data/prop_types.cljc index 74da14d8c..4ba80339a 100644 --- a/webapp/src/cljc/lipas/data/prop_types.cljc +++ b/webapp/src/cljc/lipas/data/prop_types.cljc @@ -6,7 +6,7 @@ [lipas.data.prop-types-new :as new] [lipas.data.prop-types-old :as old])) -(def all old/all) +(def all new/all) (def used (let [used (set (mapcat (comp keys :props second) types/all))] diff --git a/webapp/src/cljc/lipas/data/prop_types_new.cljc b/webapp/src/cljc/lipas/data/prop_types_new.cljc index e4f9fbcaa..37b5e2b3a 100644 --- a/webapp/src/cljc/lipas/data/prop_types_new.cljc +++ b/webapp/src/cljc/lipas/data/prop_types_new.cljc @@ -123,8 +123,8 @@ :se "Antal hål/fairways" :en "Number of holes/fairways"}) - ;; Add new :ligthing-info prop - (assoc :ligthing-info + ;; Add new :lighting-info prop + (assoc :lighting-info {:name {:fi "Valaistuksen lisätieto" :se "Ytterligare information om belysningen" :en "Additional information about the lighting"} From 66b1321579d867e99e476d6d4b0398e8215b6b2d Mon Sep 17 00:00:00 2001 From: Valtteri Harmainen Date: Sat, 12 Oct 2024 17:56:50 +0300 Subject: [PATCH 04/68] Rename "Keilahallit" sub-category to "Keilahallit ja biljardisalit" --- webapp/src/cljc/lipas/data/types_new.cljc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/webapp/src/cljc/lipas/data/types_new.cljc b/webapp/src/cljc/lipas/data/types_new.cljc index 25f4c4396..5ed3c54f0 100644 --- a/webapp/src/cljc/lipas/data/types_new.cljc +++ b/webapp/src/cljc/lipas/data/types_new.cljc @@ -9,7 +9,11 @@ old/main-categories) (def sub-categories - old/sub-categories) + (-> old/sub-categories + ;; alaluokka "Keilahallit" tulee uudelleennimetä "Keilahallit ja biljardisalit" + (assoc-in [2600 :name] {:fi "Keilahallit ja biljardisalit" + :se "Bowlinghallar och biljardsalonger" + :en "Bowling alleys and billiard halls"}))) (def all1 (-> old/all @@ -336,8 +340,10 @@ true (update :props dissoc :kiosk?) + ;; There's unfortunate typo in the + ;; old lighting? prop (contains? (:props v) :ligthing?) - (assoc-in [:props :ligthing-info] {:priority 0})))) + (assoc-in [:props :lighting-info] {:priority 0})))) {})))) (def all4 From dc61a54e426f67e143fe3d26940b21515fe5a5f8 Mon Sep 17 00:00:00 2001 From: Valtteri Harmainen Date: Sat, 12 Oct 2024 18:23:38 +0300 Subject: [PATCH 05/68] Add special field for :space-divisible prop --- .../src/cljc/lipas/data/prop_types_new.cljc | 22 ++++++--- webapp/src/cljc/lipas/schema/core.cljc | 2 +- .../src/cljs/lipas/ui/sports_sites/views.cljs | 47 +++++++++++++++++++ 3 files changed, 63 insertions(+), 8 deletions(-) diff --git a/webapp/src/cljc/lipas/data/prop_types_new.cljc b/webapp/src/cljc/lipas/data/prop_types_new.cljc index 37b5e2b3a..624fda29c 100644 --- a/webapp/src/cljc/lipas/data/prop_types_new.cljc +++ b/webapp/src/cljc/lipas/data/prop_types_new.cljc @@ -212,15 +212,23 @@ :en ""}}) ;; Add new :space-divisible prop + + ;; Toteutus esim: Valinta Kyllä/Ei -> Jos kyllä, täydennettävä + ;; kenttä "Tila voidaan jakaa x osaan" (voidaan syöttää lukuarvo + ;; esim. 2, joka tarkoittaa että tila voidaan jakaa kahteen + ;; osaan). (assoc :space-divisible - {:name {:fi "Tila jaettavissa osiin" - :se "Utrymmet kan delas upp" - :en "Space can be divided"} - :data-type "boolean" + {:name {:fi "Tila jaettavissa osiin" + :se "Utrymmet kan delas upp" + :en "Space can be divided"} + :helper-text {:fi "Syötä numero moneenko osaan tila on jaettavissa" + :se "Ange antalet delar som utrymmet kan delas in i" + :en "Enter the number of sections into which the space can be divided"} + :data-type "number" :description - {:fi "" - :se "" - :en ""}}) + {:fi "Onko tila jaettavissa osiin esim. jakoseinien tai -verhojen avulla" + :se "Är utrymmet delbart i sektioner, till exempel med skiljeväggar eller gardiner?" + :en "Is the space divisible into sections, for example, with partition walls or curtains?"}}) ;; Add new :auxiliary-training-area prop (assoc :auxiliary-training-area diff --git a/webapp/src/cljc/lipas/schema/core.cljc b/webapp/src/cljc/lipas/schema/core.cljc index 375b37649..5b72531b3 100644 --- a/webapp/src/cljc/lipas/schema/core.cljc +++ b/webapp/src/cljc/lipas/schema/core.cljc @@ -733,7 +733,7 @@ (s/def :lipas.sports-site.properties/fitness-stairs-length-m ::real) (s/def :lipas.sports-site.properties/fitness-stairs-length-m ::real) (s/def :lipas.sports-site.properties/free-customer-use? boolean?) -(s/def :lipas.sports-site.properties/space-divisible string?) +(s/def :lipas.sports-site.properties/space-divisible ::real) (s/def :lipas.sports-site.properties/auxiliary-training-area? boolean?) (s/def :lipas.sports-site.properties/sport-specification string?) (s/def :lipas.sports-site.properties/width-of-active-space-m ::real) diff --git a/webapp/src/cljs/lipas/ui/sports_sites/views.cljs b/webapp/src/cljs/lipas/ui/sports_sites/views.cljs index b5a9c90b1..02a55ae4e 100644 --- a/webapp/src/cljs/lipas/ui/sports_sites/views.cljs +++ b/webapp/src/cljs/lipas/ui/sports_sites/views.cljs @@ -503,6 +503,25 @@ :items (-> data :edit-data :rinks) :lipas-id (-> data :edit-data :lipas-id)}])])) +(defn space-divisible-field + [{:keys [tr value label helper-text tooltip on-change spec disabled?] :as props}] + (r/with-let [checkbox-state (r/atom (some? value))] + [:<> + [lui/checkbox + {:label label + :value @checkbox-state + :on-change #(reset! checkbox-state %)}] + (when @checkbox-state + [lui/text-field + {:value value + :label helper-text + :disabled disabled? + :tooltip tooltip + :spec spec + :type "number" + :on-change on-change}])]) + ) + ;; Used from activities -> lipas-property now ;; Regular perustiedot uses the properties-form directly, which doesn't use this (defn make-prop-field @@ -513,6 +532,7 @@ spec (keyword :lipas.sports-site.properties prop-k) disabled? read-only? label (or label (get-in prop-type [:name locale])) + helper-text (get-in prop-type [:helper-text locale]) tooltip (or description (get-in prop-type [:description locale])) data-type (get prop-type :data-type) on-change set-field @@ -558,6 +578,18 @@ :tooltip tooltip :geoms geoms :on-change on-change}] + + (= :space-divisible k) [space-divisible-field + {:tr tr + :value value + :helper-text helper-text + :type "number" + :spec spec + :label label + :tooltip tooltip + :geoms geoms + :on-change on-change}] + (= "boolean" data-type) [lui/checkbox {:value value :label label @@ -585,6 +617,7 @@ "number") :on-change on-change}]))) +;; TODO refactor to use `make-prop-field` function above (defn properties-form [{:keys [tr edit-data editing? display-data type-code on-change read-only? key geoms geom-type problems? width pools]}] @@ -641,6 +674,7 @@ (into (for [[k v] types-props :let [label (-> types-props k :name locale) + helper-text (-> types-props k :helper-text locale) data-type (:data-type v) tooltip (if (:derived? v) "Lasketaan automaattisesti olosuhdetiedoista" @@ -653,6 +687,7 @@ :value (-> display-data k) :disabled? disabled? :priority (:priority v) + ;; TODO Could be nicer with a multi-method :form-field (cond (material-field? k) [surface-material-selector @@ -694,6 +729,18 @@ :tooltip tooltip :geoms geoms :on-change on-change}] + + (= :space-divisible k) [space-divisible-field + {:tr tr + :value value + :type "number" + :helper-text helper-text + :spec spec + :label label + :tooltip tooltip + :geoms geoms + :on-change on-change}] + (= "boolean" data-type) [lui/checkbox {:value value :tooltip tooltip From f85b5bc800e886c7664ba665e315e2548d529718 Mon Sep 17 00:00:00 2001 From: Valtteri Harmainen Date: Tue, 15 Oct 2024 18:41:20 +0300 Subject: [PATCH 06/68] Several small fixes to type changes --- .../src/cljc/lipas/data/prop_types_new.cljc | 74 ++++++++++++++++++- webapp/src/cljc/lipas/data/types_new.cljc | 2 +- webapp/src/cljc/lipas/schema/core.cljc | 13 +++- .../src/cljs/lipas/ui/sports_sites/views.cljs | 24 ++++++ 4 files changed, 105 insertions(+), 8 deletions(-) diff --git a/webapp/src/cljc/lipas/data/prop_types_new.cljc b/webapp/src/cljc/lipas/data/prop_types_new.cljc index 624fda29c..d029f9abd 100644 --- a/webapp/src/cljc/lipas/data/prop_types_new.cljc +++ b/webapp/src/cljc/lipas/data/prop_types_new.cljc @@ -231,7 +231,7 @@ :en "Is the space divisible into sections, for example, with partition walls or curtains?"}}) ;; Add new :auxiliary-training-area prop - (assoc :auxiliary-training-area + (assoc :auxiliary-training-area? {:name {:fi "Oheisharjoittelutila" :se "Kompletterande träningsområde" :en "Auxiliary training area"} @@ -242,11 +242,50 @@ :en ""}}) ;; Add new :sport-specification prop + + ;; Ominaisuuden nimi esim. "Lajitarkenne". Vastaava + ;; toiminnallisuus kuin veneilyn palvelupaikoissa - eli + ;; lisätiedoissa voidaan tarkentaa, minkä voimistelulajin + ;; harrastamiseen kohde on pääasiassa tarkoitettu. Vaihtoehdot: + ;; a. Lattialajit b. Telinelajit c. Lattia- ja telinelajit + ;; mahdollisia d. Pääasiassa cheerleading- tai + ;; sirkusharjoittelukäyttöön e. Ei tietoa (assoc :sport-specification {:name {:fi "Lajitarkenne" :se "Sportspecifikation" :en "Sport specification"} - :data-type "string" + :data-type "enum" + :opts {"floor-disciplines" + {:label {:fi "Lattialajit" :en "Floor disciplines" :se "Golvdiscipliner"} + :description + {:fi "Voimistelulajit, jotka suoritetaan pääasiassa lattialla." + :en "Gymnastics disciplines that are primarily performed on the floor." + :se "Gymnastikdiscipliner som huvudsakligen utförs på golvet."}} + + "apparatus-disciplines" + {:label {:fi "Telinelajit" :en "Apparatus disciplines" :se "Redskapsgrenar"} + :description + {:fi "Voimistelulajit, jotka suoritetaan erilaisilla telineillä." + :en "Gymnastics disciplines that are performed on various apparatus." + :se "Gymnastikdiscipliner som utförs på olika redskap."}} + + "floor-and-apparatus" + {:label {:fi "Lattia- ja telinelajit mahdollisia" :en "Both floor and apparatus disciplines possible" :se "Både golv- och redskapsgrenar möjliga"} + :description + {:fi "Tilassa voidaan harjoitella sekä lattia- että telinelajeja." + :en "The space allows for practicing both floor and apparatus disciplines." + :se "Utrymmet möjliggör träning av både golv- och redskapsgrenar."}} + + "cheerleading-circus" + {:label {:fi "Pääasiassa cheerleading- tai sirkusharjoittelukäyttöön" :en "Mainly for cheerleading or circus training" :se "Huvudsakligen för cheerleading- eller cirkusträning"} + :description + {:fi "Tila on ensisijaisesti tarkoitettu cheerleading- tai sirkusharjoitteluun." + :en "The space is primarily intended for cheerleading or circus training." + :se "Utrymmet är främst avsett för cheerleading- eller cirkusträning."}} + + "no-information" + {:label {:fi "Ei tietoa" :en "No information" :se "Ingen information"}}} + :description {:fi "" :se "" @@ -290,7 +329,34 @@ {:name {:fi "Parkour-salin varustelu ja rakenteet" :se "Utrustning och strukturer i parkourhallen" :en "Parkour hall equipment and structures"} - :data-type "string" + :data-type "enum-coll" + :opts {"fixed-obstacles" + {:label {:fi "Kiinteät esteet / rakennelmat" :en "Fixed obstacles / structures" :se "Fasta hinder / strukturer"} + :description + {:fi "Pysyvästi asennetut esteet tai rakennelmat harjoittelua varten." + :en "Permanently installed obstacles or structures for training purposes." + :se "Permanent installerade hinder eller strukturer för träningsändamål."}} + + "movable-obstacles" + {:label {:fi "Liikkuvat esteet / rakennelmat" :en "Movable obstacles / structures" :se "Flyttbara hinder / strukturer"} + :description + {:fi "Siirrettävät tai muunneltavat esteet ja rakennelmat harjoittelua varten." + :en "Movable or adjustable obstacles and structures for training purposes." + :se "Flyttbara eller justerbara hinder och strukturer för träningsändamål."}} + + "floor-acrobatics-area" + {:label {:fi "Permanto/akrobatiatila" :en "Floor/acrobatics area" :se "Golv/akrobatikområde"} + :description + {:fi "Avoin tila lattiaharjoittelua ja akrobaattisia liikkeitä varten." + :en "Open space for floor exercises and acrobatic movements." + :se "Öppet utrymme för golvövningar och akrobatiska rörelser."}} + + "gym-strength-area" + {:label {:fi "Kuntosali-/voimailutila" :en "Gym/strength training area" :se "Gym/styrketräningsområde"} + :description + {:fi "Alue, joka on varustettu kuntosalilaitteilla ja välineillä voimaharjoittelua varten." + :en "Area equipped with gym machines and equipment for strength training." + :se "Område utrustat med gymmaskiner och utrustning för styrketräning."}}} :description {:fi "" :se "" @@ -426,7 +492,7 @@ (assoc-in [:highest-obstacle-m :description :fi] "Korkeimman esteen korkeus (m)") ;; Pintamateriaalikentän valittavissa seuraavista ne ominaisuudet, jotka saliin sopivat: a) Kiinteät esteet / rakennelmat b) Liikkuvat esteet / rakennelmat c) Permanto/akrobatiatila d) Kuntosali-/voimailutila (assoc-in [:parkour-hall-equipment-and-structures :description :fi] "Valitse parkour-salissa olevat rakenteet tai varusteet") - (assoc-in [:ringette-boundary-markings :description :fi] "Onko kaukaloissa ringeten rajamerkinnät?") + (assoc-in [:ringette-boundary-markings? :description :fi] "Onko kaukaloissa ringeten rajamerkinnät?") (assoc-in [:swimming-pool-count :name :fi] "Altaiden lukumäärä") ;; Laskenta mahdollista tehdä automaattisesti syötettyjen altaiden perusteella (lasketaan yksinkertaisesti kaikki altaat yhteen tai luvun voi tarvittaessa korjata käsin, samaan tapaan kuin reittien pituuslaskuri toimii) (assoc-in [:swimming-pool-count :description :fi] "Altaiden lukumäärä yhteensä. Syötä tieto tai laske automaattisesti.") diff --git a/webapp/src/cljc/lipas/data/types_new.cljc b/webapp/src/cljc/lipas/data/types_new.cljc index 5ed3c54f0..33a750b0f 100644 --- a/webapp/src/cljc/lipas/data/types_new.cljc +++ b/webapp/src/cljc/lipas/data/types_new.cljc @@ -493,7 +493,7 @@ ;; Devissä tietokentän nimenä on vielä "Vapaa käyttö" -> Pitäisi olla "Kohde on vapaasti käytettävissä" (assoc-in [2510 :props :free-use?] {:priority 0}) (assoc-in [2520 :description :fi] "Kilpajäähalli on jääurheilun kilpailu- ja ottelutapahtumiin soveltuva jäähalli. Katsomon koko, kenttien lukumäärä ja muut tarkemmat tiedot kuvataan lisätiedoissa.") - (assoc-in [2520 :props :ringette-boundary-markings] {:priority 0}) + (assoc-in [2520 :props :ringette-boundary-markings?] {:priority 0}) ;; Olisiko kenttien/kaukaloiden tiedonhallintaa mahdollista helpottaa Lipaksessa (mallia esim. uimahallien altaista tai salibandyn ominaisuustiedoista?) (assoc-in [2520 :props :field-1-flexible-rink?] {:priority 0}) ;; Olisiko kenttien/kaukaloiden tiedonhallintaa mahdollista helpottaa Lipaksessa (mallia esim. uimahallien altaista tai salibandyn ominaisuustiedoista?) diff --git a/webapp/src/cljc/lipas/schema/core.cljc b/webapp/src/cljc/lipas/schema/core.cljc index 5b72531b3..fe3d28b33 100644 --- a/webapp/src/cljc/lipas/schema/core.cljc +++ b/webapp/src/cljc/lipas/schema/core.cljc @@ -13,6 +13,7 @@ [lipas.data.loi :as loi] [lipas.data.materials :as materials] [lipas.data.owners :as owners] + [lipas.data.prop-types :as prop-types] [lipas.data.reminders :as reminders] [lipas.data.sports-sites :as sports-sites] [lipas.data.swimming-pools :as swimming-pools] @@ -724,7 +725,8 @@ (s/def :lipas.sports-site.properties/canoeing-club? boolean?) (s/def :lipas.sports-site.properties/activity-service-company? boolean?) (s/def :lipas.sports-site.properties/boating-service-class string?) -(s/def :lipas.sports-site.properties/water-point string?) +(s/def :lipas.sports-site.properties/water-point + (into #{} (keys (get-in prop-types/all [:water-point :opts])))) (s/def :lipas.sports-site.properties/customer-service-point? boolean?) (s/def :lipas.sports-site.properties/height-of-basket-or-net-adjustable? boolean?) (s/def :lipas.sports-site.properties/changing-rooms-m2 ::real) @@ -739,7 +741,9 @@ (s/def :lipas.sports-site.properties/width-of-active-space-m ::real) (s/def :lipas.sports-site.properties/length-of-active-space-m ::real) (s/def :lipas.sports-site.properties/mirror-wall? boolean?) -(s/def :lipas.sports-site.properties/parkour-hall-equipment-and-structures string?) +(s/def :lipas.sports-site.properties/parkour-hall-equipment-and-structures + (s/coll-of + (into #{} (keys (get-in prop-types/all [:parkour-hall-equipment-and-structures :opts]))))) (s/def :lipas.sports-site.properties/ringette-boundary-markings? boolean?) (s/def :lipas.sports-site.properties/field-1-flexible-rink? boolean?) (s/def :lipas.sports-site.properties/field-2-flexible-rink? boolean?) @@ -750,6 +754,9 @@ (s/def :lipas.sports-site.properties/pyramid-tables-count ::real) (s/def :lipas.sports-site.properties/carom-tables-count ::real) (s/def :lipas.sports-site.properties/total-billiard-tables-count ::real) +(s/def :lipas.sports-site.properties/boating-service-class + (s/coll-of + (into #{} (keys (get-in prop-types/all [:boating-service-class :opts]))))) (s/def :lipas.sports-site/properties (s/keys :opt-un [:lipas.sports-site.properties/height-m @@ -934,7 +941,7 @@ :lipas.sports-site.properties/pyramid-tables-count :lipas.sports-site.properties/carom-tables-count :lipas.sports-site.properties/total-billiard-tables-count - ])) + :lipas.sports-site.properties/boating-service-class])) (s/def :lipas.sports-site/properties-old (s/map-of keyword? (s/or :string? (str-in 1 100) diff --git a/webapp/src/cljs/lipas/ui/sports_sites/views.cljs b/webapp/src/cljs/lipas/ui/sports_sites/views.cljs index 02a55ae4e..53b78ac88 100644 --- a/webapp/src/cljs/lipas/ui/sports_sites/views.cljs +++ b/webapp/src/cljs/lipas/ui/sports_sites/views.cljs @@ -605,8 +605,20 @@ :label label :disabled disabled? :value-fn first + :on-change on-change :label-fn (comp locale :name second)}] + (= "enum-coll" data-type k) [lui/multi-select + {:items (:opts prop-type) + :deselect? true + :value value + :helper-text tooltip + :on-change on-change + :label label + :disabled disabled? + :value-fn first + :label-fn (comp locale :name second)}] + :else [lui/text-field {:value value :label label @@ -746,6 +758,7 @@ :tooltip tooltip :disabled disabled? :on-change on-change}] + (= "enum" data-type) [lui/select {:items (:opts v) :deselect? true @@ -757,6 +770,17 @@ :value-fn first :label-fn (comp locale :label second)}] + (= "enum-coll" data-type) [lui/autocomplete + {:multi? true + :items (:opts v) + :deselect? true + :value value + :helper-text tooltip + :on-change on-change + :label label + :disabled disabled? + :value-fn first + :label-fn (comp locale :label second)}] :else (let [el [lui/text-field {;; form ->field adds the :label, but that doesn't work From 97d12458524c4aa4bd2cf1deadb1058a68c4f08b Mon Sep 17 00:00:00 2001 From: Valtteri Harmainen Date: Sun, 20 Oct 2024 11:44:34 +0300 Subject: [PATCH 07/68] Add symbols for new types --- webapp/src/cljc/lipas/data/styles.cljc | 87 +++++++++++++++++++------- 1 file changed, 65 insertions(+), 22 deletions(-) diff --git a/webapp/src/cljc/lipas/data/styles.cljc b/webapp/src/cljc/lipas/data/styles.cljc index 91430281f..ac29dffa2 100644 --- a/webapp/src/cljc/lipas/data/styles.cljc +++ b/webapp/src/cljc/lipas/data/styles.cljc @@ -126,11 +126,6 @@ :radius 9, :fill {:color "#8fed75"}, :stroke {:color "#000000"}}, - 1190 - {:shape "circle", - :radius 9, - :fill {:color "#ffffff"}, - :stroke {:color "#000000"}}, 4422 {:shape "linestring", :stroke @@ -154,10 +149,6 @@ :radius 9, :fill {:color "#73d28b"}, :stroke {:color "#004800"}}, - 106 - {:shape "polygon", - :fill {:color "#50e76a"}, - :stroke {:color "#000000", :width 1.5}}, 4610 {:shape "circle", :radius 9, @@ -217,11 +208,6 @@ :radius 9, :fill {:color "#00c100"}, :stroke {:color "#ff5500"}}, - 4840 - {:shape "circle", - :radius 9, - :fill {:color "#dcc210"}, - :stroke {:color "#aa0000"}}, 1510 {:shape "circle", :radius 9, @@ -523,10 +509,6 @@ :radius 9, :fill {:color "#62d53c"}, :stroke {:color "#000000"}}, - 1650 - {:shape "polygon", - :fill {:color "#62d53c"}, - :stroke {:color "#000000" :width 1.5}}, 2250 {:shape "square", :radius 9, @@ -757,18 +739,79 @@ :line-join "round", :line-dash [5 2]}, :fill {:color "#000000"}} + ;; Rullahiihtorata + 4407 + {:shape "linestring", + :stroke + {:color "#f77ec3", + :width 3.5, + :line-cap "round", + :line-join "round", + :line-dash [5 2]}, + :fill {:color "#000000"}} + ;; Monikäyttöreitti + 4406 + {:shape "linestring", + :stroke + {:color "#665e8a", + :width 3.5, + :line-cap "round", + :line-join "round", + :line-dash [5 2]}, + :fill {:color "#000000"}} + ;; Koiravaljakkoreitti + 4441 + {:shape "linestring", + :stroke + {:color "#80a172", + :width 3.5, + :line-cap "round", + :line-join "round", + :line-dash [5 2]}, + :fill {:color "#000000"}} + ;; Ovaalirata + 6150 + {:shape "circle", + :radius 9, + :fill {:color "#f0c39e"}, + :stroke {:color "#000000"}} + ;;Pulkkamäki + 1190 + {:shape "circle", + :radius 9, + :fill {:color "#f2d3ef"}, + :stroke {:color "#000000"}} + ;; Golfkenttä (alue) + 1650 + {:shape "polygon", + :fill {:color "#9efa52"}, + :stroke {:color "#000000" :width 1.5}} + ;; Sisäleikki-/aktiviteettipuisto: 2225 {:shape "square", :radius 9, - :fill {:color "#ac6c46"}, + :fill {:color "#d9936a"}, :stroke {:color "#000000"}} + ;; Biljardisali 2620 {:shape "square", :radius 9, - :fill {:color "#ac6c46"}, + :fill {:color "#9afcc0"}, :stroke {:color "#000000"}} 3250 {:shape "circle", :radius 9, - :fill {:color "#aaaaff"}, - :stroke {:color "#000000"}}}) + :fill {:color "#6e6d91"}, + :stroke {:color "#000000"}} + ;; Jousiammuntamaastorata + 4840 + {:shape "circle", + :radius 9, + :fill {:color "#948938"}, + :stroke {:color "#000000"}} + ;; Monikäyttöalueet ja virkistysmetsät, joissa on virkistyspalveluita + 106 + {:shape "polygon", + :fill {:color "#99d18f"}, + :stroke {:color "#000000" :width 1.5}} + }) From 18007405e0306aad9b06bcd434d80c9d51a87119 Mon Sep 17 00:00:00 2001 From: Valtteri Harmainen Date: Sun, 20 Oct 2024 15:12:18 +0300 Subject: [PATCH 08/68] Add final batch of type changes --- .../src/cljc/lipas/data/prop_types_new.cljc | 226 ++++++++++---- .../src/cljc/lipas/data/prop_types_old.cljc | 4 +- webapp/src/cljc/lipas/data/types_new.cljc | 279 +++++++++++++++++- 3 files changed, 449 insertions(+), 60 deletions(-) diff --git a/webapp/src/cljc/lipas/data/prop_types_new.cljc b/webapp/src/cljc/lipas/data/prop_types_new.cljc index d029f9abd..cd6cc88c2 100644 --- a/webapp/src/cljc/lipas/data/prop_types_new.cljc +++ b/webapp/src/cljc/lipas/data/prop_types_new.cljc @@ -255,36 +255,36 @@ :se "Sportspecifikation" :en "Sport specification"} :data-type "enum" - :opts {"floor-disciplines" - {:label {:fi "Lattialajit" :en "Floor disciplines" :se "Golvdiscipliner"} - :description - {:fi "Voimistelulajit, jotka suoritetaan pääasiassa lattialla." - :en "Gymnastics disciplines that are primarily performed on the floor." - :se "Gymnastikdiscipliner som huvudsakligen utförs på golvet."}} - - "apparatus-disciplines" - {:label {:fi "Telinelajit" :en "Apparatus disciplines" :se "Redskapsgrenar"} - :description - {:fi "Voimistelulajit, jotka suoritetaan erilaisilla telineillä." - :en "Gymnastics disciplines that are performed on various apparatus." - :se "Gymnastikdiscipliner som utförs på olika redskap."}} - - "floor-and-apparatus" - {:label {:fi "Lattia- ja telinelajit mahdollisia" :en "Both floor and apparatus disciplines possible" :se "Både golv- och redskapsgrenar möjliga"} - :description - {:fi "Tilassa voidaan harjoitella sekä lattia- että telinelajeja." - :en "The space allows for practicing both floor and apparatus disciplines." - :se "Utrymmet möjliggör träning av både golv- och redskapsgrenar."}} - - "cheerleading-circus" - {:label {:fi "Pääasiassa cheerleading- tai sirkusharjoittelukäyttöön" :en "Mainly for cheerleading or circus training" :se "Huvudsakligen för cheerleading- eller cirkusträning"} - :description - {:fi "Tila on ensisijaisesti tarkoitettu cheerleading- tai sirkusharjoitteluun." - :en "The space is primarily intended for cheerleading or circus training." - :se "Utrymmet är främst avsett för cheerleading- eller cirkusträning."}} - - "no-information" - {:label {:fi "Ei tietoa" :en "No information" :se "Ingen information"}}} + :opts {"floor-disciplines" + {:label {:fi "Lattialajit" :en "Floor disciplines" :se "Golvdiscipliner"} + :description + {:fi "Voimistelulajit, jotka suoritetaan pääasiassa lattialla." + :en "Gymnastics disciplines that are primarily performed on the floor." + :se "Gymnastikdiscipliner som huvudsakligen utförs på golvet."}} + + "apparatus-disciplines" + {:label {:fi "Telinelajit" :en "Apparatus disciplines" :se "Redskapsgrenar"} + :description + {:fi "Voimistelulajit, jotka suoritetaan erilaisilla telineillä." + :en "Gymnastics disciplines that are performed on various apparatus." + :se "Gymnastikdiscipliner som utförs på olika redskap."}} + + "floor-and-apparatus" + {:label {:fi "Lattia- ja telinelajit mahdollisia" :en "Both floor and apparatus disciplines possible" :se "Både golv- och redskapsgrenar möjliga"} + :description + {:fi "Tilassa voidaan harjoitella sekä lattia- että telinelajeja." + :en "The space allows for practicing both floor and apparatus disciplines." + :se "Utrymmet möjliggör träning av både golv- och redskapsgrenar."}} + + "cheerleading-circus" + {:label {:fi "Pääasiassa cheerleading- tai sirkusharjoittelukäyttöön" :en "Mainly for cheerleading or circus training" :se "Huvudsakligen för cheerleading- eller cirkusträning"} + :description + {:fi "Tila on ensisijaisesti tarkoitettu cheerleading- tai sirkusharjoitteluun." + :en "The space is primarily intended for cheerleading or circus training." + :se "Utrymmet är främst avsett för cheerleading- eller cirkusträning."}} + + "no-information" + {:label {:fi "Ei tietoa" :en "No information" :se "Ingen information"}}} :description {:fi "" @@ -330,33 +330,33 @@ :se "Utrustning och strukturer i parkourhallen" :en "Parkour hall equipment and structures"} :data-type "enum-coll" - :opts {"fixed-obstacles" - {:label {:fi "Kiinteät esteet / rakennelmat" :en "Fixed obstacles / structures" :se "Fasta hinder / strukturer"} - :description - {:fi "Pysyvästi asennetut esteet tai rakennelmat harjoittelua varten." - :en "Permanently installed obstacles or structures for training purposes." - :se "Permanent installerade hinder eller strukturer för träningsändamål."}} - - "movable-obstacles" - {:label {:fi "Liikkuvat esteet / rakennelmat" :en "Movable obstacles / structures" :se "Flyttbara hinder / strukturer"} - :description - {:fi "Siirrettävät tai muunneltavat esteet ja rakennelmat harjoittelua varten." - :en "Movable or adjustable obstacles and structures for training purposes." - :se "Flyttbara eller justerbara hinder och strukturer för träningsändamål."}} - - "floor-acrobatics-area" - {:label {:fi "Permanto/akrobatiatila" :en "Floor/acrobatics area" :se "Golv/akrobatikområde"} - :description - {:fi "Avoin tila lattiaharjoittelua ja akrobaattisia liikkeitä varten." - :en "Open space for floor exercises and acrobatic movements." - :se "Öppet utrymme för golvövningar och akrobatiska rörelser."}} - - "gym-strength-area" - {:label {:fi "Kuntosali-/voimailutila" :en "Gym/strength training area" :se "Gym/styrketräningsområde"} - :description - {:fi "Alue, joka on varustettu kuntosalilaitteilla ja välineillä voimaharjoittelua varten." - :en "Area equipped with gym machines and equipment for strength training." - :se "Område utrustat med gymmaskiner och utrustning för styrketräning."}}} + :opts {"fixed-obstacles" + {:label {:fi "Kiinteät esteet / rakennelmat" :en "Fixed obstacles / structures" :se "Fasta hinder / strukturer"} + :description + {:fi "Pysyvästi asennetut esteet tai rakennelmat harjoittelua varten." + :en "Permanently installed obstacles or structures for training purposes." + :se "Permanent installerade hinder eller strukturer för träningsändamål."}} + + "movable-obstacles" + {:label {:fi "Liikkuvat esteet / rakennelmat" :en "Movable obstacles / structures" :se "Flyttbara hinder / strukturer"} + :description + {:fi "Siirrettävät tai muunneltavat esteet ja rakennelmat harjoittelua varten." + :en "Movable or adjustable obstacles and structures for training purposes." + :se "Flyttbara eller justerbara hinder och strukturer för träningsändamål."}} + + "floor-acrobatics-area" + {:label {:fi "Permanto/akrobatiatila" :en "Floor/acrobatics area" :se "Golv/akrobatikområde"} + :description + {:fi "Avoin tila lattiaharjoittelua ja akrobaattisia liikkeitä varten." + :en "Open space for floor exercises and acrobatic movements." + :se "Öppet utrymme för golvövningar och akrobatiska rörelser."}} + + "gym-strength-area" + {:label {:fi "Kuntosali-/voimailutila" :en "Gym/strength training area" :se "Gym/styrketräningsområde"} + :description + {:fi "Alue, joka on varustettu kuntosalilaitteilla ja välineillä voimaharjoittelua varten." + :en "Area equipped with gym machines and equipment for strength training." + :se "Område utrustat med gymmaskiner och utrustning för styrketräning."}}} :description {:fi "" :se "" @@ -498,6 +498,118 @@ (assoc-in [:swimming-pool-count :description :fi] "Altaiden lukumäärä yhteensä. Syötä tieto tai laske automaattisesti.") (assoc-in [:pool-water-area-m2 :description :fi] "Asiakaskäytössä oleva vesipinta-ala yhteensä.") + + ;;; Maasto ja loput ;;; + + ;; Add new pulkkamäki prop-type + (assoc :sledding-hill? + {:name + {:fi "Pulkkamäki" + :se "Pulkabacke" + :en "Sledding hill"} + :data-type "boolean" + :description + {:fi "Kohteessa on pulkkamäki" + :se "Det finns en pulkabacke på platsen." + :en "There is a sledding hill at the location."}}) + + + ;; Add new kulkutavat prop-type + (assoc :travel-modes + {:name {:fi "Kulkutavat" + :se "Resesätt" + :en "Travel Modes"} + :data-type "enum-coll" + :opts {"by-foot" + {:label {:fi "Jalan" :en "On Foot" :se "Till fots"} + :description + {:fi "Liikkuminen jalkaisin" + :en "Traveling on foot" + :se "Att resa till fots"}} + + "snow-shoes" + {:label {:fi "Lumikengillä" :en "With Snowshoes" :se "Med snöskor"} + :description + {:fi "Liikkuminen lumikengillä" + :en "Traveling with snowshoes" + :se "Att resa med snöskor"}} + + "fat-bike" + {:label {:fi "Läskipyörällä" :en "With Fat Bike" :se "Med fatbike"} + :description + {:fi "Liikkuminen läskipyörällä" + :en "Traveling with a fat bike" + :se "Att resa med fatbike"}}} + :description + {:fi "Lisää reitille soveltuvat kulkutavat" + :se "Lägg till lämpliga resesätt för rutten" + :en "Add suitable travel modes for the route"}}) + + ;; Add new travel-mode-info prop-type + (assoc :travel-mode-info + {:name {:fi "Kulkutavat, lisätieto" + :se "Resesätt, ytterligare information" + :en "Travel Modes, Additional Information"} + :data-type "string" + :description + {:fi "Täsmennä soveltuvia kulkutapoja tarvittaessa" + :se "Specificera lämpliga resesätt vid behov" + :en "Specify suitable travel modes if necessary"}}) + + ;; Add new HS point prop-type + (assoc :hs-point + {:name {:fi "HS-piste", :se "HS-punkt", :en "HS Point"} + :data-type "numeric" + :description + {:fi "Hyppyrimäen HS-piste metreinä" + :se "HS-punkten i backhoppning i meter" + :en "Ski jumping hill HS point in "}}) + + ;; Add new mobile-orienteering-available? prop-type + (assoc :mobile-orienteering? + {:name {:fi "Mobiilisunnistusmahdollisuus" + :se "Mobilorientering möjlig" + :en "Mobile Orienteering Available"} + :data-type "boolean" + :description + {:fi "" + :se "" + :en ""}}) + + ;; Add new bike-orienteering-available? prop-type + (assoc :bike-orienteering? + {:name {:fi "Pyöräsuunnistus mahdollista" + :se "Cykelorientering möjlig" + :en "Bike Orienteering Possible"} + :data-type "boolean" + :description + {:fi "" + :se "" + :en ""}}) + + ;; Add new ski-orienteering? prop-type + (assoc :ski-orienteering? + {:name {:fi "Hiihtosuunnistus mahdollista" + :se "Skidorientering möjlig" + :en "Ski Orienteering Possible"} + :data-type "boolean" + :description + {:fi "" + :se "" + :en ""}}) + + ;; Add new ympärivuotinen käyttö prop-type + (assoc :year-round-use? + {:name {:fi "Ympärivuotinen käyttö" + :se "Året runt användning" + :en "Year-round Use"} + :data-type "boolean" + :description + {:fi "Kohde on ympärivuotisessa käytössä" + :se "Platsen är i användning året runt" + :en "The location is in use year-round"}}) + + )) (def used diff --git a/webapp/src/cljc/lipas/data/prop_types_old.cljc b/webapp/src/cljc/lipas/data/prop_types_old.cljc index ca724bf6b..5cee2175e 100644 --- a/webapp/src/cljc/lipas/data/prop_types_old.cljc +++ b/webapp/src/cljc/lipas/data/prop_types_old.cljc @@ -804,9 +804,9 @@ :en ""}}, :curling-lanes-count {:name - {:fi "Curling-ratojen lkm", + {:fi "Curling-ratojen lukumäärä", :se "Antal curlingbanor", - :en "How many curling lanes"}, + :en "Count of curling lanes"}, :data-type "numeric", :description {:fi "Curling-ratojen lukumäärä", diff --git a/webapp/src/cljc/lipas/data/types_new.cljc b/webapp/src/cljc/lipas/data/types_new.cljc index 33a750b0f..5714a5c16 100644 --- a/webapp/src/cljc/lipas/data/types_new.cljc +++ b/webapp/src/cljc/lipas/data/types_new.cljc @@ -548,7 +548,284 @@ (assoc-in [3250 :props :free-use?] {:priority 0}) (update-in [3220 :props] dissoc :eu-beach?))) -(def all all4) +(def all5 + (-> all4 + + ;; Add new rullahiihto type. Props added via script + (assoc 4407 + {:name + {:fi "Rullahiihtorata" + :se "Rullskidbana" + :en "Roller Ski Track"} + :description + {:fi "Asfaltoitu rullahiihtoon lumettomana aikana tarkoitettu reitti. Reitti kulkee maastossa, ja sen käyttöä muilla kulkutavoilla on rajoitettu." + :se "En asfalterad bana avsedd för rullskidåkning under snöfria perioder. Banan går genom terrängen och användningen av andra färdsätt är begränsad." + :en "An asphalt track intended for roller skiing during snow-free periods. The track runs through terrain, and the use of other modes of travel is restricted."} + :geometry-type "LineString" + :tags {:fi ["rullahiihto"] :se ["rullskidåkning"] :en ["roller skiing"]} + :main-category 4000 + :sub-category 4400 + :status "active" + :type-code 4407 + :props + {}}) + + ;; Add new monikäyttöreitti type. Props added via script + (assoc 4406 + {:name + {:fi "Monikäyttöreitti" + :se "Multianvändningsled" + :en "Multi-use Trail"} + :description + {:fi "Talvisin tai ympärivuotisesti käytössä oleva maastoreitti, joka soveltuu usealle kulkutavalle (esim. jalan, lumikengille, läskipyörälle). Lisätietoihin merkitään, jos reitti on ympärivuotisessa käytössä ja mahdolliset kulkutavat." + :se "En terrängled som används på vintern eller året runt och som är lämplig för flera färdsätt (t.ex. till fots, med snöskor, fatbike). Ytterligare information anger om leden är i bruk året runt och möjliga färdsätt." + :en "A terrain trail used in winter or year-round, suitable for multiple modes of travel (e.g., on foot, with snowshoes, fat bike). Additional information indicates if the trail is in year-round use and possible modes of travel."} + :geometry-type "LineString" + :tags {:fi ["yhteiskäyttöreitti" "talvipolku"] :se ["gemensam led" "vinterstig"] :en ["shared trail" "winter path"]} + :main-category 4000 + :sub-category 4400 + :status "active" + :type-code 4406 + :props + {}}) + + ;; Add new koiravaljakkoreitti type + (assoc 4441 + {:name + {:fi "Koiravaljakkoreitti" + :se "Hundspannsrutt" + :en "Dog Sledding Route"} + :description + {:fi "Koiravaljakoille ylläpidetty reitti." + :se "En rutt underhållen för hundspann." + :en "A route maintained for dog sledding."} + :geometry-type "LineString" + :tags {:fi ["valjakkoajo" "valjakkoreitti"] :se [] :en []} + :main-category 4000 + :sub-category 4400 + :status "active" + :type-code 4441 + :props + {}}) + + (assoc 6150 + {:name + {:fi "Ovaalirata" + :se "Ovalbana" + :en "Oval Track"} + :description + {:fi "Islanninhevosten askellajiratsastukseen varattu rata ulkona." + :se "En bana utomhus avsedd för gångartstävlingar med islandshästar." + :en "An outdoor track designated for gaited riding competitions with Icelandic horses."} + :geometry-type "LineString" + :tags {:fi ["islanninhevosrata" "islanninhevosratsastus" "ovaalibaana" "askellajiratsastus" "askellajirata"] + :se ["islandshästbana" "islandshästridning" "ovalbana" "gångartstävling" "gångartsbana"] + :en ["Icelandic horse track" "Icelandic horse riding" "oval track" "gaited riding" "gaited track"]} + :main-category 6000 + :sub-category 6100 + :status "active" + :type-code 6150 + :props + {}}))) + +(def all6 + (-> all5 + + (assoc-in [4110 :description :fi] "Laskettelun suorituspaikka on lasketteluun tai lumilautailuun tarkoitettu liikuntapaikka, esim. laskettelukeskus. Laskettelun suorituspaikassa voi olla laskettelurinteitä, parkkeja tai muita rinnerakenteita ja hiihtohissejä.") + (assoc-in [4110 :props :customer-service-point?] {:priority 0}) + (update-in [4110 :props] clojure.core/dissoc :toboggan-run?) + (update-in [4110 :props] clojure.core/dissoc :school-use?) + (update-in [4110 :props] clojure.core/dissoc :free-use) + (assoc-in [4110 :props :sledding-hill?] {:priority 0}) + (assoc-in [4210 :name :fi] "Curlingrata/-halli") + (assoc-in [4210 :description :fi] "Pysyvästi lajiin varustettu tila, esim. curlingrata tai curlinghalli.") + (update-in [4210 :props] clojure.core/dissoc :fields-count) + (assoc-in [4210 :props :curling-lanes-count] {:priority 0}) + (assoc-in [4210 :props :stand-capacity-person] {:priority 0}) + (assoc-in [4210 :props :changing-rooms?] {:priority 0}) + (assoc-in [4210 :props :changing-rooms-m2] {:priority 0}) + (update-in [4210 :props] clojure.core/dissoc :school-use?) + (update-in [4210 :props] clojure.core/dissoc :free-use) + (update-in [4220 :props] clojure.core/dissoc :school-use?) + (update-in [4220 :props] clojure.core/dissoc :free-use) + (update-in [4230 :props] clojure.core/dissoc :school-use?) + (update-in [4230 :props] clojure.core/dissoc :free-use) + (update-in [4240 :props] clojure.core/dissoc :school-use?) + (update-in [4240 :props] clojure.core/dissoc :free-use) + (assoc-in [4320 :description :fi] "Mäkihyppyyn soveltuva mäki, vauhtimäessä on jää-, keramiikka- tai muovilatu. Mäen koko, materiaalit ja mahdollinen kesäkäyttö kuvataan lisätiedoissa.") + (assoc-in [4320 :props :changing-rooms?] {:priority 0}) + (assoc-in [4320 :props :changing-rooms-m2] {:priority 0}) + (assoc-in [4320 :props :jumps-count] {:priority 0}) + (assoc-in [4402 :name :fi] "Hiihtolatu") + (assoc-in [4402 :description :fi] "Talvikaudella hiihtoa varten ylläpidetty reitti. Hiihtotyylit kerrotaan ominaisuustiedoissa.") + (assoc-in [4407 :description :fi] "Asfaltoitu rullahiihtoon lumettomana aikana tarkoitettu reitti. Reitti kulkee maastossa, ja sen käyttöä muilla kulkutavoilla on rajoitettu.") + (assoc-in [4407 :props :surface-material] {:priority 0}) + (assoc-in [4407 :props :surface-material-info] {:priority 0}) + (assoc-in [4407 :props :route-length-km] {:priority 0}) + (assoc-in [4407 :props :lit-route-length-km] {:priority 0}) + (assoc-in [4407 :props :route-width-m] {:priority 0}) + (assoc-in [4407 :props :free-use] {:priority 0}) + (assoc-in [4407 :props :outdoor-exercise-machines?] {:priority 0}) + (assoc-in [4407 :props :rest-places-count] {:priority 0}) + (assoc-in [4407 :props :toilet?] {:priority 0}) + (assoc-in [4407 :props :may-be-shown-in-harrastuspassi-fi?] {:priority 0}) + (update-in [4403 :props] clojure.core/dissoc :free-use) + (update-in [4403 :props] clojure.core/dissoc :school-use?) + (update-in [4404 :props] clojure.core/dissoc :free-use) + (update-in [4405 :props] clojure.core/dissoc :free-use) + (update-in [4405 :props] clojure.core/dissoc :school-use?) + (assoc-in [4412 :description :fi] "Pyöräilyreitti, joka kulkee enimmäkseen päällystetyillä teillä tai sorateillä. Reitti voi olla merkitty maastoon tai se on digitaalisesti opastettu") + (update-in [4412 :props] clojure.core/dissoc :free-use) + (update-in [4412 :props] clojure.core/dissoc :school-use?) + (update-in [4421 :props] clojure.core/dissoc :school-use?) + (update-in [4422 :props] clojure.core/dissoc :school-use?) + (update-in [4451 :props] clojure.core/dissoc :school-use?) + (update-in [4451 :props] clojure.core/dissoc :free-use) + (update-in [4452 :props] clojure.core/dissoc :free-use) + (assoc-in [4452 :props :jumps-count] {:priority 0}) + (assoc-in [4320 :description :fi] "Mäkihyppyyn soveltuva mäki, vauhtimäessä on jää-, keramiikka- tai muovilatu. Mäen koko, materiaalit ja mahdollinen kesäkäyttö kuvataan lisätiedoissa.") + (assoc-in [4320 :props :changing-rooms?] {:priority 0}) + (update-in [4320 :props] clojure.core/dissoc :school-use?) + (assoc-in [4406 :description :fi] "Talvisin tai ympärivuotisesti käytössä oleva maastoreitti, joka soveltuu usealle kulkutavalle (esim. jalan, lumikengille, läskipyörälle). Lisätietoihin merkitään, jos reitti on ympärivuotisessa käytössä ja mahdolliset kulkutavat.") + (assoc-in [4406 :props :surface-material] {:priority 0}) + (assoc-in [4406 :props :surface-material-info] {:priority 0}) + (assoc-in [4406 :props :route-length-km] {:priority 0}) + (assoc-in [4406 :props :lit-route-length-km] {:priority 0}) + (assoc-in [4406 :props :rest-places-count] {:priority 0}) + (assoc-in [4406 :props :toilet?] {:priority 0}) + (assoc-in [4406 :props :route-width-m] {:priority 0}) + (assoc-in [4406 :props :travel-modes] {:priority 0}) + (assoc-in [4406 :props :travel-mode-info] {:priority 0}) + (assoc-in [4406 :props :summer-usage?] {:priority 0}) + (assoc-in [4441 :description :fi] "Koiravaljakoille ylläpidetty reitti.") + (assoc-in [4441 :props :surface-material] {:priority 0}) + (assoc-in [4441 :props :surface-material-info] {:priority 0}) + (assoc-in [4441 :props :route-length-km] {:priority 0}) + (assoc-in [4441 :props :lit-route-length-km] {:priority 0}) + (assoc-in [4441 :props :route-width-m] {:priority 0}) + (assoc-in [4441 :props :free-use] {:priority 0}) + (assoc-in [4441 :props :summer-usage?] {:priority 0}) + (assoc-in [4510 :description :fi] "Suunnistukseen käytetty alue. Lisätietoihin merkitään, jos aluetta käytetään mobo-, pyörä- tai hiihtosuunnistukseen. Suunnistusalueesta on saatavilla kartta ja maankäyttöön on maanomistajan suostumus.") + (update-in [4510 :props] clojure.core/dissoc :free-use) + (assoc-in [4510 :props :mobile-orienteering?] {:priority 0}) + (assoc-in [4510 :props :bike-orienteering?] {:priority 0}) + (assoc-in [4510 :props :ski-orienteering?] {:priority 0}) + (update-in [4610 :props] clojure.core/dissoc :automated-timing?) + (assoc-in [4610 :props :changing-rooms?] {:priority 0}) + (assoc-in [4610 :props :changing-rooms-m2] {:priority 0}) + (update-in [4610 :props] clojure.core/dissoc :surface-material) + (update-in [4610 :props] clojure.core/dissoc :surface-material-info) + (update-in [4610 :props] clojure.core/dissoc :school-use?) + (update-in [4620 :props] clojure.core/dissoc :automated-timing?) + (update-in [4620 :props] clojure.core/dissoc :surface-material) + (update-in [4620 :props] clojure.core/dissoc :surface-material-info) + (assoc-in [4620 :props :summer-usage?] {:priority 0}) + (update-in [4620 :props] clojure.core/dissoc :school-use?) + (assoc-in [4630 :name :se] "Maastohiihtokeskus") + (update-in [4630 :props] clojure.core/dissoc :automated-timing?) + (update-in [4630 :props] clojure.core/dissoc :school-use?) + (update-in [4640 :props] clojure.core/dissoc :automated-timing?) + (update-in [4720 :props] clojure.core/dissoc :school-use?) + (update-in [4720 :props] clojure.core/dissoc :free-use) + (update-in [4810 :props] clojure.core/dissoc :track-width-m) + (update-in [4810 :props] clojure.core/dissoc :school-use?) + (update-in [4810 :props] clojure.core/dissoc :free-use) + (update-in [4820 :props] clojure.core/dissoc :track-width-m) + (update-in [4820 :props] clojure.core/dissoc :school-use?) + (update-in [4820 :props] clojure.core/dissoc :free-use) + (assoc-in [4830 :description :fi] "Ulkona tai sisällä sijaitseva jousiammuntarata. Radan käyttö edellyttää erillistä lupaa, seuran jäsenyyttä tai harjoitusvuoroa. Radan varustus ja soveltuvat lajit kuvataan lisätiedoissa.") + (update-in [4830 :props] clojure.core/dissoc :school-use?) + (update-in [4830 :props] clojure.core/dissoc :free-use) + (assoc-in [4830 :props :free-customer-use?] {:priority 0}) + (assoc-in [4840 :description :fi] "Maastoon rakennettu jousiammuntarata. Radan käyttö edellyttää erillistä lupaa, seuran jäsenyyttä tai harjoitusvuoroa. ") + (assoc-in [4840 :props :free-customer-use?] {:priority 0}) + (update-in [4840 :props] clojure.core/dissoc :school-use?) + (update-in [4840 :props] clojure.core/dissoc :free-use) + (assoc-in [5110 :description :fi] "Soutustadion sisältää pysyvästi soutuun käytettäviä rakenteita. Soutustadionissa on katsomo ja valmius ratamerkintöihin.") + (update-in [5110 :props] clojure.core/dissoc :school-use?) + (update-in [5120 :props] clojure.core/dissoc :school-use?) + (assoc-in [5130 :description :fi] "Pysyvä moottorivenekilpailujen rata-alue.") + (update-in [5130 :props] clojure.core/dissoc :school-use?) + (assoc-in [5140 :description :fi] "Rakennettu pysyvästi vesihiihdolle. Vesihiihtoalueella on laituri.") + (update-in [5140 :props] clojure.core/dissoc :school-use?) + (update-in [5150 :props] clojure.core/dissoc :school-use?) + (assoc-in [5160 :description :fi] "Soudun ja melonnan sisäharjoittelutila on erityisesti näihin lajeihin pysyvästi tarkoitettu liikuntapaikka.") + (update-in [5160 :props] clojure.core/dissoc :school-use?) + (assoc-in [5210 :description :fi] "Harraste- tai urheiluilmailuun tarkoitettu alue, esim. lentopaikka.") + (update-in [5210 :props] clojure.core/dissoc :school-use?) + (update-in [5310 :props] clojure.core/dissoc :school-use?) + (assoc-in [5310 :props :summer-usage?] {:priority 0}) + (assoc-in [5320 :description :fi] "Pääasiassa moottoripyöräilyä varten rakennettu, luonnonmukainen ei-asfalttipintainen alue (esim. enduroreitit ja trial-harjoittelualueet maastoliikennealueilla).") + (update-in [5320 :props] clojure.core/dissoc :school-use?) + (assoc-in [5320 :props :summer-usage?] {:priority 0}) + (assoc-in [5330 :description :fi] "Suuri rata-autoiluun tai moottoripyöräilyyn tarkoitettu asfaltoitu moottoriurheilupaikka.") + (update-in [5330 :props] clojure.core/dissoc :school-use?) + (assoc-in [5330 :props :summer-usage?] {:priority 0}) + (assoc-in [5340 :description :fi] "Pääasiallisesti kartingajoon tai supermotoon käytetty rata.") + (update-in [5340 :props] clojure.core/dissoc :school-use?) + (assoc-in [5340 :props :summer-usage?] {:priority 0}) + (assoc-in [5350 :description :fi] "Pääasiallisesti kiihdytysautoiluun tai kiihdytysmoottoripyöräilyyn käytetty rata.") + (update-in [5350 :props] clojure.core/dissoc :school-use?) + (assoc-in [5350 :props :summer-usage?] {:priority 0}) + (assoc-in [5360 :description :fi] "Pääasiallisesti jokamiesajoa, rallicrossia tai moottoripyöräilyä varten.") + (update-in [5360 :props] clojure.core/dissoc :school-use?) + (assoc-in [5360 :props :summer-usage?] {:priority 0}) + (assoc-in [5370 :name :fi] "Speedway- ja jääspeedwayrata") + (update-in [5370 :props] clojure.core/dissoc :school-use?) + (assoc-in [5370 :props :summer-usage?] {:priority 0}) + (update-in [6120 :props] clojure.core/dissoc :ligthing?) + (assoc-in [6130 :name :fi] "Esteratsastuskenttä tai -alue") + (assoc-in [6130 :description :fi] "Pysyvästi esteratsastukseen varusteltu kenttä tai alue ulkona.") + (assoc-in [6150 :description :fi] "Islanninhevosten askellajiratsastukseen varattu rata ulkona.") + (assoc-in [6150 :props :customer-service-point?] {:priority 0}) + (assoc-in [6150 :props :surface-material] {:priority 0}) + (assoc-in [6150 :props :surface-material-info] {:priority 0}) + (assoc-in [6150 :props :ligthing?] {:priority 0}) + (assoc-in [6150 :props :toilet?] {:priority 0}) + (assoc-in [6150 :props :track-width-m] {:priority 0}) + (assoc-in [6150 :props :track-length-m] {:priority 0}) + (assoc-in [6150 :props :may-be-shown-in-harrastuspassi-fi?] {:priority 0}) + (assoc-in [6150 :props :free-use] {:priority 0}) + (assoc-in [5360 :props :summer-usage?] {:priority 0}) + (update-in [6140 :props] clojure.core/dissoc :school-use?) + (update-in [6210 :props] clojure.core/dissoc :school-use?) + (update-in [6220 :props] clojure.core/dissoc :school-use?) + + ) + ) + +(def all7 + (-> all6 + + ;; Remove :winter-use?, summer-use? and add :year-round-use? to + ;; replace them + (->> (reduce-kv (fn [m k v] + (assoc m k + (cond-> v + (contains? (:props v) :summer-usage?) + (assoc-in [:props :year-round-use?] {:priority 0}) + + (contains? (:props v) :winter-usage?) + (assoc-in [:props :year-round-use?] {:priority 0}) + + true (update :props dissoc :winter-usage? :summer-usage?) + + ))) + {})) + + ;; Deprecate pyörä- and hiihtosuunnistusallue + ;; They were merged to "suunnistusalue" 4510 + (assoc-in [4530 :status] "deprecated") + (assoc-in [4520 :status] "deprecated") + + ;; Migrate harjoityshyppyrimäki to hyppyrimäki + (assoc-in [4310 :status] "deprecated") + (update-in [4320 :props] assoc :hs-point {:priority 0}) + (update-in [4320 :props] dissoc :p-point) + + )) + +(def all all7) (def active (reduce-kv (fn [m k v] (if (not= "active" (:status v)) (dissoc m k) m)) all all)) From 7182cf32f3f77be55fffa3052bc82e4d2645f246 Mon Sep 17 00:00:00 2001 From: Valtteri Harmainen Date: Sun, 20 Oct 2024 17:03:15 +0300 Subject: [PATCH 09/68] Localize new enums in display view --- .../src/cljs/lipas/ui/sports_sites/subs.cljs | 78 ++++++++++++------- 1 file changed, 48 insertions(+), 30 deletions(-) diff --git a/webapp/src/cljs/lipas/ui/sports_sites/subs.cljs b/webapp/src/cljs/lipas/ui/sports_sites/subs.cljs index 577bdc044..d1a7569d8 100644 --- a/webapp/src/cljs/lipas/ui/sports_sites/subs.cljs +++ b/webapp/src/cljs/lipas/ui/sports_sites/subs.cljs @@ -1,12 +1,14 @@ (ns lipas.ui.sports-sites.subs - (:require ["@turf/helpers" :refer [lineString]] - ["@turf/length$default" :as turf-length] - [clojure.spec.alpha :as s] - [lipas.data.types :as types] - [lipas.roles :as roles] - [lipas.ui.utils :as utils] - [lipas.utils :as cutils] - [re-frame.core :as rf])) + (:require + ["@turf/helpers" :refer [lineString]] + ["@turf/length$default" :as turf-length] + [clojure.spec.alpha :as s] + [lipas.data.prop-types :as prop-types] + [lipas.data.types :as types] + [lipas.roles :as roles] + [lipas.ui.utils :as utils] + [lipas.utils :as cutils] + [re-frame.core :as rf])) (rf/reg-sub ::sports-sites (fn [db _] @@ -279,21 +281,23 @@ :distance-km distance-km :distance-m (* 1000 distance-km)}))))))))))) -(rf/reg-sub ::elevation-stats - (fn [[_ lipas-id]] - (rf/subscribe [:lipas.ui.sports-sites.subs/elevation lipas-id])) - (fn [elevation _] - (for [segment elevation] - (->> segment - (map :elevation-m) - (partition 2 1) - (reduce (fn [res [prev curr]] - (let [d (- curr prev)] - (cond - (zero? d) res - (pos? d) (update res :ascend-m + d) - (neg? d) (update res :descend-m + (Math/abs d))))) - {:ascend-m 0 :descend-m 0}))))) + +(rf/reg-sub + ::elevation-stats + (fn [[_ lipas-id]] + (rf/subscribe [:lipas.ui.sports-sites.subs/elevation lipas-id])) + (fn [elevation _] + (for [segment elevation] + (->> segment + (map :elevation-m) + (partition 2 1) + (reduce (fn [res [prev curr]] + (let [d (- curr prev)] + (cond + (zero? d) res + (pos? d) (update res :ascend-m + d) + (neg? d) (update res :descend-m + (Math/abs d))))) + {:ascend-m 0 :descend-m 0}))))) (rf/reg-sub ::display-site (fn [[_ lipas-id] _] @@ -332,7 +336,16 @@ city (get cities (-> latest :location :city :city-code)) status (statuses (-> latest :status)) - get-material #(get-in materials [% locale])] + get-material #(get-in materials [% locale]) + get-travel-mode #(get-in prop-types/all [:travel-modes :opts % :label locale]) + + get-parkour-structure #(get-in prop-types/all [:parkour-hall-equipment-and-structures :opts % :label locale]) + + get-boating-service-class #(get-in prop-types/all [:boating-service-class :opts % :label locale]) + + get-water-point #(get-in prop-types/all [:water-point :opts % :label locale]) + + get-sport-specification #(get-in prop-types/all [:sport-specification :opts % :label locale]) ] (merge {:status (-> status locale) @@ -356,11 +369,16 @@ :construction-year (-> latest :construction-year) :renovation-years (-> latest :renovation-years) - :properties (-> latest - :properties - (update :surface-material #(map get-material %)) - (update :running-track-surface-material get-material) - (update :training-spot-surface-material get-material)) + :properties (-> latest + :properties + (update :surface-material #(map get-material %)) + (update :running-track-surface-material get-material) + (update :training-spot-surface-material get-material) + (update :travel-modes #(map get-travel-mode %)) + (update :parkour-hall-equipment-and-structures #(map get-parkour-structure %)) + (update :boating-service-class get-boating-service-class) + (update :water-point get-water-point) + (update :sport-specification get-sport-specification)) :location {:address (-> latest :location :address) @@ -411,7 +429,7 @@ (fn [v] (get-in audience-stand-access [v locale]))))) :locker-rooms (:locker-rooms latest) - :audits (:audits latest)}) + :audits (:audits latest)}) ;; TODO maybe check activities for type (when true From 450f1d961941100554621be2ce92a36994d8e9d1 Mon Sep 17 00:00:00 2001 From: Valtteri Harmainen Date: Sun, 20 Oct 2024 17:25:11 +0300 Subject: [PATCH 10/68] Localize new enums in reports etc. --- webapp/src/cljc/lipas/i18n/core.cljc | 87 +++++++++++++++++++++++++++- 1 file changed, 86 insertions(+), 1 deletion(-) diff --git a/webapp/src/cljc/lipas/i18n/core.cljc b/webapp/src/cljc/lipas/i18n/core.cljc index 909ecf41f..df6a7b790 100644 --- a/webapp/src/cljc/lipas/i18n/core.cljc +++ b/webapp/src/cljc/lipas/i18n/core.cljc @@ -122,6 +122,41 @@ :translations materials/surface-materials :many? true} + ;; Proerties->travel-modes + {:path [:properties :travel-modes] + :translations (-> prop-types/all + (get-in [:travel-modes :opts]) + (update-vals :label)) + :many? true} + + ;; Proerties->parkour-hall-equipment-and-structures + {:path [:properties :parkour-hall-equipment-and-structures] + :translations (-> prop-types/all + (get-in [:parkour-hall-equipment-and-structures :opts]) + (update-vals :label)) + :many? true} + + ;; Proerties->boating-service-class + {:path [:properties :boating-service-class] + :translations (-> prop-types/all + (get-in [:boating-service-class :opts]) + (update-vals :label)) + :many? false} + + ;; Properties->water-point + {:path [:properties :water-point] + :translations (-> prop-types/all + (get-in [:water-point :opts]) + (update-vals :label)) + :many? false} + + ;; Properties->sport-specification + {:path [:properties :sport-specification] + :translations (-> prop-types/all + (get-in [:sport-specification :opts]) + (update-vals :label)) + :many? false} + ;; Ice stadiums {:path [:type :size-category] :translations ice/size-categories} @@ -221,7 +256,57 @@ {:path [:properties :surface-material] :target-path [:properties :surface-material-localized] :translate-fn (fn [locales vs] - (map (fn [v] (-> v materials/surface-materials (select-keys locales))) vs))}] + (map (fn [v] (-> v materials/surface-materials (select-keys locales))) vs))} + + ;; Proerties->travel-modes + {:path [:properties :travel-modes] + :translate-fn (fn [locales vs] + (-> prop-types/all + (get-in [:travel-modes :opts]) + (select-keys vs) + (->> (map :label) + (map #(select-keys % locales)))))} + + ;; Proerties->parkour-hall-equipment-and-structures + {:path [:properties :parkour-hall-equipment-and-structures] + :target-path [:properties :parkour-hall-equipment-and-structures-localized] + :translate-fn (fn [locales vs] + (-> prop-types/all + (get-in [:parkour-hall-equipment-and-structures :opts]) + (select-keys vs) + (->> (map :label) + (map #(select-keys % locales)))))} + + ;; Proerties->boating-service-class + {:path [:properties :boating-service-class] + :target-path [:properties :boating-service-class-localized] + :translate-fn (fn [locales vs] + (-> prop-types/all + (get-in [:boating-service-class :opts]) + (select-keys vs) + (->> (map :label) + (map #(select-keys % locales)))))} + + ;; Properties->water-point + {:path [:properties :water-point] + :target-path [:properties :water-point-localized] + :translate-fn (fn [locales vs] + (-> prop-types/all + (get-in [:water-point :opts]) + (select-keys vs) + (->> (map :label) + (map #(select-keys % locales)))))} + + ;; Properties->sport-specification + {:path [:properties :sport-specification] + :target-path [:properties :sport-specification-localized] + :translate-fn (fn [locales vs] + (-> prop-types/all + (get-in [:sport-specification :opts]) + (select-keys vs) + (->> (map :label) + (map #(select-keys % locales)))))}] + (map #(update % :translate-fn memoize)))) (defn localize2 From 5d9f6daadb18bd42044afc1d4626fec927a3f51c Mon Sep 17 00:00:00 2001 From: Valtteri Harmainen Date: Sun, 20 Oct 2024 20:50:23 +0300 Subject: [PATCH 11/68] Make "planned" and "planning" styles look less aggressive --- webapp/src/cljs/lipas/ui/map/styles.cljs | 32 +++++++++++++----------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/webapp/src/cljs/lipas/ui/map/styles.cljs b/webapp/src/cljs/lipas/ui/map/styles.cljs index 4ea36e306..b5495044f 100644 --- a/webapp/src/cljs/lipas/ui/map/styles.cljs +++ b/webapp/src/cljs/lipas/ui/map/styles.cljs @@ -107,21 +107,23 @@ stroke-black (Stroke. #js {:color "#00000" :width 1}) - stroke-planned (Stroke. #js {:color "#3b3b3b" - :lineDash #js [2 20] - ; :lineDashOffset 1 - :width (case (:shape m) - ("polygon" "linestring") 10 - ("circle") 5 - ("square") 4)}) - - stroke-planning (Stroke. #js {:color "#ee00ee" - :lineDash #js [2 20] - ; :lineDashOffset 1 - :width (case (:shape m) - ("polygon" "linestring") 10 - ("circle") 5 - ("square") 4)}) + stroke-planned (Stroke. + #js{:color "#b1b7c4" + :lineDash #js[2 20] + ; :lineDashOffset 1 + :width (case (:shape m) + ("polygon" "linestring") 7 + ("circle") 5 + ("square") 4)}) + + stroke-planning (Stroke. + #js{:color "#ee00ee" + :lineDash #js[2 20] + ; :lineDashOffset 1 + :width (case (:shape m) + ("polygon" "linestring") 7 + ("circle") 5 + ("square") 4)}) stroke (Stroke. #js {:color stroke-color :lineDash (when (or selected? hover?) From 0699f08a2a26cfeccd924d7eb1fdf1010a30561b Mon Sep 17 00:00:00 2001 From: Valtteri Harmainen Date: Sat, 26 Oct 2024 13:50:56 +0300 Subject: [PATCH 12/68] Add remaining type-code and prop label adjustments --- webapp/dev/user.clj | 11 + webapp/src/cljc/lipas/data/materials.cljc | 8 +- webapp/src/cljc/lipas/data/prop_types.cljc | 1816 ++++++- .../src/cljc/lipas/data/prop_types_new.cljc | 12 + webapp/src/cljc/lipas/data/types.cljc | 4622 ++++++++++++++++- webapp/src/cljc/lipas/data/types_new.cljc | 27 +- .../src/cljs/lipas/ui/sports_sites/views.cljs | 15 +- 7 files changed, 6486 insertions(+), 25 deletions(-) diff --git a/webapp/dev/user.clj b/webapp/dev/user.clj index 89ffa9bab..3173db25f 100644 --- a/webapp/dev/user.clj +++ b/webapp/dev/user.clj @@ -61,4 +61,15 @@ (require '[migratus.core :as migratus]) (migratus/create nil "activities_status" :sql) + (migratus/create nil "roles" :edn) + + (require '[lipas.maintenance :as maintenance]) + (require '[lipas.backend.core :as core]) + + (def robot (core/get-user (db) "robot@lipas.fi")) + + (maintenance/merge-types (db) (search) robot 4530 4510) + (maintenance/merge-types (db) (search) robot 4520 4510) + (maintenance/merge-types (db) (search) robot 4310 4320) + ) diff --git a/webapp/src/cljc/lipas/data/materials.cljc b/webapp/src/cljc/lipas/data/materials.cljc index aa3b058f6..4b14afe92 100644 --- a/webapp/src/cljc/lipas/data/materials.cljc +++ b/webapp/src/cljc/lipas/data/materials.cljc @@ -48,7 +48,7 @@ "fiberglass" {:fi "Lasikuitu" :se "Glasfiber" :en "Fiberglass"} - "soil" {:fi "Maa / luonnonmukainen" + "soil" {:fi "Maa/luonnonmukainen" :se "Jordet" :en "Soil"} "wood" {:fi "Puu" @@ -57,9 +57,9 @@ "glass" {:fi "Lasi" :se nil :en "Glass"} - "synthetic" {:fi "Muovi / synteettinen" - :se "Plast / syntetisk" - :en "Plastic / synthetic"} + "synthetic" {:fi "Muovi/synteettinen" + :se "Plast/syntetisk" + :en "Plastic/synthetic"} "grass" {:fi "Nurmi" :se "Gräs" :en "Grass"} diff --git a/webapp/src/cljc/lipas/data/prop_types.cljc b/webapp/src/cljc/lipas/data/prop_types.cljc index 4ba80339a..d8971ac99 100644 --- a/webapp/src/cljc/lipas/data/prop_types.cljc +++ b/webapp/src/cljc/lipas/data/prop_types.cljc @@ -2,11 +2,1819 @@ "Type codes went through a major overhaul in the summer of 2024. This namespace represents the changes made." (:require - [lipas.data.types :as types] - [lipas.data.prop-types-new :as new] - [lipas.data.prop-types-old :as old])) + [lipas.data.types :as types])) -(def all new/all) +(def all + {:height-m + {:name + {:fi "Tilan korkeus m", :se "Utrymmets höjd", :en "Venue's height"}, + :data-type "numeric", + :description + {:fi "Sisäliikuntatilan korkeus metreinä (matalin kohta)", + :se "Motionssalens höjd i meter (från lägsta punkten)", + :en ""}}, + :heating? + {:name {:fi "Lämmitys", :se "Uppvärmning", :en "Heating"}, + :data-type "boolean", + :description + {:fi "Onko liikuntapaikassa lämmitys", + :se "Är idrottsplatsen utrustad med uppvärmning", + :en ""}}, + :field-2-area-m2 + {:name + {:fi "2. kentän ala m2", + :se "Andra planens areal m2", + :en "2. field's area sq. m"}, + :data-type "numeric", + :description + {:fi "2. kentän pinta-ala neliömetreinä", + :se "Andra planens areal i kvadratmeter", + :en ""}}, + :surface-material + {:name + {:fi "Pintamateriaali", :se "Ytmaterial", :en "Surface material"}, + :data-type "enum-coll", + :description + {:fi + "Liikunta-alueiden pääasiallinen pintamateriaali - tarkempi kuvaus liikuntapaikan eri tilojen pintamateriaalista voidaan antaa pintamateriaalin lisätietokentässä", + :se + "Idrotts områdets ytmaterial. Friidrottsplanens mittplans pålägg.", + :en ""}}, + :basketball-fields-count + {:name + {:fi "Koripallokentät lkm", + :se "Antalet korgbollsplaner", + :en "Basketball fields pcs"}, + :data-type "numeric", + :description + {:fi "Koripallokenttien lukumäärä", + :se "Antalet korgbollsplaner i salen", + :en ""}}, + :surface-material-info + {:name + {:fi "Pintamateriaali lisätieto", + :se "Ytterligare information om ytmaterialen", + :en "Surface material information"}, + :data-type "string", + :description + {:fi + "Syötä pintamateriaalin tarkempi kuvaus- esim. tekonurmen yleisnimitys ”esim. Kumirouhetekonurmi”, tuotenimi ja tieto täytemateriaalin laadusta (esim. biohajoava/perinteinen kumirouhe).", + :se "Ytterilgare information om ytmaterialen", + :en ""}}, + :height-of-basket-or-net-adjustable? + {:name + {:fi "Korin tai verkon korkeus säädettävissä", + :se "Korgens eller nätets höjd är justerbar", + :en "Height of the basket or net is adjustable"}, + :data-type "boolean", + :description {:fi "", :se "", :en ""}}, + :holes-count + {:name + {:fi "Reikien/väylien lkm", + :se "Antal hål/fairways", + :en "Number of holes/fairways"}, + :data-type "numeric", + :description + {:fi "Väylien lukumäärä", :se "Antalet ranger", :en ""}}, + :skijump-hill-type + {:name + {:fi "Hyppyrimäen tyyppi", + :se "Hoppbackens typ", + :en "Type of ski jump hill"}, + :data-type "string", + :description + {:fi "Hyppyrimäen tyyppi (harjoitus, pienmäki, normaali, suurmäki)", + :se + "Typ av hoppbacke (övningsbacke, liten, normalbacke, storbacke)", + :en ""}}, + :lifts-count + {:name {:fi "Hissit lkm", :se "Antalet skidliftar", :en "Lifts"}, + :data-type "numeric", + :description + {:fi "Hiihtohissien lukumäärä", + :se "Antal skidliftar i skidcentrumet", + :en ""}}, + :field-3-length-m + {:name + {:fi "3. kentän pituus m", + :se "Tredje planens längd m", + :en "3. field's length m"}, + :data-type "numeric", + :description + {:fi "3. kentän pituus metreinä", + :se "Tredje planens längd i meter", + :en ""}}, + :pool-tracks-count + {:name + {:fi "1. altaan radat lkm", + :se "Första bassängens antal banor", + :en "Courses in 1. pool"}, + :data-type "numeric", + :description + {:fi "1. altaan ratojen lukumäärä", + :se "Antal banor i första bassängen", + :en ""}}, + :field-2-length-m + {:name + {:fi "2. kentän pituus m", + :se "Andra planens längd m", + :en "2. field's length m"}, + :data-type "numeric", + :description + {:fi "2. kentän pituus metreinä", + :se "Andra planens längd i meter", + :en ""}}, + :plastic-outrun? + {:name + {:fi "Muovitettu alastulo", + :se "Plast-belagd landning", + :en "Plastic outrun"}, + :data-type "boolean", + :description + {:fi "Muovitettu hyppyrimäen alastulopaikka", + :se "Hoppbacken har plast-belagd landningsplats", + :en ""}}, + :automated-timing? + {:name + {:fi "Automaattinen ajanotto", + :se "Automatisk tidtagning", + :en "Automatic timing"}, + :data-type "boolean", + :description + {:fi "Varustus automaattiseen ajanottoon", + :se "Utrustning för automatisk tidtagning", + :en ""}}, + :freestyle-slope? + {:name {:fi "Kumparerinne", :se "Puckelpist", :en "Freestyle slope"}, + :data-type "boolean", + :description + {:fi "Hiihtokeskuksessa on kumparerinne", + :se "Skidcentret har en puckelpist", + :en ""}}, + :kiosk? + {:name {:fi "Kioski", :se "Kiosk", :en "Kiosk"}, + :data-type "boolean", + :description + {:fi "Onko liikuntapaikalla kioski tai vastaava", + :se "Har idrottsplatsen en kiosk eller något liknande", + :en ""}}, + :summer-usage? + {:name {:fi "Kesäkäyttö", :se "I sommarbruk", :en "Summer usage"}, + :data-type "boolean", + :description + {:fi "Käytössä myös kesäisin", + :se "Används också under sommaren", + :en ""}}, + :stand-capacity-person + {:name + {:fi "Katsomon kapasiteetti hlö", + :se "Läktarens person kapasitet", + :en "Stand size"}, + :data-type "numeric", + :description + {:fi "Katsomon koko kapasiteetti, henkilölukumäärä", + :se "Läktarens hela person kapasitet", + :en ""}}, + :free-use? + {:name + {:fi "Kohde on vapaasti käytettävissä", + :se "Fri användning", + :en "Free access"}, + :data-type "boolean", + :description + {:fi + "Liikuntapaikka on vapaasti käytettävissä ilman vuorovarausta tai pääsymaksua", + :se + "Motionsplatsen är fri att användas utan tidsbokning eller entréavgift", + :en ""}}, + :pier? + {:name {:fi "Laituri", :se "Brygga", :en "Pier"}, + :data-type "boolean", + :description {:fi "", :se "", :en ""}}, + :sport-specification + {:name + {:fi "Lajitarkenne", + :se "Sportspecifikation", + :en "Sport specification"}, + :data-type "enum", + :opts + {"floor-disciplines" + {:label + {:fi "Lattialajit", + :en "Floor disciplines", + :se "Golvdiscipliner"}, + :description + {:fi "Voimistelulajit, jotka suoritetaan pääasiassa lattialla.", + :en + "Gymnastics disciplines that are primarily performed on the floor.", + :se "Gymnastikdiscipliner som huvudsakligen utförs på golvet."}}, + "apparatus-disciplines" + {:label + {:fi "Telinelajit", + :en "Apparatus disciplines", + :se "Redskapsgrenar"}, + :description + {:fi "Voimistelulajit, jotka suoritetaan erilaisilla telineillä.", + :en + "Gymnastics disciplines that are performed on various apparatus.", + :se "Gymnastikdiscipliner som utförs på olika redskap."}}, + "floor-and-apparatus" + {:label + {:fi "Lattia- ja telinelajit mahdollisia", + :en "Both floor and apparatus disciplines possible", + :se "Både golv- och redskapsgrenar möjliga"}, + :description + {:fi "Tilassa voidaan harjoitella sekä lattia- että telinelajeja.", + :en + "The space allows for practicing both floor and apparatus disciplines.", + :se + "Utrymmet möjliggör träning av både golv- och redskapsgrenar."}}, + "cheerleading-circus" + {:label + {:fi "Pääasiassa cheerleading- tai sirkusharjoittelukäyttöön", + :en "Mainly for cheerleading or circus training", + :se "Huvudsakligen för cheerleading- eller cirkusträning"}, + :description + {:fi + "Tila on ensisijaisesti tarkoitettu cheerleading- tai sirkusharjoitteluun.", + :en + "The space is primarily intended for cheerleading or circus training.", + :se + "Utrymmet är främst avsett för cheerleading- eller cirkusträning."}}, + "no-information" + {:label + {:fi "Ei tietoa", :en "No information", :se "Ingen information"}}}, + :description + {:fi "Valitse voimistelulaji, johon tila on pääasiassa tarkoitettu.", + :se "", + :en ""}}, + :may-be-shown-in-excursion-map-fi? + {:name + {:fi "Saa julkaista Retkikartta.fi-palvelussa", + :se "Får publiceras i Utflyktskarta.fi", + :en "May be shown in Excursionmap.fi"}, + :data-type "boolean", + :description + {:fi "Kohteen tiedot saa julkaista Retkikartta.fi-palvelussa", + :se "Information om motionsstället får publiceras i Retkikartta.fi", + :en ""}}, + :sprint-lanes-count + {:name + {:fi "Etusuorien lkm", + :se "Antalet raksträckor (framför läktaren)", + :en "Number of sprint lanes"}, + :data-type "numeric", + :description + {:fi "Etusuorien lukumäärä", + :se "Antalet raksträckor (framför läkataren)", + :en ""}}, + :javelin-throw-places-count + {:name + {:fi "Keihäänheittopaikat lkm", + :se "Spjutkastningsplatser st.", + :en "Number of javelin throw places"}, + :data-type "numeric", + :description + {:fi "Keihäänheittopaikkojen lukumäärä", + :se "Antalet spjutkastningsplatser", + :en ""}}, + :active-space-width-m + {:name + {:fi "Liikuntakäytössä olevan tilan leveys m", + :se "Bredd på aktivt utrymme m", + :en "Width of active space m"}, + :data-type "numeric", + :description + {:fi "Liikuntakäytössä olevan tilan leveys (m)", :se "", :en ""}}, + :tennis-courts-count + {:name + {:fi "Tenniskentät lkm", + :se "Antalet tennisplaner", + :en "Tennis courts pcs"}, + :data-type "numeric", + :description + {:fi "Tenniskenttien lukumäärä", + :se "Antalet tennisplaner", + :en ""}}, + :ski-service? + {:name {:fi "Suksihuolto", :se "Skidservice", :en "Ski service"}, + :data-type "boolean", + :description + {:fi "Suksihuoltopiste löytyy", + :se "Det finns en skidservicepunkt", + :en ""}}, + :field-1-length-m + {:name + {:fi "1. kentän pituus m", + :se "Första planens längd m", + :en "1. field's length m"}, + :data-type "numeric", + :description + {:fi "1. kentän pituus metreinä", + :se "Första planens längd i meter", + :en ""}}, + :mirror-wall? + {:name {:fi "Peiliseinä", :se "Spegelvägg", :en "Mirror wall"}, + :data-type "boolean", + :description + {:fi "Liikuntatilassa vähintään yhdellä seinällä on kiinteät peilit", + :se "", + :en ""}}, + :finish-line-camera? + {:name {:fi "Maalikamera", :se "Målkamera", :en "Finish line camera"}, + :data-type "boolean", + :description + {:fi "Liikuntapaikalla on maalikamera", + :se "Idrottsplatsen har en målkamera", + :en ""}}, + :travel-mode-info + {:name + {:fi "Kulkutavat, lisätieto", + :se "Resesätt, ytterligare information", + :en "Travel Modes, Additional Information"}, + :data-type "string", + :description + {:fi "Täsmennä soveltuvia kulkutapoja tarvittaessa", + :se "Specificera lämpliga resesätt vid behov", + :en "Specify suitable travel modes if necessary"}}, + :parking-place? + {:name + {:fi "Parkkipaikka", :se "Parkeringsplats", :en "Parking place"}, + :data-type "boolean", + :description + {:fi "Parkkipaikka käytettävissä", + :se "Tillgänglig parkeringsplats", + :en ""}}, + :canoeing-club? + {:name {:fi "Melontaseura", :se "", :en "Canoeing club"}, + :data-type "boolean", + :description + {:fi "Onko kyseessä melontaseuran tila", :se "", :en ""}}, + :total-billiard-tables-count + {:name + {:fi "Biljardipöydät yhteensä lkm", + :se "Totalt antal biljardbord", + :en "Total number of billiard tables"}, + :data-type "numeric", + :description {:fi "", :se "", :en ""}}, + :sledding-hill? + {:name {:fi "Pulkkamäki", :se "Pulkabacke", :en "Sledding hill"}, + :data-type "boolean", + :description + {:fi "Kohteessa on pulkkamäki", + :se "Det finns en pulkabacke på platsen.", + :en "There is a sledding hill at the location."}}, + :climbing-routes-count + {:name + {:fi "Kiipeilyreittien lkm", + :se "Antalet klättringsrutter", + :en "Climbing routes pcs"}, + :data-type "numeric", + :description + {:fi "Kiipeilyreittien lukumäärä", + :se "Antalet klättringsrutter", + :en ""}}, + :outdoor-exercise-machines? + {:name + {:fi "Kuntoilutelineitä", + :se "Gym apparater utomhus", + :en "Exercise machines outdoors"}, + :data-type "boolean", + :description + {:fi "Onko reitin varrella kuntoilulaitteita", + :se "Finns det gym apparater längs rutten", + :en ""}}, + :automated-scoring? + {:name + {:fi "Kirjanpitoautomaatti", + :se "Bokföringsautomat", + :en "Automatic scoring"}, + :data-type "boolean", + :description + {:fi "Keilaradalla on sähköinen pistelasku", + :se "Bowlingbanan har elektroniskt poängräknings system", + :en ""}}, + :mobile-orienteering? + {:name + {:fi "Mobiilisuunnistusmahdollisuus", + :se "Mobilorientering möjlig", + :en "Mobile Orienteering Available"}, + :data-type "boolean", + :description {:fi "", :se "", :en ""}}, + :track-width-m + {:name + {:fi "Radan leveys m", :se "Banans bredd m", :en "Width of track m"}, + :data-type "numeric", + :description + {:fi "Juoksuradan, pyöräilyradan tms. leveys metreinä", + :se "Löpbanan, rundbanan el.dyl. bredd i meter", + :en ""}}, + :ice-climbing? + {:name {:fi "Jääkiipeily", :se "Isklättring", :en "Ice climbing"}, + :data-type "boolean", + :description + {:fi "Onko jääkiipeily mahdollista kiipeilypaikalla", + :se "Finns det möjlighet för isklättring vid klättringsplatsen", + :en ""}}, + :free-use {:name {:fi "Kohde on vapaasti käytettävissä"}}, + :field-length-m + {:name + {:fi "Kentän pituus m", + :se "Planens längd m", + :en "Length of field"}, + :data-type "numeric", + :description + {:fi "Kentän/kenttien pituus mahdollisine turva-alueineen metreinä", + :se "Planens/planernas längd i meter", + :en ""}}, + :skijump-hill-material + {:name + {:fi "Vauhtimäen rakennemateriaali", + :se "Överbackens konstruktionsmaterial", + :en "Ski jump hill material"}, + :data-type "string", + :description + {:fi "Vauhtimäen rakennemateriaali", + :se "Överbackens konstruktionsmaterial (backhoppning)", + :en ""}}, + :carom-tables-count + {:name + {:fi "Karapöydät lkm", + :se "Antal karombord", + :en "Number of carom tables"}, + :data-type "numeric", + :description {:fi "", :se "", :en ""}}, + :longest-slope-m + {:name + {:fi "Pisin rinne m", + :se "Längsta slalombacken m", + :en "Longest slope m"}, + :data-type "numeric", + :description + {:fi "Pisimmän rinteen pituus metreinä", + :se "Längsta slalombackens längd i meter", + :en ""}}, + :circular-lanes-count + {:name + {:fi "Kiertävät radat lkm", + :se "Antalet cirkulerande löpbanor", + :en "Number of circular lanes"}, + :data-type "numeric", + :description + {:fi "Kiertävien juoksuratojen lukumäärä", + :se "Antalet cirkulerande löpbanor", + :en ""}}, + :boat-launching-spot? + {:name + {:fi "Veneen vesillelaskupaikka", + :se "Sjösättningsplats för båtar", + :en "Place for launching a boat"}, + :data-type "boolean", + :description + {:fi "Mahdollisuus veneen vesillelaskuun", + :se "Sjösättningsplats för båtar", + :en ""}}, + :parkour-hall-equipment-and-structures + {:name + {:fi "Parkour-salin varustelu ja rakenteet", + :se "Utrustning och strukturer i parkourhallen", + :en "Parkour hall equipment and structures"}, + :data-type "enum-coll", + :opts + {"fixed-obstacles" + {:label + {:fi "Kiinteät esteet/rakennelmat", + :en "Fixed obstacles/structures", + :se "Fasta hinder/strukturer"}, + :description + {:fi + "Pysyvästi asennetut esteet tai rakennelmat harjoittelua varten.", + :en + "Permanently installed obstacles or structures for training purposes.", + :se + "Permanent installerade hinder eller strukturer för träningsändamål."}}, + "movable-obstacles" + {:label + {:fi "Liikkuvat esteet/rakennelmat", + :en "Movable obstacles/structures", + :se "Flyttbara hinder/strukturer"}, + :description + {:fi + "Siirrettävät tai muunneltavat esteet ja rakennelmat harjoittelua varten.", + :en + "Movable or adjustable obstacles and structures for training purposes.", + :se + "Flyttbara eller justerbara hinder och strukturer för träningsändamål."}}, + "floor-acrobatics-area" + {:label + {:fi "Permanto/akrobatiatila", + :en "Floor/acrobatics area", + :se "Golv/akrobatikområde"}, + :description + {:fi + "Avoin tila lattiaharjoittelua ja akrobaattisia liikkeitä varten.", + :en "Open space for floor exercises and acrobatic movements.", + :se "Öppet utrymme för golvövningar och akrobatiska rörelser."}}, + "gym-strength-area" + {:label + {:fi "Kuntosali-/voimailutila", + :en "Gym/strength training area", + :se "Gym/styrketräningsområde"}, + :description + {:fi + "Alue, joka on varustettu kuntosalilaitteilla ja välineillä voimaharjoittelua varten.", + :en + "Area equipped with gym machines and equipment for strength training.", + :se + "Område utrustat med gymmaskiner och utrustning för styrketräning."}}}, + :description + {:fi "Valitse parkour-salissa olevat rakenteet tai varusteet", + :se "", + :en ""}}, + :ski-track-traditional? + {:name + {:fi "Perinteinen latu", + :se "Skidspår för klassisk stil", + :en "Traditional ski track"}, + :data-type "boolean", + :description + {:fi "Perinteisen tyylin hiihtomahdollisuus/latu-ura", + :se "Möjlighet att skida klassisk stil", + :en ""}}, + :altitude-difference + {:name + {:fi "Korkeusero m", + :se "Höjdskillnad m", + :en "Altitude difference"}, + :data-type "numeric", + :description + {:fi "Reitin korkeusero metreinä", + :se "Ruttens höjdskillnad i meter", + :en ""}}, + :climbing-wall-height-m + {:name + {:fi "Kiipeilyseinän korkeus m", + :se "Klätterväggens höjd m", + :en "Climbing wall height"}, + :data-type "numeric", + :description + {:fi "Kiipeilyseinän korkeus metreinä (max)", + :se "Klätterväggens höjd i meter (max)", + :en ""}}, + :route-width-m + {:name + {:fi "Reitin leveys m", + :se "Ruttens bredd m", + :en "Route's width m"}, + :data-type "numeric", + :description + {:fi "Reitin leveys metreinä", :se "Banans bredd i meter", :en ""}}, + :rapid-canoeing-centre? + {:name + {:fi "Koskimelontakeskus", + :se "Centrum för paddling", + :en "Rapid canoeing centre"}, + :data-type "boolean", + :description + {:fi "Kilpailujen järjestäminen mahdollista.", + :se "Möjligt att arrangera tävlingar.", + :en "Competitions possible."}}, + :beach-length-m + {:name + {:fi "Rannan pituus m", + :se "Strandens längd m", + :en "Length of beach m"}, + :data-type "numeric", + :description + {:fi "Hoidetun rannan pituus metreinä", + :se "Skötta strandens längd i meter", + :en ""}}, + :match-clock? + {:name {:fi "Ottelukello", :se "Matchklocka", :en "Match clock"}, + :data-type "boolean", + :description + {:fi "Onko liikuntapaikalla ottelukello", + :se "Finns det en matchklocka vid idrottsplatsen", + :en ""}}, + :sprint-track-length-m + {:name + {:fi "Etusuoran pituus m", + :se "Raksträckans längd (framför läktaren)", + :en "Length of sprint track"}, + :data-type "numeric", + :description + {:fi "Juoksuradan etusuoran pituus", + :se "Längden på löpbanans raksträcka", + :en ""}}, + :inner-lane-length-m + {:name + {:fi "Sisäradan pituus m", + :se "Innerbanans längd m", + :en "Length of inner lane m"}, + :data-type "numeric", + :description + {:fi "Sisäradan pituus kiertävissä radoissa", + :se "Längden på innerbanan i de cirkulerande banorna", + :en ""}}, + :discus-throw-places + {:name + {:fi "Kiekonheittopaikat lkm", + :se "Diskusplatser st.", + :en "Number of discus throw places"}, + :data-type "numeric", + :description + {:fi "Kiekonheittopaikkojen lukumäärä", + :se "Antalet diskuskastningsplatser", + :en ""}}, + :fields-count + {:name + {:fi "Kenttien lkm", :se "Antalet planer", :en "Number of fields"}, + :data-type "numeric", + :description + {:fi "Montako saman tyypin kenttää liikuntapaikassa on", + :se "Hur många planer av samma typ har motionsplatsen", + :en ""}}, + :field-1-width-m + {:name + {:fi "1. kentän leveys m", + :se "Första planens bredd m", + :en "1. field's width m"}, + :data-type "numeric", + :description + {:fi "1. kentän leveys metreinä", + :se "Första planens bredd i meter", + :en ""}}, + :field-3-width-m + {:name + {:fi "3. kentän leveys m", + :se "Tredje planens bredd m", + :en "3. field's width m"}, + :data-type "numeric", + :description + {:fi "3. kentän leveys metreinä", + :se "Tredje planens bredd i meter", + :en ""}}, + :field-2-width-m + {:name + {:fi "2. kentän leveys m", + :se "Andra planens bredd m", + :en "2. field's width m"}, + :data-type "numeric", + :description + {:fi "2. kentän leveys metreinä", + :se "Andra planens bredd i meter", + :en ""}}, + :badminton-courts-count + {:name + {:fi "Sulkapallokentät lkm", + :se "Antalet badmintonsplaner", + :en "Badminton courts pcs"}, + :data-type "numeric", + :description + {:fi "Sulkapallokenttien lukumäärä salissa", + :se "Antalet badmintonsplaner i salen", + :en ""}}, + :fitness-stairs-length-m + {:name + {:fi "Kuntoportaiden pituus m", + :se "Längden på tränings trapporna m", + :en "Length of the fitness stairs m"}, + :data-type "numeric", + :description {:fi "", :se "", :en ""}}, + :free-customer-use? + {:name + {:fi "Vapaa asiakaskäyttö", + :se "Fri kundanvändning", + :en "Free customer use"}, + :data-type "boolean", + :description + {:fi + "Liikuntapaikka on asiakkaiden käytettävissä esim. kulkukortilla ilman henkilökunnan läsnäoloa. Vapaa asiakaskäyttö voi olla rajattu tiettyihin kellonaikoihin.", + :se "", + :en ""}}, + :hammer-throw-places-count + {:name + {:fi "Moukarinheittopaikat lkm", + :se "Antalet släggkastningsplatser", + :en "Hammer throw"}, + :data-type "numeric", + :description + {:fi "Moukarinheittopaikkojen lukumäärä", + :se "Antal platser för att släggkastning", + :en ""}}, + :may-be-shown-in-harrastuspassi-fi? + {:name + {:fi "Saa julkaista Harrastuspassi.fi-sovelluksessa", + :se "Får publiceras i Harrastuspassi.fi", + :en "May be shown in Harrastuspassi.fi"}, + :data-type "boolean", + :description + {:fi "Kohteen tiedot saa julkaista Harrastuspassi.fi-sovelluksessa", + :se + "När du kryssat för rutan ”Kan visas på Harrastuspassi.fi” flyttas uppgifterna om idrottsanläggningen automatisk till Harrastuspassi.fi –applikationen.", + :en + "When the option ”May be shown in Harrastuspassi.fi” is ticked, the information regarding the sport facility will be transferred automatically to the Harrastuspassi.fi application."}}, + :pool-width-m + {:name + {:fi "1. altaan leveys m", + :se "Första bassängens bredd m", + :en "1. pool's width"}, + :data-type "numeric", + :description + {:fi "1. altaan/pääaltaan leveys metreinä", + :se "Första/huvudbassängens bredd i meter", + :en ""}}, + :pool-min-depth-m + {:name + {:fi "1. altaan syvyys min m", + :se "1a bassängens djup min m", + :en "1. pool's depth min m"}, + :data-type "numeric", + :description + {:fi "1. altaan syvyys matalimmasta päästä metreinä", + :se "Första bassängens grundaste punkt i meter.", + :en ""}}, + :padel-courts-count + {:name + {:fi "Padelkentät lkm", + :se "Antalet padelbanor", + :en "Number of padel courts"}, + :data-type "numeric", + :description {:fi "", :se "", :en ""}}, + :hs-point + {:name {:fi "HS-piste", :se "HS-punkt", :en "HS Point"}, + :data-type "numeric", + :description + {:fi "Hyppyrimäen HS-piste metreinä", + :se "HS-punkten i backhoppning i meter", + :en "Ski jumping hill HS point in "}}, + :ice-rinks-count + {:name {:fi "Kaukalot lkm", :se "Antalet rinkar", :en "Ice rinks"}, + :data-type "numeric", + :description + {:fi "Kaukaloiden lukumäärä", + :se "Antalet rinkar (hockey) det finns vid idrottsplatsen", + :en ""}}, + :field-1-area-m2 + {:name + {:fi "1. kentän ala m2", + :se "Första planens areal m2", + :en "1. field's area sq. m"}, + :data-type "numeric", + :description + {:fi "1. kentän pinta-ala neliömetreinä", + :se "Första planens areal i kvadratmeter", + :en ""}}, + :k-point + {:name {:fi "K-piste", :se "K-punkt", :en "K point"}, + :data-type "numeric", + :description + {:fi "Hyppyrimäen k-piste metreinä", + :se "Hoppbackens k-punkt i meter", + :en ""}}, + :polevault-places-count + {:name + {:fi "Seiväshyppypaikat lkm", + :se "Antalet stavhoppsplatser", + :en "Pole vault"}, + :data-type "numeric", + :description + {:fi "Seiväshyppypaikkojen lukumäärä", + :se "Antalet stavhoppningsplatser", + :en ""}}, + :group-exercise-rooms-count + {:name + {:fi "Ryhmäliikuntatilat lkm", + :se "Antalet gruppmotions utrymmen", + :en "Room for exercise groups"}, + :data-type "numeric", + :description + {:fi "Liikuntasalien ja ryhmäliikuntatilojen lukumäärä", + :se "Antalet gymnastiksalar och gruppmotions utrymmen", + :en ""}}, + :snowpark-or-street? + {:name + {:fi "Parkki", :se "Trick/street pist", :en "Snow park/street"}, + :data-type "boolean", + :description + {:fi + "Onko rinnehiihtokeskuksessa ns. temppurinne, snowpark tai vastaava", + :se "Har skidcentrumet en trickbana, snowpark eller något liknande", + :en ""}}, + :field-2-flexible-rink? + {:name + {:fi "2. kenttä: onko joustokaukalo?", + :se "Fält 2: finns det flexibel rink?", + :en "Field 2: is there a flexible rink?"}, + :data-type "boolean", + :description {:fi "", :se "", :en ""}}, + :space-divisible + {:name + {:fi "Tila jaettavissa osiin", + :se "Utrymmet kan delas upp", + :en "Space can be divided"}, + :helper-text + {:fi "Moneenko osaan tila on jaettavissa (lkm)", + :se "Ange antalet delar som utrymmet kan delas in i", + :en + "Enter the number of sections into which the space can be divided"}, + :data-type "number", + :description + {:fi + "Onko tila jaettavissa osiin esim. jakoseinien tai -verhojen avulla", + :se + "Är utrymmet delbart i sektioner, till exempel med skiljeväggar eller gardiner", + :en + "Is the space divisible into sections, for example, with partition walls or curtains"}}, + :max-vertical-difference + {:name + {:fi "Korkeusero max m", + :se "Höjdskillnad max m", + :en "Max vertical difference"}, + :data-type "numeric", + :description + {:fi "Suurin korkeusero rinteissä", + :se "Största höjdskillnaden i slalombackorna", + :en ""}}, + :bowling-lanes-count + {:name + {:fi "Keilaradat lkm", + :se "Antalet bowlingbanor", + :en "Bowling lanes"}, + :data-type "numeric", + :description + {:fi "Keilaratojen lukumäärä", :se "Antalet bowlingbanor", :en ""}}, + :air-gun-shooting? + {:name + {:fi "Ilma-aseammunta", + :se "Luftgevärsskytte", + :en "Air gun shooting"}, + :data-type "boolean", + :description + {:fi "Ilma-aseammuntamahdollisuus", + :se "Möjlighet för luftgevärsskytte", + :en ""}}, + :gymnastic-routines-count + {:name + {:fi "Telinevoimistelusarjat lkm", + :se "Antalet redskapsgymnastikserier", + :en "Gymnastic routines"}, + :data-type "numeric", + :description + {:fi "Telinevoimistelun telinesarjojen lukumäärä", + :se "Antalet redskap för redskapsgymnastik", + :en ""}}, + :toilet? + {:name {:fi "Yleisö-wc", :se "Allmän toalett", :en "Toilet"}, + :data-type "boolean", + :description + {:fi "Onko kohteessa yleiseen käyttöön tarkoitettuja wc-tiloja?", + :se "Är allmänna toaletten i användning", + :en ""}}, + :gymnastics-space? + {:name + {:fi "Telinevoimistelutila", + :se "Utrymme för redskapsgymnastik", + :en "Space for gymnastics"}, + :data-type "boolean", + :description + {:fi "Onko liikuntasalissa myös telinevoimistelutila", + :se "Har motionssalen också område/utrymme för redskapsgymnastik", + :en ""}}, + :snooker-tables-count + {:name + {:fi "Snookerpöydät lkm", + :se "Antal snookerbord", + :en "Number of snooker tables"}, + :data-type "numeric", + :description {:fi "", :se "", :en ""}}, + :show-jumping? + {:name {:fi "Esteratsastus", :se "Banhoppning", :en "Show jumping"}, + :data-type "boolean", + :description + {:fi + "Onko ratsastuskentällä/maneesissa esteratsastukseen soveltuva varustus", + :se "Har ridplanen/ridhuset utrustning för banhoppning", + :en ""}}, + :shower? + {:name {:fi "Suihku", :se "Dusch", :en "Shower"}, + :data-type "boolean", + :description + {:fi "Onko suihku käytettävissä", + :se "Är duschen i användning", + :en ""}}, + :rest-places-count + {:name + {:fi "Taukopaikat lkm", + :se "Antalet viloplatser", + :en "Rest places"}, + :data-type "numeric", + :description + {:fi "Montako taukopaikkaa reitin varrella on", + :se "Hur många viloplatser finns det längs med rutten", + :en ""}}, + :changing-rooms? + {:name {:fi "Pukukopit", :se "Omklädningsrum", :en "Changing rooms"}, + :data-type "boolean", + :description + {:fi "Onko pukukoppeja", :se "Finns det omklädningsrum", :en ""}}, + :pistol-shooting? + {:name + {:fi "Pistooliammunta", :se "Pistolskytte", :en "Pistol shooting"}, + :data-type "boolean", + :description + {:fi "Pistooliammuntamahdollisuus", + :se "Möjlighet för pistolskytte", + :en ""}}, + :halfpipe-count + {:name + {:fi "Halfpipe lkm", :se "Antal halfpipe", :en "Halfpipe count"}, + :data-type "numeric", + :description + {:fi "Halfpipe, superpipe lukumäärät", + :se "Antal halfpipe", + :en ""}}, + :shooting-positions-count + {:name + {:fi "Ampumapaikat lkm", + :se "Antalet skytteplatser", + :en "Shooting positions"}, + :data-type "numeric", + :description + {:fi "Montako ampumapaikkaa liikuntareitin varrella on", + :se "Hur många skytteplatser finns det längs motionsrutten", + :en ""}}, + :running-track-surface-material + {:name + {:fi "Juoksuradan pintamateriaali", + :se "Löpbanans ytmaterial", + :en "Surface material for running track"}, + :data-type "string", + :description + {:fi "Juoksuradan pintamateriaali/päällyste", + :se "Löpbanans ytmaterial/pålägg", + :en ""}}, + :boating-service-class + {:name + {:fi "Venesatama- tai laituriluokka", + :se "Båthamn eller bryggklass", + :en "Boat harbor or pier class"}, + :description + {:fi + "https://ava.vaylapilvi.fi/ava/Julkaisut/MKL/mkl_2008-1_venesatamien_luokitus.pdf", + :se + "https://ava.vaylapilvi.fi/ava/Julkaisut/MKL/mkl_2008-1_venesatamien_luokitus.pdf", + :en + "https://ava.vaylapilvi.fi/ava/Julkaisut/MKL/mkl_2008-1_venesatamien_luokitus.pdf"}, + :data-type "enum", + :opts + {"home-harbor" + {:label {:fi "Kotisatama", :en "Home harbor", :se "Hemmahamn"}, + :description + {:fi + "Satama, jossa veneet pääasiallisesti säilytetään veneilykauden aikana ja jossa veneen omistaja joko omistaa tai hallitsee venepaikan. Satamat ovat yleensä kunnallisia, kaupallisia tai veneseurojen ylläpitämiä satamia.", + :en + "A harbor where boats are mainly stored during the boating season and where the boat owner either owns or controls the berth. Harbors are usually municipal, commercial, or maintained by boating clubs.", + :se + "En hamn där båtar huvudsakligen förvaras under båtsäsongen och där båtägaren antingen äger eller kontrollerar båtplatsen. Hamnarna är vanligtvis kommunala, kommersiella eller underhålls av båtklubbar."}}, + "visiting-harbor" + {:label + {:fi "Vierassatama (Palvelusatama, Vieraslaituri, Retkisatama)", + :en "Visiting harbor", + :se "Besökshamn"}, + :description + {:fi + "Satama, jossa veneretken tai matkapurjehduksen aikana voi käydä kaupassa, asioimassa, lepäämässä, yöpymässä tai veneen huollossa.", + :en + "A harbor where during a boating trip or sailing voyage you can go shopping, run errands, rest, stay overnight, or service the boat.", + :se + "En hamn där du under en båttur eller seglingsresa kan handla, göra ärenden, vila, övernatta eller serva båten."}}, + "safety-harbor" + {:label + {:fi "Turvasatama (Suojasatama, Hätäsatama)", + :en "Safety harbor", + :se "Säkerhetshamn"}, + :description + {:fi + "Satama, josta voidaan hakea suojaa tai saada ensiapua tai korjausapua.", + :en + "A harbor where you can seek shelter or get first aid or repair assistance.", + :se + "En hamn där man kan söka skydd eller få första hjälp eller reparationshjälp."}}, + "canoe-pier" + {:label {:fi "Melontalaituri", :en "Canoe pier", :se "Kanotbrygga"}, + :description + {:fi "Melontaan tarkoitettu laituri.", + :en "Pier intended for canoeing.", + :se "Brygga avsedd för kanotpaddling."}}, + "no-class" + {:label + {:fi + "Kohde ei täytä minkään venesatama- tai laituriluokan vaatimuksia (esim. rantautumispaikka)", + :en + "The target does not meet the requirements of any marina or dock class (e.g., landing place)", + :se + "Objektet uppfyller inte kraven för någon småbåtshamn- eller bryggklass (t.ex. landningsplats)"}, + :description + {:fi + "Kohde ei täytä minkään venesatama- tai laituriluokan vaatimuksia (esim. rantautumispaikka).", + :en + "The site does not meet the requirements of any boat harbor or pier class (e.g., landing place).", + :se + "Platsen uppfyller inte kraven för någon båthamn eller bryggklass (t.ex. landningsplats)."}}, + "no-information" + {:label + {:fi "Ei tietoa", + :se "Ingen information", + :en "No information"}}}}, + :tatamis-count + {:name + {:fi "Tatamit ja mattoalueet lkm", + :se "Antal tatami- och mattområden", + :en "Tatamis and mat areas"}, + :data-type "numeric", + :description + {:fi "Tatamien ja mattoalueiden lukumäärä", + :se "Antal tatami- och mattområden", + :en "Number of tatami and mat areas"}}, + :lit-route-length-km + {:name + {:fi "Valaistua reittiä km", + :se "Belyst rutt km", + :en "Lit route's length km"}, + :data-type "numeric", + :description + {:fi "Montako kilometriä reitistä on valaistua", + :se "Hur många km av rutten är uppbelyst", + :en ""}}, + :area-m2 + {:name + {:fi "Liikuntapinta-ala m2", + :se "Areal m2", + :en "Area in square meters"}, + :data-type "numeric", + :description + {:fi "Liikuntapaikan liikuntapinta-ala, neliömetreinä", + :se "Idrottsplatsens areal i kvadratmeter", + :en ""}}, + :field-width-m + {:name + {:fi "Kentän leveys m", :se "Planens bredd m", :en "Width of field"}, + :data-type "numeric", + :description + {:fi "Kentän/kenttien leveys mahdollisine turva-alueineen metreinä", + :se "Planens/planernas bredd i meter", + :en ""}}, + :cosmic-bowling? + {:name {:fi "Hohtokeilaus", :se "Discobowling", :en "Cosmic bowling"}, + :data-type "boolean", + :description + {:fi "Onko keilaradalla hohtokeilausmahdollisuus", + :se "Har bowlingsbanan möjlighet för discobowling", + :en ""}}, + :travel-modes + {:name {:fi "Kulkutavat", :se "Resesätt", :en "Travel Modes"}, + :data-type "enum-coll", + :opts + {"by-foot" + {:label {:fi "Jalan", :en "On Foot", :se "Till fots"}, + :description + {:fi "Liikkuminen jalkaisin", + :en "Traveling on foot", + :se "Att resa till fots"}}, + "snow-shoes" + {:label + {:fi "Lumikengillä", :en "With Snowshoes", :se "Med snöskor"}, + :description + {:fi "Liikkuminen lumikengillä", + :en "Traveling with snowshoes", + :se "Att resa med snöskor"}}, + "fat-bike" + {:label + {:fi "Läskipyörällä", :en "With Fat Bike", :se "Med fatbike"}, + :description + {:fi "Liikkuminen läskipyörällä", + :en "Traveling with a fat bike", + :se "Att resa med fatbike"}}}, + :description + {:fi "Lisää reitille soveltuvat kulkutavat", + :se "Lägg till lämpliga resesätt för rutten", + :en "Add suitable travel modes for the route"}}, + :wrestling-mats-count + {:name + {:fi "Painimatot lkm", + :se "Brottarmattor st.", + :en "Wrestling mats pcs"}, + :data-type "numeric", + :description + {:fi "Painimattojen lukumäärä", :se "Antal brottarmattor", :en ""}}, + :lighting-info + {:name + {:fi "Valaistuksen lisätieto", + :se "Ytterligare information om belysningen", + :en "Additional information about the lighting"}, + :data-type "string", + :description + {:fi "Esim. lux-määrä tai muu tarkentava tieto", + :se "T.ex. lux-mängd eller annan förtydligande information", + :en "E.g. lux amount or other specifying information"}}, + :eu-beach? + {:name {:fi "EU-uimaranta", :se "EU-badstrand", :en "EU beach"}, + :data-type "boolean", + :description + {:fi + "Uimaranta, joka täyttää EU-kriteerit uimaveden laadusta ja valvonnasta", + :se + "Badstrand, som fyller EU-kriterierna med kvaliteten och övervakningen av badvattnet", + :en ""}}, + :rifle-shooting? + {:name + {:fi "Kivääriammunta", :se "Gevärbana", :en "Rifle shooting places"}, + :data-type "boolean", + :description + {:fi "Kivääriammuntamahdollisuus", + :se "Möjlighet för gevärskytte", + :en ""}}, + :swimming-pool-count + {:name + {:fi "Altaiden lukumäärä", + :se "Antalet simbassänger", + :en "Number of swimming pools"}, + :data-type "numeric", + :description + {:fi + "Altaiden lukumäärä yhteensä. Syötä tieto tai laske automaattisesti.", + :se "Antalet simbassänger, också terapi bassänger", + :en ""}}, + :pool-water-area-m2 + {:name + {:fi "Vesipinta-ala m2", + :se "Bassängernas vatten areal", + :en "Pool water area in sq. m"}, + :data-type "numeric", + :description + {:fi "Asiakaskäytössä oleva vesipinta-ala yhteensä.", + :se "Den totala vattenytan tillgänglig för kunder.", + :en "The total water surface area available for customers."}}, + :highest-obstacle-m + {:name + {:fi "Korkeimman esteen korkeus m", + :se "Höjden på den högsta hindret m", + :en "The height of the highest obstacle m"}, + :data-type "numeric", + :description {:fi "", :se "", :en ""}}, + :year-round-use? + {:name + {:fi "Ympärivuotinen käyttö", + :se "Året runt användning", + :en "Year-round Use"}, + :data-type "boolean", + :description + {:fi "Kohde on ympärivuotisessa käytössä", + :se "Platsen är i användning året runt", + :en "The location is in use year-round"}}, + :curling-lanes-count + {:name + {:fi "Curling-ratojen lukumäärä", + :se "Antal curlingbanor", + :en "Count of curling lanes"}, + :data-type "numeric", + :description + {:fi "Curling-ratojen lukumäärä", + :se "Antal curlingbanor", + :en "Number of curling lanes"}}, + :climbing-wall-width-m + {:name + {:fi "Kiipeilyseinän leveys m", + :se "Klätterväggens bredd m", + :en "Climbing wall width"}, + :data-type "numeric", + :description + {:fi "Kiipeilyseinän leveys metreinä sivusuunnassa", + :se "Bredden på klätterväggen i meter i sidled", + :en "Width of the climbing wall in meters laterally"}}, + :area-km2 + {:name + {:fi "Pinta-ala km2", + :se "Areal km2", + :en "Area in square kilometres"}, + :data-type "numeric", + :description + {:fi "Alueen pinta-ala neliökilometreinä", + :se "Områdets areal i kvadratkilometer", + :en "Area of the region in square kilometers"}}, + :scoreboard? + {:name {:fi "Tulostaulu", :se "Resultattavla", :en "Score board"}, + :data-type "boolean", + :description + {:fi "Onko liikuntapaikalla tulostaulu/sähköinen tulostaulu", + :se "Finns det en resultattavla/elektronisk resultattavla på idrottsplatsen", + :en "Is there a scoreboard/electronic scoreboard at the sports facility"}}, + :futsal-fields-count + {:name + {:fi "Futsal-kentät lkm", + :se "Antalet Futsal-planer", + :en "Number of futsal fields"}, + :data-type "numeric", + :description + {:fi "Futsal-kenttien lukumäärä", + :se "Antal futsalplaner", + :en "Number of futsal courts"}}, + :ski-orienteering? + {:name + {:fi "Hiihtosuunnistus mahdollista", + :se "Skidorientering möjlig", + :en "Ski Orienteering Possible"}, + :data-type "boolean", + :description {:fi "", :se "", :en ""}}, + :training-wall? + {:name + {:fi "Lyöntiseinä", + :se "Vägg att träna på tennis", + :en "Training wall for tennis"}, + :data-type "boolean", + :description + {:fi "Onko tenniskentällä lyöntiseinä", + :se "Finns det en träningsvägg vid tennisplanen", + :en "Is there a hitting wall on the tennis court"}}, + :shotput-count + {:name + {:fi "Kuulantyöntöpaikat lkm", + :se "Antalet kulstötningsplatser", + :en "Shot put"}, + :data-type "numeric", + :description + {:fi "Kuulantyöntöpaikkojen lukumäärä", + :se "Antal kulstötningsplatser", + :en "Number of shot put areas"}}, + :active-space-length-m + {:name + {:fi "Liikuntakäytössä olevan tilan pituus m", + :se "Längd på aktivt utrymme m", + :en "Length of active space m"}, + :data-type "numeric", + :description + {:fi "Liikuntakäytössä olevan tilan pituus (m)", :se "", :en ""}}, + :longjump-places-count + {:name + {:fi "Pituus- ja kolmiloikkapaikat lkm", + :se "Antalet längd- och trestegshopp platser", + :en "Long jump"}, + :data-type "numeric", + :description + {:fi "Pituus- ja kolmiloikkapaikkojen lukumäärä", + :se "Antal längd- och trestegshoppsplatser", + :en "Number of long jump and triple jump areas"}}, + :football-fields-count + {:name + {:fi "Jalkapallokentät lkm", + :se "Antalet fotbollsplaner", + :en "Football fields pcs"}, + :data-type "numeric", + :description + {:fi "Montako jalkapallokenttää mahtuu saliin/halliin", + :se "Hur många fotbollsplaner ryms i salen/hallen", + :en "How many football (soccer) fields can fit in the hall"}}, + :floorball-fields-count + {:name + {:fi "Salibandykentät lkm", + :se "Antalet innebandyplaner", + :en "Floor ball field"}, + :data-type "numeric", + :description + {:fi "Salibandykenttien lukumäärä", + :se "Antalet innebandyplaner", + :en "Number of floorball courts"}}, + :auxiliary-training-area? + {:name + {:fi "Oheisharjoittelutila", + :se "Kompletterande träningsområde", + :en "Auxiliary training area"}, + :data-type "boolean", + :description + {:fi + "Onko kohteessa oheisharjoitteluun soveltuva tila? Oheisharjoittelutila on liikuntapaikan käyttäjille tarkoitettu erillinen pienliikuntatila, jota voidaan käyttää esim. lämmittelyyn tai oheisharjoitteluun. Tilan koko, varustelu ja pintamateriaali ovat oheisharjoitteluun soveltuvia.", + :se "Finns det en lämplig plats för kompletterande träning på platsen? En kompletterande träningsyta är en separat mindre träningsyta avsedd för användare av idrottsanläggningen, som kan användas till exempel för uppvärmning eller kompletterande träning. Utrymmets storlek, utrustning och ytskikt är lämpliga för kompletterande träning.", + :en "Is there a suitable area for supplementary training at the facility? A supplementary training area is a separate small exercise space intended for users of the sports facility, which can be used, for example, for warm-ups or supplementary training. The size, equipment, and surface material of the area are suitable for supplementary training."}}, + :equipment-rental? + {:name + {:fi "Välinevuokraus", + :se + "Uthyrning av idrottsutrustning t.ex. slalom,skidning, terräncyklar osv.", + :en "Equipment rental"}, + :data-type "boolean", + :description + {:fi "Välinevuokraus mahdollista", + :se "Möjlighet att hyra utrustning", + :en "Equipment rental available"}}, + :slopes-count + {:name + {:fi "Rinteiden lkm", + :se "Antalet slalombackar", + :en "Number of slopes"}, + :data-type "numeric", + :description + {:fi "Rinteiden määrä yhteensä", + :se "Totala antalet slalombackar", + :en "Total number of slopes"}}, + :pool-length-m + {:name + {:fi "1. altaan pituus m", + :se "Första bassängens längd", + :en "1. pool's length"}, + :data-type "numeric", + :description + {:fi "1. altaan/pääaltaan pituus metreinä", + :se "Första/huvudbassängens längd i meter", + :en ""}}, + :other-pools-count + {:name + {:fi "Muut altaat lkm", + :se "Antalet andra bassänger", + :en "Number of other pools"}, + :data-type "numeric", + :description + {:fi "Porealtaiden, kylmäaltaiden yms lukumäärä yhteensä", + :se "Antalet övriga bassänger såsom bubbelpool, kallbassäng o.dyl.", + :en "Total number of hot tubs, cold pools, etc."}}, + :shortest-slope-m + {:name + {:fi "Lyhin rinne m", + :se "Kortaste slalombacken m", + :en "Shortest slope m"}, + :data-type "numeric", + :description + {:fi "Lyhimmän rinteen pituus metreinä", + :se "Kortaste skidbacken i meter", + :en "Length of the shortest slope in meters"}}, + :pool-tables-count + {:name + {:fi "Poolpöydät lkm", + :se "Antal poolbord", + :en "Number of pool tables"}, + :data-type "numeric", + :description {:fi "", :se "", :en ""}}, + :squash-courts-count + {:name + {:fi "Squash-kentät lkm", + :se "Antalet squashplaner", + :en "Squash courts"}, + :data-type "numeric", + :description + {:fi "Squash-kenttien lukumäärä", + :se "Antalet squash-planer", + :en ""}}, + :changing-rooms-m2 + {:name + {:fi "Pukukoppien kokonaispinta-ala m²", + :se "Omklädningsrummens totala yta m²", + :en "Total area of the changing rooms in m²"}, + :data-type "numeric", + :description {:fi "", :se "", :en ""}}, + :ringette-boundary-markings? + {:name + {:fi "Ringeten rajamerkinnät", + :se "Gränsmarkeringar för ringette", + :en "Ringette boundary markings"}, + :data-type "boolean", + :description + {:fi "Onko kaukaloissa ringeten rajamerkinnät?", :se "", :en ""}}, + :boxing-rings-count + {:name + {:fi "Nyrkkeilykehät lkm", + :se "Antalet boxningsringar", + :en "Boxing rings pcs"}, + :data-type "numeric", + :description + {:fi "Nyrkkeilykehien lukumäärä", + :se "Antalet boxningsringar", + :en ""}}, + :ice-reduction? + {:name {:fi "Jäätymisenesto", :se "Frostskydd", :en "Ice reduction"}, + :data-type "boolean", + :description + {:fi "Jäätymisenestojärjestelmä talviuintipaikassa", + :se "Har vinterbadplatsen mekanism för frostskydd", + :en ""}}, + :activity-service-company? + {:name + {:fi "Ohjelmapalveluyritys", :se "", :en "Activity service company"}, + :data-type "boolean", + :description + {:fi "Toimiiko kohteessa ohjelmapalveluyritys.", :se "", :en ""}}, + :field-1-flexible-rink? + {:name + {:fi "1. kenttä: onko joustokaukalo?", + :se "Fält 1: finns det flexibel rink?", + :en "Field 1: is there a flexible rink?"}, + :data-type "boolean", + :description {:fi "", :se "", :en ""}}, + :fencing-bases-count + {:name + {:fi "Miekkailualustat lkm", + :se "Antalet fäktnings underlag", + :en "Fencing bases"}, + :data-type "numeric", + :description + {:fi "Miekkailualustojen lukumäärä", + :se "Antal underlägg avsedda för fäktning", + :en ""}}, + :weight-lifting-spots-count + {:name + {:fi "Painonnostopaikat/nostolavat lkm", + :se "Antal tyngdlyftningsplatser/lyftplattformar", + :en "Number of weightlifting areas/platforms"}, + :data-type "numeric", + :description + {:fi + "Painnostopaikkojen lukumäärä. Huom. nostolava on painonnostopaikka, joka kestää painojen pudottamisen", + :se + "Antal tyngdlyftningsplatser. Obs: En lyftplattform är en tyngdlyftningsplats som tål att vikter tappas.", + :en + "Number of weightlifting areas. Note: A lifting platform is a weightlifting area that can withstand the dropping of weights."}}, + :landing-places-count + {:name + {:fi "Alastulomontut lkm", + :se "Antalet landningsgropar", + :en "Landing places"}, + :data-type "numeric", + :description + {:fi "Alastulomonttujen lukumäärä", + :se "Antalet landnigsgropar", + :en ""}}, + :bike-orienteering? + {:name + {:fi "Pyöräsuunnistus mahdollista", + :se "Cykelorientering möjlig", + :en "Bike Orienteering Possible"}, + :data-type "boolean", + :description {:fi "", :se "", :en ""}}, + :toboggan-run? + {:name {:fi "Ohjaskelkkamäki", :se "Rodelbana", :en "Toboggan run"}, + :data-type "boolean", + :description + {:fi "Onko rinnehiihtokeskuksessa ohjaskelkkamäki", + :se "Har skidcentrumet en rodelbana", + :en ""}}, + :sauna? + {:name {:fi "Sauna", :se "Bastu", :en "Sauna"}, + :data-type "boolean", + :description + {:fi "Onko sauna käytettävissä", + :se "Är bastun i användning", + :en ""}}, + :jumps-count + {:name + {:fi "Hyppyrien lkm", + :se "Antalet hoppbackar", + :en "Number of jumps"}, + :data-type "numeric", + :description + {:fi "Hyppyrien lukumäärä", :se "Antalet hoppbackar", :en ""}}, + :table-tennis-count + {:name + {:fi "Pöytätennispöytien lkm", + :se "Antalet bord för bordtennis", + :en "Table tennis table count"}, + :data-type "numeric", + :description + {:fi "Pingis-/pöytätennispöytien lukumäärä", + :se "Antal bordtennisbord (pingisbord)", + :en ""}}, + :pool-max-depth-m + {:name + {:fi "1. altaan syvyys max m", + :se "Första bassängens max djup m", + :en "1. pool's depth max m"}, + :data-type "numeric", + :description + {:fi "1. altaan syvyys syvimmästä päästä metreinä", + :se "Första bassängens djupaste punkt i meter", + :en ""}}, + :loudspeakers? + {:name {:fi "Äänentoisto", :se "Ljudåtergivning", :en "Loudspeakers"}, + :data-type "boolean", + :description + {:fi + "Onko liikuntapaikalla välineistö ja valmius kenttäkuulutuksiin", + :se + "Har motionsplatsen utrustning och färdighet till att göra utrop", + :en ""}}, + :customer-service-point? + {:name + {:fi "Myynti- tai asiakaspalvelupiste", + :en "Sales or customer service point", + :se "Försäljnings- eller kundservicepunkt"}, + :description + {:fi + "Liikuntapaikalla on pysyvä myynti- tai asiakaspalvelupiste, josta on saatavissa asiakaspalvelua. Myynti- tai asiakaspalvelupiste voi olla rajoitetusti auki liikuntapaikan käyttöaikojen puitteissa.", + :se + "Det finns en permanent försäljnings- eller kundservicestation på idrottsanläggningen där kundservice är tillgänglig. Försäljnings- eller kundservicestationen kan ha begränsade öppettider inom idrottsanläggningens användningstider.", + :en + "There is a permanent sales or customer service point at the sports facility, where customer service is available. The sales or customer service point may have limited opening hours within the usage hours of the sports facility."}, + :data-type "boolean"}, + :shotgun-shooting? + {:name + {:fi "Haulikkoammunta", + :se "Hagelgevärsskytte", + :en "Shotgun shooting"}, + :data-type "boolean", + :description + {:fi "Haulikkoammuntamahdollisuus", + :se "Möjlighet för hagelskytte", + :en ""}}, + :water-point + {:name {:fi "Vesipiste", :en "Water point", :se "Vattenpunkt"}, + :description {:fi "", :se "", :en ""}, + :data-type "enum", + :opts + {"year-round" + {:label {:fi "Ympärivuotinen", :se "Året runt", :en "Year-round"}}, + "seasonal" + {:label + {:fi "Kausittaisesti käytössä", + :se "Säsongsvis i bruk", + :en "Seasonally in use"}}}}, + :lit-slopes-count + {:name + {:fi "Valaistut rinteet lkm", + :se "Antalet belysta slalombackar", + :en "Number of lit slopes"}, + :data-type "numeric", + :description + {:fi "Montako rinnettä on valaistu", + :se "Hur många belysta slalombackar finns det", + :en ""}}, + :green? + {:name {:fi "Puttausviheriö", :se "Puttnings green", :en "Green"}, + :data-type "boolean", + :description + {:fi "Onko golfkentällä puttausviheriö", + :se "Finns det en puttnings green vid golfbanan", + :en ""}}, + :free-rifle-shooting? + {:name + {:fi "Pienoiskivääriammunta", + :se "Miniatyrgevärsskytte", + :en "Free rifle shooting"}, + :data-type "boolean", + :description + {:fi "Pienoiskivääriammuntamahdollisuus", + :se "Möjlighet förminiatyrgevärskytte", + :en ""}}, + :winter-usage? + {:name {:fi "Talvikäyttö", :se "Vinterbruk", :en "Winter usage"}, + :data-type "boolean", + :description + {:fi "Liikuntapaikka on käytössä myös talvisin", + :se "Motionsplatsen är i bruk under vintern", + :en ""}}, + :ligthing? + {:name {:fi "Valaistus", :se "Belysning", :en "Lighting"}, + :data-type "boolean", + :description + {:fi "Onko liikuntapaikka valaistu", + :se "Är idrottsplatsen uppbelyst", + :en ""}}, + :field-3-area-m2 + {:name + {:fi "3. kentän ala m2", + :se "Tredje planens areal m2", + :en "3. field's area sq. m"}, + :data-type "numeric", + :description + {:fi "3. kentän pinta-ala neliömetreinä", + :se "Tredje planens areal i kvadratmeter", + :en ""}}, + :accessibility-info + {:name + {:fi "Linkki esteettömyystietoon", + :se "Länk till tillgänglighetsinformation", + :en "Link to accessibility information"}, + :data-type "string", + :description + {:fi + "Syötä linkki verkkosivulle, jossa on kuvattu kohteen esteettömyyteen liittyvät tiedot", + :se + "Ange länken till webbplatsen där information om objektets tillgänglighet beskrivs.", + :en + "Enter the link to the website where the accessibility information of the location is described."}}, + :covered-stand-person-count + {:name + {:fi "Katettua katsomoa hlö", + :se "Takbeläggda läktarens person mängd", + :en "Stand with roof"}, + :data-type "numeric", + :description + {:fi "Katetun katsomon henkilömäärä", + :se "Hur mycket av läktaren är täckt med tak, antalet personer", + :en ""}}, + :playground? + {:name {:fi "Leikkipuisto", :se "Lekpark", :en "Playground"}, + :data-type "boolean", + :description + {:fi "Onko liikuntapaikan yhteydessä leikkipuisto", + :se "Finns det en lekpark i samband med idrottsplatsen", + :en ""}}, + :handball-fields-count + {:name + {:fi "Käsipallokentät lkm", + :se "Antalet handbollsplaner", + :en "Handball fields pcs"}, + :data-type "numeric", + :description + {:fi "Käsipallokenttien lukumäärä salissa", + :se "Antalet handbollsplaner som ryms i salen/hallen", + :en ""}}, + :p-point + {:name {:fi "P-piste", :se "P-punkt", :en "P point"}, + :data-type "numeric", + :description + {:fi "Hyppyrimäen P-piste metreinä", + :se "Hoppbackens P-punkt i meter", + :en ""}}, + :inruns-material + {:name + {:fi "Vauhtimäen latumateriaali", + :se "Överbackens spårmaterial", + :en "Inrun's material"}, + :data-type "string", + :description + {:fi "Hyppyrimäen vauhtimäen materiaali", + :se "Hoppbackens spårmaterial vid överbacken", + :en ""}}, + :pyramid-tables-count + {:name + {:fi "Pyramidipöydät lkm", + :se "Antal pyramidbord", + :en "Number of pyramid tables"}, + :data-type "numeric", + :description {:fi "", :se "", :en ""}}, + :basketball-field-type + {:name + {:fi "Koripallokentän tyyppi", + :se "Korgbollsplanens typ", + :en "Type of basketball field"}, + :data-type "string", + :description + {:fi + "Onko liikuntapaikka normaali koripallokenttä, minikoripallokenttä vai yhden korin koripallokenttä", + :se + "Har idrottsplaten en normal korgbollsplan, mini-korgbollsplan eller bara en korg", + :en ""}}, + :kaisa-tables-count + {:name + {:fi "Kaisapöydät lkm", + :se "Antal kaisabord", + :en "Number of kaisa tables"}, + :data-type "numeric", + :description {:fi "", :se "", :en ""}}, + :volleyball-fields-count + {:name + {:fi "Lentopallokentät lkm", + :se "Antalet volleybollplaner", + :en "Volleyball field"}, + :data-type "numeric", + :description + {:fi "Lentopallokenttien lukumäärä", + :se "Antalet volleybollplaner", + :en ""}}, + :boat-places-count + {:name + {:fi "Venepaikat lkm", :se "Antalet båtplats", :en "Boat places"}, + :data-type "numeric", + :description + {:fi "Venepaikkojen lukumäärä", :se "Antalet båtplatser", :en ""}}, + :pool-temperature-c + {:name + {:fi "1. altaan lämpö c", + :se "Första bassängens temperatur c", + :en "1. pool's temperature c"}, + :data-type "numeric", + :description + {:fi "1. altaan veden lämpötila celsiusasteina", + :se "Första bassängens vatten temperatur i celcius", + :en ""}}, + :climbing-wall? + {:name {:fi "Kiipeilyseinä", :se "Klättervägg", :en "Climbing wall"}, + :data-type "boolean", + :description + {:fi "Onko kohteessa kiipeilyseinä", + :se "Finns det en klättervägg på platsen", + :en "Is there a climbing wall at the location"}}, + :ski-track-freestyle? + {:name + {:fi "Luistelu-ura", :se "Fristils spår", :en "Freestyle ski track"}, + :data-type "boolean", + :description + {:fi "Vapaan tyylin latu-ura/luistelu-ura", + :se "Skidspår för fristil", + :en ""}}, + :spinning-hall? + {:name {:fi "Spinning-sali", :se "Spinning sal", :en "Spinning hall"}, + :data-type "boolean", + :description + {:fi "Salissa spinning-varustus", + :se "Salen har spinning utrustning", + :en ""}}, + :other-platforms? + {:name + {:fi "Muut hyppytelineet", + :se "Andra hoppställningar", + :en "Other platforms"}, + :data-type "boolean", + :description + {:fi "Uimahyppytelineet rannalla", + :se "Hopptornen vid stranden", + :en ""}}, + :school-use? + {:name + {:fi "Koululiikuntapaikka", + :se "Skolidrottsplats", + :en "Sport facility in school use"}, + :data-type "boolean", + :description + {:fi "Liikuntapaikkaa käytetään koulujen liikuntatunneilla", + :se "Idrottsplatsen används under skolornas gymnastiktimmar", + :en ""}}, + :highjump-places-count + {:name + {:fi "Korkeushyppypaikat lkm", + :se "Antalet höjdhopps platser", + :en "High jump"}, + :data-type "numeric", + :description + {:fi "Korkeushppypaikkojen lukumäärä", + :se "Antalet höjdhoppsplatser", + :en ""}}, + :light-roof? + {:name + {:fi "Kevytkate", :se "Lättvikts takläggning", :en "Light roof"}, + :data-type "boolean", + :description + {:fi "Kentälle voidaan asentaa kevytkate tai muu tilapäinen katos", + :se + "På planen kan installeras en lättvikts takläggning eller något annat tillfälligt tak", + :en ""}}, + :route-length-km + {:name + {:fi "Reitin pituus km", + :se "Ruttens längd km", + :en "Route's length km"}, + :data-type "numeric", + :description + {:fi "Reitin pituus kilometreinä", + :se "Ruttens längd i kilometer", + :en ""}}, + :field-3-flexible-rink? + {:name + {:fi "3. kenttä: onko joustokaukalo?", + :se "Fält 3: finns det flexibel rink?", + :en "Field 3: is there a flexible rink?"}, + :data-type "boolean", + :description {:fi "", :se "", :en ""}}, + :exercise-machines-count + {:name + {:fi "Kuntoilulaitteet lkm", + :se "Antalet gym apparater", + :en "Number of exercise machines"}, + :data-type "numeric", + :description + {:fi "Kuntoilulaitteiden lukumäärä", + :se "Antalet gym apparater", + :en ""}}, + :track-type + {:name {:fi "Ratatyyppi", :se "Typ av bana", :en "Type of track"}, + :data-type "string", + :description {:fi "Radan tyyppi", :se "Banans typ", :en ""}}, + :training-spot-surface-material + {:name + {:fi "Suorituspaikan pintamateriaali", + :se "Prestationsplatsens ytmaterial", + :en "Surface material for training spot"}, + :data-type "string", + :description + {:fi "Esim. keihäänheittopaikan pintamateriaali/päällys", + :se "T.ex. spjutkastningsplatsens ytmaterial/överläggning", + :en ""}}, + :range? + {:name + {:fi "Harjoitusalue/range", :se "Övningszon/Range", :en "Range"}, + :data-type "boolean", + :description + {:fi "Onko golfin harjoitusalue/range", + :se "Finns det övningsområde/range för golf", + :en ""}}, + :track-length-m + {:name + {:fi "Radan pituus m", + :se "Banans längd i m", + :en "Length of track m"}, + :data-type "numeric", + :description + {:fi "Juoksuradan, pyöräilyradan tms. pituus metreinä", + :se "Löpbanans, rundbanans el.dyl. längd i meter", + :en ""}}}) (def used (let [used (set (mapcat (comp keys :props second) types/all))] diff --git a/webapp/src/cljc/lipas/data/prop_types_new.cljc b/webapp/src/cljc/lipas/data/prop_types_new.cljc index cd6cc88c2..253d2599c 100644 --- a/webapp/src/cljc/lipas/data/prop_types_new.cljc +++ b/webapp/src/cljc/lipas/data/prop_types_new.cljc @@ -163,6 +163,12 @@ :se "Länk till tillgänglighetsinformation" :en "Link to accessibility information"}) + ;; Update :accessibility-info description + (assoc-in [:accessibility-info :description] + {:fi "Syötä linkki verkkosivulle, jossa on kuvattu kohteen esteettömyyteen liittyvät tiedot" + :se "Ange länken till webbplatsen där information om objektets tillgänglighet beskrivs." + :en "Enter the link to the website where the accessibility information of the location is described."}) + ;; Update Halfpipe name (assoc-in [:halfpipe-count :name] {:fi "Halfpipe lkm" @@ -615,3 +621,9 @@ (def used (let [used (set (mapcat (comp keys :props second) types/all))] (select-keys all used))) + +(comment + (require '[clojure.pprint :as pprint]) + #?(:clj (spit "/tmp/prop-types.edn" (with-out-str (pprint/pprint all)))) + + ) diff --git a/webapp/src/cljc/lipas/data/types.cljc b/webapp/src/cljc/lipas/data/types.cljc index 806ca2098..96c20c40c 100644 --- a/webapp/src/cljc/lipas/data/types.cljc +++ b/webapp/src/cljc/lipas/data/types.cljc @@ -1,24 +1,4630 @@ (ns lipas.data.types - "Type codes went through a major overhaul in the summer of 2024. This - namespace hosts a controlled place to roll-out the changes." + "Categorization of sports sites." (:require - [lipas.data.types-old :as old] - [lipas.data.types-new :as new] [lipas.utils :as utils])) (def main-categories - new/main-categories) + {0 + {:type-code 0, + :name + {:fi "Virkistyskohteet ja palvelut", + :se "Rekreationsanläggningar och tjänster", + :en "Recreational destinations and services"}, + :ptv + {:ontology-urls + ["http://www.yso.fi/onto/koko/p10416" + "http://www.yso.fi/onto/koko/p37350"], + :service-classes + ["http://uri.suomi.fi/codelist/ptv/ptvserclass2/code/P27.2"]}}, + 1000 + {:type-code 1000, + :name + {:fi "Ulkokentät ja liikuntapuistot", + :se "Utomhusplaner och idrottsparker", + :en "Outdoor fields and sports parks"}, + :ptv + {:ontology-urls + ["http://www.yso.fi/onto/koko/p10416" + "http://www.yso.fi/onto/koko/p69291" + "http://www.yso.fi/onto/koko/p67276"], + :service-classes + ["http://uri.suomi.fi/codelist/ptv/ptvserclass2/code/P27.2"]}}, + 2000 + {:type-code 2000, + :name + {:fi "Sisäliikuntatilat", + :se "Anläggningar för inomhusidrott", + :en "Indoor sports facilities"}, + :ptv + {:ontology-urls + ["http://www.yso.fi/onto/koko/p10416" + "http://www.yso.fi/onto/koko/p69660"], + :service-classes + ["http://uri.suomi.fi/codelist/ptv/ptvserclass2/code/P27.1"]}}, + 3000 + {:type-code 3000, + :name + {:fi "Vesiliikuntapaikat", + :se "Anläggningar för vattenidrott", + :en "Water sports facilities"}, + :ptv + {:ontology-urls + ["http://www.yso.fi/onto/koko/p10416" + "http://www.yso.fi/onto/koko/p18621"], + :service-classes + ["http://uri.suomi.fi/codelist/ptv/ptvserclass2/code/P27.1" + "http://uri.suomi.fi/codelist/ptv/ptvserclass2/code/P27.2"]}}, + 4000 + {:type-code 4000, + :name + {:fi "Maastoliikuntapaikat", + :se "Anläggningar för terrängidrott", + :en "Cross-country sports facilities"}, + :ptv + {:ontology-urls + ["http://www.yso.fi/onto/koko/p10416" + "http://www.yso.fi/onto/koko/p12424"], + :service-classes + ["http://uri.suomi.fi/codelist/ptv/ptvserclass2/code/P27.2"]}}, + 5000 + {:type-code 5000, + :name + {:fi "Veneily, ilmailu ja moottoriurheilu", + :se "Anläggningar för båtsport, flygsport och motorsport", + :en "Boating, aviation and motor sports"}, + :ptv + {:ontology-urls + ["http://www.yso.fi/onto/koko/p34055" + "http://www.yso.fi/onto/koko/p36083" + "http://www.yso.fi/onto/koko/p18298" + "http://www.yso.fi/onto/koko/p75772" + "http://www.yso.fi/onto/koko/p31773"], + :service-classes + ["http://uri.suomi.fi/codelist/ptv/ptvserclass2/code/P27.2"]}}, + 6000 + {:type-code 6000, + :name + {:fi "Eläinurheilualueet", + :se "Anläggningar för djursport", + :en "Animal sports areas"}, + :ptv + {:ontology-urls + ["http://www.yso.fi/onto/koko/p10416" + "http://www.yso.fi/onto/koko/p8973"], + :service-classes + ["http://uri.suomi.fi/codelist/ptv/ptvserclass2/code/P27.1"]}}, + 7000 + {:type-code 7000, + :name + {:fi "Huoltorakennukset", + :se "Servicebyggnader", + :en "Maintenance/service buildings"}, + :ptv {:ontology-urls [], :service-classes []}}}) (def sub-categories - new/sub-categories) + {2100 + {:type-code 2100, + :name + {:fi "Kuntoilukeskukset ja liikuntasalit", + :se "Konditionsidrottscentra och idrottssalar", + :en "Fitness centres and sports halls"}, + :ptv + {:ontology-urls + ["http://www.yso.fi/onto/koko/p30560" + "http://www.yso.fi/onto/koko/p85878"]}, + :main-category "2000"}, + 5200 + {:type-code 5200, + :name + {:fi "Urheiluilmailualueet", + :se "Områden för flygsport", + :en "Sport aviation areas"}, + :main-category "5000"}, + 4200 + {:type-code 4200, + :name + {:fi "Katetut talviurheilupaikat", + :se "Vintersportplatser under tak", + :en "Covered winter sports facilities"}, + :ptv {:ontology-urls ["http://www.yso.fi/onto/koko/p8460"]}, + :main-category "4000"}, + 2200 + {:type-code 2200, + :name + {:fi "Liikuntahallit", :se "Idrottshallar", :en "Sports halls"}, + :ptv {:ontology-urls ["http://www.yso.fi/onto/koko/p33522"]}, + :main-category "2000"}, + 1 + {:type-code 1, + :name + {:fi "Virkistys- ja retkeilyalueet", + :se "Rekreations- och friluftsområden", + :en "Recreational and outdoor areas "}, + :ptv + {:ontology-urls + ["http://www.yso.fi/onto/koko/p37350" + "http://www.yso.fi/onto/koko/p33303"]}, + :main-category "0"}, + 7000 + {:type-code 7000, + :name + {:fi "Huoltotilat", + :se "Servicebyggnader", + :en "Maintenance/service buildings"}, + :main-category "7000"}, + 4400 + {:type-code 4400, + :name + {:fi "Liikunta- ja ulkoilureitit", + :se "Idrotts- och friluftsleder", + :en "Sports and outdoor recreation routes "}, + :ptv {:ontology-urls ["http://www.yso.fi/onto/koko/p32315"]}, + :main-category "4000"}, + 1300 + {:type-code 1300, + :name {:fi "Pallokentät", :se "Bollplaner", :en "Ball games courts"}, + :ptv {:ontology-urls ["http://www.yso.fi/onto/koko/p75504"]}, + :main-category "1000"}, + 6100 + {:type-code 6100, + :name {:fi "Hevosurheilu", :se "Hästsport", :en "Equestrian sports"}, + :ptv {:ontology-urls ["http://www.yso.fi/onto/koko/p35523"]}, + :main-category "6000"}, + 4700 + {:type-code 4700, + :name + {:fi "Kiipeilypaikat", + :se "Klättringsplatser", + :en "Climbing venues"}, + :ptv {:ontology-urls ["http://www.yso.fi/onto/koko/p4261"]}, + :main-category "4000"}, + 3100 + {:type-code 3100, + :name + {:fi "Uima-altaat, hallit ja kylpylät", + :se "Simbassänger, hallar och badinrättningar", + :en "Indoor swimming pools, halls and spas"}, + :ptv + {:ontology-urls + ["http://www.yso.fi/onto/koko/p1459" + "http://www.yso.fi/onto/koko/p11070" + "http://www.yso.fi/onto/koko/p35112"]}, + :main-category "3000"}, + 2500 + {:type-code 2500, + :name {:fi "Jäähallit", :se "Ishallar", :en "Ice-skating arenas"}, + :ptv {:ontology-urls ["http://www.yso.fi/onto/koko/p11376"]}, + :main-category "2000"}, + 1200 + {:type-code 1200, + :name + {:fi "Yleisurheilukentät ja -paikat", + :se "Planer och platser för friidrott", + :en "Athletics fields and venues"}, + :ptv {:ontology-urls ["http://www.yso.fi/onto/koko/p85607"]}, + :main-category "1000"}, + 5300 + {:type-code 5300, + :name + {:fi "Moottoriurheilualueet", + :se "Områden för motorsport", + :en "Motor sports areas"}, + :ptv {:ontology-urls ["http://www.yso.fi/onto/koko/p31773"]}, + :main-category "5000"}, + 1600 + {:type-code 1600, + :name {:fi "Golfkentät", :se "Golfbanor", :en "Golf courses"}, + :ptv {:ontology-urls ["http://www.yso.fi/onto/koko/p32648"]}, + :main-category "1000"}, + 1500 + {:type-code 1500, + :name + {:fi "Jääurheilualueet ja luonnonjäät", + :se "Isidrottsområden och naturisar", + :en "Ice sports areas and sites with natural ice"}, + :ptv {:ontology-urls ["http://www.yso.fi/onto/koko/p75572"]}, + :main-category "1000"}, + 6200 + {:type-code 6200, + :name {:fi "Koiraurheilu", :se "Hundsport", :en "Dog sports"}, + :ptv {:ontology-urls ["http://www.yso.fi/onto/koko/p72589"]}, + :main-category "6000"}, + 3200 + {:type-code 3200, + :name + {:fi "Maauimalat ja uimarannat", + :se "Utebassänger och badstränder", + :en "Open air pools and beaches"}, + :ptv + {:ontology-urls + ["http://www.yso.fi/onto/koko/p32279" + "http://www.yso.fi/onto/koko/p76123" + "http://www.yso.fi/onto/koko/p13459"]}, + :main-category "3000"}, + 2 + {:type-code 2, + :name + {:fi "Retkeilyn palvelut", + :se "Utflyktstjänster", + :en "Hiking facilities"}, + :ptv {:ontology-urls ["http://www.yso.fi/onto/koko/p36881"]}, + :main-category "0"}, + 1100 + {:type-code 1100, + :name + {:fi "Lähiliikunta ja liikuntapuistot", + :se "Närmotion och idrottsparker", + :en "Neighbourhood sports facilities and parks "}, + :ptv + {:ontology-urls + ["http://www.yso.fi/onto/koko/p84486" + "http://www.yso.fi/onto/koko/p69291"]}, + :main-category "1000"}, + 4100 + {:type-code 4100, + :name + {:fi "Laskettelurinteet ja rinnehiihtokeskukset", + :se "Slalombackar och alpina skidcentra", + :en "Ski slopes and downhill ski resorts"}, + :ptv + {:ontology-urls + ["http://www.yso.fi/onto/koko/p10549" + "http://www.yso.fi/onto/koko/p84378" + "http://www.yso.fi/onto/koko/p4432"]}, + :main-category "4000"}, + 5100 + {:type-code 5100, + :name + {:fi "Veneurheilupaikat", + :se "Platser för båtsport", + :en "Boating sports facilities"}, + :ptv {:ontology-urls ["http://www.yso.fi/onto/koko/p75772"]}, + :main-category "5000"}, + 2600 + {:type-code 2600, + :name + {:fi "Keilahallit ja biljardisalit", + :se "Bowlinghallar och biljardsalonger", + :en "Bowling alleys and billiard halls"}, + :ptv {:ontology-urls ["http://www.yso.fi/onto/koko/p9812"]}, + :main-category "2000"}, + 2300 + {:type-code 2300, + :name + {:fi "Yksittäiset lajikohtaiset sisäliikuntapaikat", + :se "Enstaka grenspecifika anläggningar för inomhusidrott", + :en "Indoor venues for various sports "}, + :ptv {:ontology-urls ["http://www.yso.fi/onto/koko/p66287"]}, + :main-category "2000"}, + 4300 + {:type-code 4300, + :name {:fi "Hyppyrimäet", :se "Hoppbackar", :en "Ski jumping hills"}, + :ptv {:ontology-urls ["http://www.yso.fi/onto/koko/p72457"]}, + :main-category "4000"}, + 4500 + {:type-code 4500, + :name + {:fi "Suunnistusalueet", + :se "Orienteringsområden", + :en "Orienteering areas"}, + :ptv {:ontology-urls ["http://www.yso.fi/onto/koko/p5355"]}, + :main-category "4000"}, + :ptv {:ontology-urls ["http://www.yso.fi/onto/koko/p18298"]}, + 4600 + {:type-code 4600, + :name + {:fi "Maastohiihtokeskukset", + :se "Längdåkningscentra", + :en "Cross-country ski resorts"}, + :ptv {:ontology-urls ["http://www.yso.fi/onto/koko/p75831"]}, + :main-category "4000"}, + 4800 + {:type-code 4800, + :name + {:fi "Ampumaurheilupaikat", + :se "Sportskytteplatser", + :en "Shooting sports facilities"}, + :ptv {:ontology-urls ["http://www.yso.fi/onto/koko/p25336"]}, + :main-category "4000"}}) -(def all new/all) +(def all + {1530 + {:description + {:fi + "Luisteluun, jääkiekkoon, kaukalopalloon, curlingiin tai muuhun jääurheiluun tarkoitettu kaukalo. Käytössä talvikaudella.", + :se + "Rink avsedd för skridskoåkning, ishockey, rinkbandy osv. Används under vintersäsongen.", + :en "Rink intended for ice-skating, ice hockey, rink bandy, etc."}, + :tags {:fi ["jääkiekkokaukalo"]}, + :name {:fi "Kaukalo", :se "Rink", :en "Rink"}, + :type-code 1530, + :main-category 1000, + :status "active", + :sub-category 1500, + :geometry-type "Point", + :props + {:surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :stand-capacity-person {:priority 0}, + :free-use? {:priority 0}, + :field-length-m {:priority 1}, + :match-clock? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :ice-rinks-count {:priority 0}, + :toilet? {:priority 0}, + :changing-rooms? {:priority 0}, + :area-m2 {:priority 1}, + :field-width-m {:priority 1}, + :lighting-info {:priority 0}, + :changing-rooms-m2 {:priority 0}, + :ligthing? {:priority 1}, + :school-use? {:priority 0}, + :light-roof? {:priority 0}}}, + 1520 + {:description + {:fi + "Luisteluun tarkoitettu luonnonmukainen kenttä. Jäädytetään käyttökuntoon talvikaudelle.", + :se "Plan avsedd för skridskoåkning. Används under vintersäsongen.", + :en "Field intended for ice-skating."}, + :tags {:fi []}, + :name + {:fi "Luistelukenttä", :se "Skridskobana", :en "Ice-skating field"}, + :type-code 1520, + :main-category 1000, + :status "active", + :sub-category 1500, + :geometry-type "Point", + :props + {:surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :stand-capacity-person {:priority 0}, + :free-use? {:priority 0}, + :field-length-m {:priority 1}, + :match-clock? {:priority 0}, + :fields-count {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :changing-rooms? {:priority 0}, + :area-m2 {:priority 1}, + :field-width-m {:priority 1}, + :lighting-info {:priority 0}, + :changing-rooms-m2 {:priority 0}, + :customer-service-point? {:priority 0}, + :ligthing? {:priority 1}, + :school-use? {:priority 0}, + :light-roof? {:priority 0}}}, + 2320 + {:description + {:fi + "Pysyvästi voimisteluun varustettu tila. Voimistelutilassa on erilaisia kiinteitä voimistelutelineitä ja -rakenteita (esim. volttimonttu, rekki tai trampoliini). Myös cheerleadingin ja sirkusharjoittelun olosuhteet luetaan voimistelutiloiksi. Tarkempi olosuhdetieto kerrotaan lisätiedoissa.", + :se "Permanent utrustning för att träna redskapsgymnastik.", + :en "Space permanently equipped for artistic gymnastics."}, + :tags {:fi ["monttu" "rekki" "nojapuut"]}, + :name + {:fi "Voimistelutila", + :se "Utrymme för redskapsgymnastik", + :en "Artistic gymnastics facility"}, + :type-code 2320, + :main-category 2000, + :status "active", + :sub-category 2300, + :geometry-type "Point", + :props + {:height-m {:priority 0}, + :surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :free-use? {:priority 0}, + :sport-specification {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :space-divisible {:priority 0}, + :gymnastic-routines-count {:priority 0}, + :area-m2 {:priority 1}, + :landing-places-count {:priority 0}, + :school-use? {:priority 0}}}, + 6130 + {:description + {:fi + "Pysyvästi esteratsastukseen varusteltu kenttä tai alue ulkona.", + :se "Bana med permanent utrustning för banhoppning", + :en "Field permanently equipped for show jumping. Outdoors."}, + :tags {:fi ["ratsastuskenttä"]}, + :name + {:fi "Esteratsastuskenttä/-alue", + :se "Bana för banhoppning", + :en "Show jumping field"}, + :type-code 6130, + :main-category 6000, + :status "active", + :sub-category 6100, + :geometry-type "Point", + :props + {:surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :free-use? {:priority 0}, + :field-length-m {:priority 1}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :area-m2 {:priority 1}, + :field-width-m {:priority 1}, + :lighting-info {:priority 0}, + :ligthing? {:priority 1}, + :school-use? {:priority 0}}}, + 1395 + {:description + {:fi + "Yksi tai useampi pöytätennispöytä ulkona. Pöytätennispöydän tulee olla sijoitettu niin, että pelaamiseen on riittävä tila pöydän ympärillä. Pöydän tulee olla pelikäyttöön soveltuva.", + :se + "Ett eller flera bordtennisbord utomhus. Bordet är lämpligt för spel och bör vara placerat så att det finns tillräckligt utrymme för spel.", + :en + "One or more outdoor table tennis tables in the same area. The table must be positioned so that there is enough space for playing. The table must be suitable for the sport."}, + :tags {:fi ["pöytätennis" "pingis" "ping pong"]}, + :name + {:fi "Pöytätennisalue", + :se "Område med bordtennisbord", + :en "Table tennis area"}, + :type-code 1395, + :main-category 1000, + :status "active", + :sub-category 1300, + :geometry-type "Point", + :props + {:free-use? {:priority 0}, + :table-tennis-count {:priority 1}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :ligthing? {:priority 1}, + :school-use? {:priority 0}, + :water-point {:priority 0}, + :lighting-info {:priority 0}}}, + 6210 + {:description + {:fi + "Koiran koulutukseen, agilityyn tai muuhun harjoittamiseen varattu ulkoalue.", + :se + "Område reserverat för hundträning, agility eller annan hundhobby.", + :en "Area reserved for dog training, agility or other dog sports."}, + :tags {:fi ["agility" "koirakenttä"]}, + :name + {:fi "Koiraurheilualue", + :se "Område för hundsport", + :en "Dog sports area"}, + :type-code 6210, + :main-category 6000, + :status "active", + :sub-category 6200, + :geometry-type "Point", + :props + {:surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :free-use? {:priority 0}, + :field-length-m {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :area-m2 {:priority 1}, + :field-width-m {:priority 0}, + :lighting-info {:priority 0}, + :ligthing? {:priority 1}, + :track-length-m {:priority 0}}}, + 1370 + {:description + {:fi + "Tennikseen tarkoitettu kenttä. Mahdollinen lyöntiseinä ja kentän pintamateriaali merkitään lisätietoihin.", + :se + "En eller flera tennisbanor på samma område. Antalet banor, ytmaterial mm i karakteristika. Även uppgift om slagväggen.", + :en + "One or more tennis courts in the same area. Number of courts, surface material, etc. specified in properties, including information about a potential hit wall."}, + :tags {:fi ["tenniskenttä"]}, + :name + {:fi "Tenniskenttä", + :se "Område med tennisbanor", + :en "Tennis court area"}, + :type-code 1370, + :main-category 1000, + :status "active", + :sub-category 1300, + :geometry-type "Point", + :props + {:surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :stand-capacity-person {:priority 0}, + :free-use? {:priority 0}, + :field-length-m {:priority 1}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :changing-rooms? {:priority 0}, + :area-m2 {:priority 1}, + :field-width-m {:priority 1}, + :lighting-info {:priority 0}, + :training-wall? {:priority 0}, + :water-point {:priority 0}, + :ligthing? {:priority 1}, + :school-use? {:priority 0}, + :light-roof? {:priority 0}}}, + 1360 + {:description + {:fi + "Pesäpalloon tarkoitettu kenttä. Jos kentän yhteydessä on katsomoita, lisätään kentän nimeen stadion-sana. Vähintään kansallisen tason pelipaikka. Pintamateriaali on esim. hiekka, hiekkatekonurmi tai muu synteettinen päällyste. Kentän koko on vähintään 50 x 100 m.", + :se + "En bobollsplan, kan ha flera läktare. Minimikrav: spelplats på nationell nivå. Sand, konstgräs med sand / annan syntetisk beläggning. >50 x 100 m.", + :en + "Finnish baseball field, may include stands. Can host at least national-level games. Sand, artificial turf / other synthetic surface, > 50 x 100 m. "}, + :tags {:fi ["pesäpallostadion"]}, + :name + {:fi "Pesäpallokenttä", :se "Bobollsplan", :en "Baseball field"}, + :type-code 1360, + :main-category 1000, + :status "active", + :sub-category 1300, + :geometry-type "Point", + :props + {:heating? {:priority 0}, + :surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :stand-capacity-person {:priority 0}, + :free-use? {:priority 0}, + :field-length-m {:priority 1}, + :match-clock? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :changing-rooms? {:priority 0}, + :area-m2 {:priority 1}, + :field-width-m {:priority 1}, + :lighting-info {:priority 0}, + :scoreboard? {:priority 0}, + :loudspeakers? {:priority 0}, + :customer-service-point? {:priority 0}, + :water-point {:priority 0}, + :ligthing? {:priority 1}, + :covered-stand-person-count {:priority 0}, + :school-use? {:priority 0}}}, + 110 + {:description + {:fi + "Erämaalailla perustetut alueet pohjoisimmassa Lapissa. Metsähallitus tietolähteenä.", + :se + "Grundade enligt ödemarkslagen, i nordligaste Lappland. Källa: Forststyrelsen.", + :en + "Areas located in northernmost Lapland, established based on the Wildeness Act (1991/62). Source of information Metsähallitus."}, + :tags {:fi []}, + :name + {:fi "Erämaa-alue", :se "Vildmarksområden", :en "Wilderness area"}, + :type-code 110, + :main-category 0, + :status "active", + :sub-category 1, + :geometry-type "Polygon", + :props + {:area-km2 {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, + 2360 + {:description + {:fi "Pysyvästi käytössä oleva ampumarata sisätiloissa.", + :se "Permanent skjutbana inomhus.", + :en "Permanent indoor shooting range."}, + :tags {:fi ["ilmakivääri" "ilma-ase" "ammunta"]}, + :name + {:fi "Sisäampumarata", + :se "Inomhusskjutbana", + :en "Indoor shooting range"}, + :type-code 2360, + :main-category 2000, + :status "active", + :sub-category 2300, + :geometry-type "Point", + :props + {:surface-material {:priority 0}, + :surface-material-info {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :air-gun-shooting? {:priority 0}, + :pistol-shooting? {:priority 0}, + :shooting-positions-count {:priority 1}, + :area-m2 {:priority 1}, + :rifle-shooting? {:priority 0}, + :free-rifle-shooting? {:priority 0}, + :school-use? {:priority 0}, + :track-length-m {:priority 1}}}, + 5310 + {:description + {:fi + "Useiden eri moottoriurheilun lajien suorituspaikkoja, huoltotilat olemassa.", + :se + "Platser för flera olika motorsportgrenar, serviceutrymmen finns.", + :en "Venues for various motor sports; service premises available."}, + :tags {:fi []}, + :name + {:fi "Moottoriurheilukeskus", + :se "Centrum för motorsport", + :en "Motor sports centre"}, + :type-code 5310, + :main-category 5000, + :status "active", + :sub-category 5300, + :geometry-type "Point", + :props + {:surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :automated-timing? {:priority 0}, + :stand-capacity-person {:priority 0}, + :free-use? {:priority 0}, + :finish-line-camera? {:priority 0}, + :track-width-m {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :area-m2 {:priority 0}, + :lighting-info {:priority 0}, + :year-round-use? {:priority 0}, + :scoreboard? {:priority 0}, + :loudspeakers? {:priority 0}, + :ligthing? {:priority 0}, + :covered-stand-person-count {:priority 0}, + :track-length-m {:priority 1}}}, + 1560 + {:description + {:fi + "Alamäkiluistelua varten vuosittain rakennettava rata. Käytössä talvikaudella.", + :se "Permanent bana byggd för utförsåkning.", + :en "Permanent track built for downhill skating. "}, + :tags {:fi ["luistelu" "alamäkiluistelu"]}, + :name + {:fi "Alamäkiluistelurata", + :se "Skridskobana för utförsåkning", + :en "Downhill skating track"}, + :type-code 1560, + :main-category 1000, + :status "active", + :sub-category 1500, + :geometry-type "Point", + :props + {:surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :lifts-count {:priority 0}, + :free-use? {:priority 0}, + :track-width-m {:priority 0}, + :altitude-difference {:priority 1}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :lighting-info {:priority 0}, + :ligthing? {:priority 1}, + :school-use? {:priority 0}, + :track-length-m {:priority 1}}}, + 205 + {:description + {:fi "Rantautumiseen osoitettu paikka, ei järjestettyjä palveluita.", + :se "Plats som anvisats för ilandstigning, inga ordnade tjänster.", + :en "Place intended for landing by boat, no services provided."}, + :tags {:fi ["laituri" "taukopaikka"]}, + :name + {:fi "Rantautumispaikka", + :se "Ilandstigningsplats", + :en "Boat dock"}, + :type-code 205, + :main-category 0, + :status "deprecated", + :sub-category 2, + :geometry-type "Point", + :props + {:toilet? {:priority 0}, + :boat-launching-spot? {:priority 0}, + :may-be-shown-in-excursion-map-fi? {:priority 0}, + :pier? {:priority 0}, + :school-use? {:priority 0}, + :free-use? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, + 2150 + {:description + {:fi + "Muun rakennuksen yhteydessä oleva avoin liikuntatila, joka sopii monipuolisesti erilaisten liikuntamuotojen harrastamiseen. Salin liikuntapinta-ala vaihtelee tyypillisesti alle 300 neliöstä noin 750 neliöön. Esim. koulurakennuksessa sijaitseva liikuntasali.", + :se + "En idrottssal som är ansluten till en annan byggnad. Storlek och höjd anges i karakteristika.", + :en + "A gymnastics hall connected to another building. Size and height specified in properties."}, + :tags {:fi ["jumppasali" "voimistelusali"]}, + :name {:fi "Liikuntasali", :se "Idrottssal", :en "Gymnastics hall"}, + :type-code 2150, + :main-category 2000, + :status "active", + :sub-category 2100, + :geometry-type "Point", + :props + {:height-m {:priority 1}, + :surface-material {:priority 1}, + :basketball-fields-count {:priority 0}, + :surface-material-info {:priority 0}, + :free-use? {:priority 0}, + :tennis-courts-count {:priority 0}, + :field-length-m {:priority 1}, + :match-clock? {:priority 0}, + :badminton-courts-count {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :space-divisible {:priority 0}, + :gymnastics-space? {:priority 0}, + :area-m2 {:priority 1}, + :field-width-m {:priority 1}, + :futsal-fields-count {:priority 0}, + :football-fields-count {:priority 0}, + :floorball-fields-count {:priority 0}, + :handball-fields-count {:priority 0}, + :volleyball-fields-count {:priority 0}, + :spinning-hall? {:priority 0}, + :school-use? {:priority 0}}}, + 2210 + {:description + {:fi + "Liikuntahalli on itsenäinen rakennus, jossa voi olla useita liikuntatiloja tai osiin jaettavissa oleva pääsali.", + :se + "Idrottshall med utrymmen för flera idrottsgrenar eller med ett i mindre sektioner indelbart huvudidrottsutrymme. Storleken varierar mellan ca 750 och 4999 m2. Inkluderar inomhusaktivitetsparker med faciliteter för flera fysiska aktiviteter.", + :en + "Building containing facilities for various sports or the main sports area can be split into smaller sections. Hall size varies between app. 750 - 4999 square meters. Includes indoor activity parks with facilities for multiple physical activities."}, + :tags {:fi ["urheilutalo" "urheiluhalli"]}, + :name {:fi "Liikuntahalli", :se "Idrottshall", :en "Sports hall "}, + :type-code 2210, + :main-category 2000, + :status "active", + :sub-category 2200, + :geometry-type "Point", + :props + {:height-m {:priority 1}, + :surface-material {:priority 1}, + :basketball-fields-count {:priority 0}, + :surface-material-info {:priority 0}, + :stand-capacity-person {:priority 0}, + :free-use? {:priority 0}, + :sprint-lanes-count {:priority 0}, + :javelin-throw-places-count {:priority 0}, + :tennis-courts-count {:priority 0}, + :field-length-m {:priority 1}, + :circular-lanes-count {:priority 0}, + :match-clock? {:priority 0}, + :inner-lane-length-m {:priority 0}, + :discus-throw-places {:priority 0}, + :badminton-courts-count {:priority 0}, + :hammer-throw-places-count {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :padel-courts-count {:priority 0}, + :polevault-places-count {:priority 0}, + :group-exercise-rooms-count {:priority 0}, + :space-divisible {:priority 0}, + :toilet? {:priority 0}, + :gymnastics-space? {:priority 0}, + :running-track-surface-material {:priority 0}, + :area-m2 {:priority 1}, + :field-width-m {:priority 1}, + :scoreboard? {:priority 0}, + :futsal-fields-count {:priority 0}, + :shotput-count {:priority 0}, + :longjump-places-count {:priority 0}, + :football-fields-count {:priority 0}, + :floorball-fields-count {:priority 0}, + :auxiliary-training-area? {:priority 0}, + :squash-courts-count {:priority 0}, + :customer-service-point? {:priority 0}, + :accessibility-info {:priority 0}, + :handball-fields-count {:priority 0}, + :volleyball-fields-count {:priority 0}, + :climbing-wall? {:priority 0}, + :school-use? {:priority 0}, + :highjump-places-count {:priority 0}}}, + 101 + {:description + {:fi + "Sijaitsevat taajamissa, max 1 km asutuksesta. Toimivat kävely-, leikki-, oleskelu-, lenkkeily- ja pyöräilypaikkoina. Kaavamerkintä V tai VL. Esimerkkejä lähi- tai ulkoilupuistoista: leikkipuistot, liikennepuistot, perhepuistot, oleskelupuistot, keskuspuistot ja kirkkopuistot.", + :se + "I tätorter, i omedelbar närhet till bebyggelse. Avsedd för daglig användning. Plats för lek, vistelse och promenader. Planbeteckning VL. Till exempel en lekpark.", + :en + "In population centres, in or near residential areas. Intended for daily use. Used for play, recreation and walks. Plan symbol VL. E.g. a playground."}, + :tags {:fi ["puisto" "lähiliikuntapaikka"]}, + :name + {:fi "Lähi-/ulkoilupuisto", :se "Närpark", :en "Neighbourhood park"}, + :type-code 101, + :main-category 0, + :status "active", + :sub-category 1, + :geometry-type "Polygon", + :props + {:playground? {:priority 0}, + :area-km2 {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :water-point {:priority 0}, + :toilet? {:priority 0}}}, + 102 + {:description + {:fi + "Päivittäin käytettäviä alueita, max 1 km asunnoista. Toimivat kävely-, leikki-, oleskelu-, lenkkeily- ja pyöräilypaikkoina. Kevyt liikenne voi mennä ulkoilupuiston läpi. Voi sisältää puistoa, metsää, peltoa, niittyä, vesialuetta. Kaavamerkintä V tai VL.", + :se + "Områden avsedda för daglig använding, max på 1 kilometers avstånd från bebyggelse. Fungerar som ett område för promenader, lekar, vistelse, joggning och cykling. Lätt trafikled kan fara igenom friluftsparken. Området kan bestå av park, skog, åker, äng och vattenled. Planbeteckning V eller VL.", + :en + "Used daily, max. 1 km from residential areas. Intended for walks, play, recreation, jogging and cycling. There may be bicycle and pedestrian traffic across the park. May consist of park, forest, fields, meadows, bodies of water. Symbol V or VL."}, + :tags {:fi ["puisto"]}, + :name {:fi "Ulkoilupuisto", :se "Friluftspark", :en "Leisure park"}, + :type-code 102, + :main-category 0, + :status "deprecated", + :sub-category 1, + :geometry-type "Polygon", + :props + {:playground? {:priority 0}, + :area-km2 {:priority 0}, + :may-be-shown-in-excursion-map-fi? {:priority 0}, + :school-use? {:priority 0}, + :free-use? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, + 7000 + {:description + {:fi + "Liikuntapaikan tai -paikkojen yhteydessä oleva, liikuntapaikan ylläpitoa tai käyttöä palveleva rakennus. Voi sisältää varastoja, pukuhuoneita, suihkutiloja yms.", + :se "Servicebyggnader i anslutning till idrottsanläggningar.", + :en "Maintenance buildings in connection with sports facilities."}, + :tags {:fi ["konesuoja" "huoltotila"]}, + :name + {:fi "Huoltorakennukset", + :se "Servicebyggnader", + :en "Maintenance/service buildings"}, + :type-code 7000, + :main-category 7000, + :status "active", + :sub-category 7000, + :geometry-type "Point", + :props + {:free-use? {:priority 0}, + :ski-service? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :shower? {:priority 0}, + :changing-rooms? {:priority 0}, + :area-m2 {:priority 0}, + :equipment-rental? {:priority 0}, + :sauna? {:priority 0}, + :school-use? {:priority 0}}}, + 1110 + {:description + {:fi + "Liikuntapuisto on useita liikuntapaikkoja käsittävä liikunta-alue. Liikuntapuistossa voi olla esim. erilaisia kenttiä, uimaranta, kuntorata, monitoimihalli, leikkipuisto jne. koottuna samalle alueelle. Lipakseen tallennetaan sekä tieto liikuntapuistosta että yksittäiset liikuntapaikat, joita puisto sisältää. Liikuntapaikat lasketaan omiksi paikoikseen.", + :se + "En idrottspark är ett idrottsområde med flera idrottsplatser. Där kan finnas olika planer, badstrand, konditionsbana, allaktivitetshall, lekpark osv samlade på samma område. I Lipas lagras uppgifter om såväl idrottsparken som enstaka faciliteter som finns i parken. Varje motionsplats räknas som en plats.", + :en + "A sports park is an area including several sports facilities, e.g., different fields, beach, a jogging track, a multi-purpose hall, a playground. 'Lipas' contains information both on the sports park and the individual sports facilities found there. The sports facilities are listed as individual items in the classification."}, + :tags {:fi ["puisto" "lähiliikunta" "lähiliikuntapaikka"]}, + :name {:fi "Liikuntapuisto", :se "Idrottspark", :en "Sports park"}, + :type-code 1110, + :main-category 1000, + :status "active", + :sub-category 1100, + :geometry-type "Polygon", + :props + {:free-use? {:priority 0}, + :fields-count {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :area-m2 {:priority 1}, + :lighting-info {:priority 0}, + :ligthing? {:priority 1}, + :accessibility-info {:priority 0}, + :playground? {:priority 0}, + :school-use? {:priority 0}}}, + 3250 + {:description + {:fi + "Vesiurheilukeskuksessa on vesistössä sijaitsevia liikuntapalveluita tai palvelukokonaisuus, joka voi muodostua erilaisista veden päällä tai vedessä olevista suorituspaikoista tai -radoista."}, + :tags {:fi []}, + :name {:fi "Vesiurheilukeskus"}, + :type-code 3250, + :main-category 3000, + :status "active", + :sub-category 3200, + :geometry-type "Point", + :props + {:free-use? {:priority 0}, + :pier? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :shower? {:priority 0}, + :changing-rooms? {:priority 0}, + :pool-water-area-m2 {:priority 0}, + :sauna? {:priority 0}, + :customer-service-point? {:priority 0}}}, + 6220 + {:description + {:fi + "Erityisesti koiraharrastusta, agilityä, koulutusta tms. varten varustettu halli.", + :se + "Hall som utrustats särskilt för hundhobby, agility, träning osv.", + :en + "Hall specifically equipped for dog sports, agility, training, etc."}, + :tags {:fi ["agility" "koirahalli"]}, + :name + {:fi "Koiraurheiluhalli", + :se "Hundsporthall", + :en "Dog sports hall"}, + :type-code 6220, + :main-category 6000, + :status "active", + :sub-category 6200, + :geometry-type "Point", + :props + {:heating? {:priority 0}, + :surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :free-use? {:priority 0}, + :field-length-m {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :area-m2 {:priority 1}, + :field-width-m {:priority 0}, + :lighting-info {:priority 0}, + :ligthing? {:priority 0}}}, + 4530 + {:description + {:fi + "Pyöräillen tapahtuvaan suunnistamiseen, alueesta on pyöräsuunnistukseen soveltuva kartta.", + :se "Karta över område som lämpar sig för cykelorientering.", + :en "A map for mountain bike orienteering available."}, + :tags {:fi []}, + :name + {:fi "Pyöräsuunnistusalue", + :se "Cykelorienteringsområde", + :en " Mountain bike orienteering area"}, + :type-code 4530, + :main-category 4000, + :status "deprecated", + :sub-category 4500, + :geometry-type "Polygon", + :props + {:area-km2 {:priority 0}, + :school-use? {:priority 0}, + :free-use? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, + 4720 + {:description + {:fi + "Merkitty luonnon kallio, jota voi käyttää kiipeilyyn. Jääkiipeily lisätietoihin. Myös boulderointikalliot.", + :se + "Märkt berg i naturen. Isklättring i tilläggsinformation. Även berg för bouldering.", + :en + "Marked natural cliff. Ice climbing specified in additional information. Also includes bouldering cliffs."}, + :tags {:fi []}, + :name {:fi "Kiipeilykallio", :se "Klätterberg", :en "Climbing rock"}, + :type-code 4720, + :main-category 4000, + :status "active", + :sub-category 4700, + :geometry-type "Point", + :props + {:surface-material {:priority 0}, + :surface-material-info {:priority 0}, + :free-use? {:priority 0}, + :may-be-shown-in-excursion-map-fi? {:priority 0}, + :climbing-routes-count {:priority 0}, + :ice-climbing? {:priority 0}, + :climbing-wall-height-m {:priority 1}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :area-m2 {:priority 1}, + :lighting-info {:priority 0}, + :climbing-wall-width-m {:priority 1}, + :ligthing? {:priority 0}}}, + 1330 + {:description + {:fi + "Rantalentopallokenttä, pehmeä alusta. Kohde voi sijaita muuallakin kuin rannalla.", + :se + "Beachvolleybollplan, mjuk grund. Kan också ha annat läge än stranden.", + :en + "Beach volleyball court, soft basement. May also be located far from a beach."}, + :tags {:fi ["rantalentopallo" "rantalentopallokenttä"]}, + :name + {:fi "Beachvolley-/rantalentopallokenttä", + :se "Beachvolleyplan", + :en "Beach volleyball court"}, + :type-code 1330, + :main-category 1000, + :status "active", + :sub-category 1300, + :geometry-type "Point", + :props + {:surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :height-of-basket-or-net-adjustable? {:priority 0}, + :free-use? {:priority 0}, + :field-length-m {:priority 1}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :area-m2 {:priority 1}, + :field-width-m {:priority 1}, + :lighting-info {:priority 0}, + :water-point {:priority 0}, + :ligthing? {:priority 1}, + :school-use? {:priority 0}}}, + 206 + {:description + {:fi + "Rakennettu tulentekopaikka tai keittokatos. Kohde voi olla esimerkiksi maasta eristetty katoksellinen tulisija tai tulisija avotulelle. Tulentekopaikan tarkempi kuvaus ja tieto mahdollisista rajoituksista lisätietoihin.", + :se "En byggd eldningsplats eller ett kokskjul. Objektet kan till exempel vara en eldstad med tak som är isolerad från marken eller en eldstad för öppen eld. En mer detaljerad beskrivning av eldningsplatsen och information om eventuella begränsningar finns i ytterligare information.", + :en "A constructed fireplace or cooking shelter. The site can be, for example, a covered fireplace isolated from the ground or a fireplace for open fires. A more detailed description of the fireplace and information about any possible restrictions can be found in the additional information."}, + :tags + {:fi + ["nuotiopaikka" + "keittokatos" + "grillauspaikka" + "ruoka" + "taukopaikka"]}, + :name + {:fi "Ruoanlaitto- / tulentekopaikka", + :se "Matlagningsplats", + :en "Cooking facilities"}, + :type-code 206, + :main-category 0, + :status "active", + :sub-category 2, + :geometry-type "Point", + :props + {:may-be-shown-in-excursion-map-fi? {:priority 0}, + :toilet? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :free-use? {:priority 0}}}, + 4830 + {:description + {:fi + "Ulkona tai sisällä sijaitseva jousiammuntarata. Radan käyttö edellyttää erillistä lupaa, seuran jäsenyyttä tai harjoitusvuoroa. Radan varustus ja soveltuvat lajit kuvataan lisätiedoissa.", + :se "Ute eller inne. Utrustning och grenar i karakteristika.", + :en + "Outdoors or indoors. Equipment and the various sports detailed in properties."}, + :tags {:fi ["jousiampumarata"]}, + :name + {:fi "Jousiammuntarata", :se "Bågskyttebana", :en "Archery range"}, + :type-code 4830, + :main-category 4000, + :status "active", + :sub-category 4800, + :geometry-type "Point", + :props + {:free-use? {:priority 0}, + :track-width-m {:priority 0}, + :free-customer-use? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :shooting-positions-count {:priority 1}, + :area-m2 {:priority 0}, + :lighting-info {:priority 0}, + :ligthing? {:priority 1}, + :track-length-m {:priority 1}}}, + 1180 + {:description + {:fi "Frisbeegolfin pelaamiseen rakennettu rata.", + :se "En bana byggt för frisbeegolf.", + :en "Track built for disc golf. "}, + :tags {:fi []}, + :name + {:fi "Frisbeegolfrata", + :se "Frisbeegolfbana", + :en "Disc golf course"}, + :type-code 1180, + :main-category 1000, + :status "active", + :sub-category 1100, + :geometry-type "Point", + :props + {:surface-material {:priority 0}, + :surface-material-info {:priority 0}, + :holes-count {:priority 1}, + :free-use? {:priority 0}, + :may-be-shown-in-excursion-map-fi? {:priority 0}, + :altitude-difference {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :lighting-info {:priority 0}, + :ligthing? {:priority 0}, + :accessibility-info {:priority 0}, + :school-use? {:priority 0}, + :track-type {:priority 0}, + :range? {:priority 0}, + :track-length-m {:priority 0}}}, + 4422 + {:description + {:fi + "Moottorikelkkailuun tarkoitettu reitti, jolla ei ole tehty virallista reittitoimitusta. Reitillä on kuitenkin ylläpitäjä ja maanomistajien lupa.", + :se "Ingen ruttexpedition.", + :en "No official approval."}, + :tags {:fi []}, + :name + {:fi "Moottorikelkkaura", + :se "Snöskoterspår", + :en "Unofficial snowmobile route"}, + :type-code 4422, + :main-category 4000, + :status "active", + :sub-category 4400, + :geometry-type "LineString", + :props + {:may-be-shown-in-excursion-map-fi? {:priority 0}, + :route-width-m {:priority 0}, + :route-length-km {:priority 1}, + :rest-places-count {:priority 0}, + :free-use? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, + 4430 + {:description + {:fi + "Ratsastukseen ja/tai kärryillä ajoon tarkoitettu reitti. Sallitut käyttötavat kerrotaan reitin tarkemmissa tiedoissa.", + :se + "Led avsedd för ridning och/eller häst med kärra. Användningsanvisningar i karakteristika.", + :en + "Route intended for horseback riding and/or carriage riding. Different uses specified in additional information."}, + :tags {:fi ["ratsastusreitti"]}, + :name {:fi "Hevosreitti", :se "Hästled", :en "Horse track"}, + :type-code 4430, + :main-category 4000, + :status "active", + :sub-category 4400, + :geometry-type "LineString", + :props + {:surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :free-use? {:priority 0}, + :route-width-m {:priority 1}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :rest-places-count {:priority 0}, + :lit-route-length-km {:priority 1}, + :school-use? {:priority 0}, + :route-length-km {:priority 1}}}, + 204 + {:description + {:fi + "Luonnon tarkkailuun tarkoitettu rakennelma, lintutorni tai vastaava.", + :se + "Anordning avsedd för observationer i naturen, t ex fågeltorn.", + :en + "Structure built for nature observation. E.g. bird observation tower."}, + :tags {:fi ["lintutorni" "näkötorni" "torni"]}, + :name + {:fi "Luontotorni", :se "Naturtorn", :en "Nature observation tower"}, + :type-code 204, + :main-category 0, + :status "active", + :sub-category 2, + :geometry-type "Point", + :props + {:toilet? {:priority 0}, + :may-be-shown-in-excursion-map-fi? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :free-use? {:priority 0}}}, + 106 + {:description + {:fi + "Monikäyttöalueiksi voidaan nimittää jokaisenoikeuksin ulkoiluun käytettäviä maa- ja metsätalousalueita. Monikäyttöalueita ovat erityisesti rakentamattomat rannat ja taajamien läheiset maa- ja metsätalousalueet. Kaavamerkintä MU. Virkistysmetsien metsätaloudessa on huomioitu mm. maisemalliset arvot, ja ne on perustettu Metsähallituksen päätöksellä. Virkistysmetsien osalta Lipas-aineisto perustuu Metsähallituksen tietoihin.", + :se + "Områden för mångsidig användning kan kallas jord- och skogsbruksområden som används för rekreation med allemansrätten. Områden för mångsidig användning är särskilt obebyggda stränder och jord- och skogsbruksområden nära tätorter. Planbeteckning MU. Inom skogsbruket i rekreationsskogar har man beaktat bl.a. landskapsvärden, och de har inrättats genom beslut av Forststyrelsen. När det gäller rekreationsskogar baseras Lipas-materialet på uppgifter från Forststyrelsen.", + :en + "Multi-use areas can be designated as agricultural and forestry areas used for outdoor activities under everyman's rights. Multi-use areas are particularly undeveloped shores and agricultural and forestry areas near urban areas. Plan designation MU. In the forestry of recreational forests, landscape values, among other things, have been considered, and they have been established by a decision of Metsähallitus. For recreational forests, the Lipas data is based on information from Metsähallitus."}, + :tags {:fi ["ulkoilualue" "virkistysalue"]}, + :name + {:fi "Monikäyttöalue tai virkistysmetsä, jossa on virkistyspalveluita", + :se "Mångbruksområde eller rekreationsskog med rekreationstjänster", + :en "Multi-use area or recreational forest with recreational services"}, + :type-code 106, + :main-category 0, + :status "active", + :sub-category 1, + :geometry-type "Polygon", + :props + {:area-km2 {:priority 0}, + :may-be-shown-in-excursion-map-fi? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, + 2620 + {:description + {:fi + "Biljardisali on biljardin pelaamiseen tarkoitettu tila. Biljardipöytien määrä ja tyyppi kuvataan lisätiedoissa."}, + :tags {:fi []}, + :name {:fi "Biljardisali"}, + :type-code 2620, + :main-category 2000, + :status "active", + :sub-category 2600, + :geometry-type "Point", + :props + {:total-billiard-tables-count {:priority 0}, + :carom-tables-count {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :snooker-tables-count {:priority 0}, + :pool-tables-count {:priority 0}, + :customer-service-point? {:priority 0}, + :pyramid-tables-count {:priority 0}, + :kaisa-tables-count {:priority 0}, + :school-use? {:priority 0}}}, + 4610 + {:description + {:fi + "Ampumahiihdon harjoitteluun tarkoitettu alue, jossa on ainakin latu ja ampumapaikka/-paikkoja. ", + :se + "Annat träningsområde för skidskytte. Spår och skjutplats finns.", + :en + "Other training area for biathlon. Ski track and shooting range."}, + :tags {:fi ["ampumapaikka"]}, + :name + {:fi "Ampumahiihdon harjoittelualue", + :se "Träningsområde för skidskytte", + :en "Training area for biathlon"}, + :type-code 4610, + :main-category 4000, + :status "active", + :sub-category 4600, + :geometry-type "Point", + :props + {:stand-capacity-person {:priority 0}, + :free-use? {:priority 0}, + :ski-service? {:priority 0}, + :finish-line-camera? {:priority 0}, + :ski-track-traditional? {:priority 0}, + :route-width-m {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :rest-places-count {:priority 0}, + :changing-rooms? {:priority 0}, + :shooting-positions-count {:priority 1}, + :lit-route-length-km {:priority 0}, + :year-round-use? {:priority 0}, + :scoreboard? {:priority 0}, + :changing-rooms-m2 {:priority 0}, + :loudspeakers? {:priority 0}, + :ski-track-freestyle? {:priority 0}, + :route-length-km {:priority 0}}}, + 2610 + {:description + {:fi + "Keilailuun varustettu halli. Ratojen määrä ja palveluvarustus kirjataan lisätietoihin.", + :se "Antalet banor och serviceutrustning i karakteristika.", + :en "Number of alleys and service facilities in properties."}, + :tags {:fi []}, + :name {:fi "Keilahalli", :se "Bowlinghall", :en "Bowling alley"}, + :type-code 2610, + :main-category 2000, + :status "active", + :sub-category 2600, + :geometry-type "Point", + :props + {:free-use? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :bowling-lanes-count {:priority 1}, + :toilet? {:priority 0}, + :area-m2 {:priority 0}, + :cosmic-bowling? {:priority 0}, + :scoreboard? {:priority 0}, + :loudspeakers? {:priority 0}, + :school-use? {:priority 0}}}, + 2110 + {:description + {:fi + "Erilasia liikuntapalveluita ja -tiloja tarjoava kuntokeskus. Kohteessa voi olla esimerkiksi kuntosali- ja ryhmäliikuntatiloja.", + :se + "Olika motionstjänster och -utrymmen, t ex gym och gruppidrottsutrymmen.", + :en + "Different sports services and premises, e.g., gym, group exercise premises. "}, + :tags {:fi ["kuntosali" "kuntoilu"]}, + :name + {:fi "Kuntokeskus", + :se "Konditionsidrottscentrum", + :en "Fitness centre"}, + :type-code 2110, + :main-category 2000, + :status "active", + :sub-category 2100, + :geometry-type "Point", + :props + {:surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :free-customer-use? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :group-exercise-rooms-count {:priority 0}, + :area-m2 {:priority 1}, + :weight-lifting-spots-count {:priority 0}, + :customer-service-point? {:priority 0}, + :spinning-hall? {:priority 0}, + :school-use? {:priority 0}, + :exercise-machines-count {:priority 0}}}, + 3120 + {:description + {:fi + "Yksittäinen tai useampi pieni uima-allas muun kuin uimahallin tai kylpylän yhteydessä. Uima-allastilat voivat olla pääasiassa esim. kuntoutus- tai terapiakäytössä. Altaiden määrä ja vesipinta-ala kerrotaan ominaisuustiedoissa.", + :se "Enstaka simbassäng , ofta i anslutning till en annan byggnad.", + :en + "Individual swimming pool, often in connection with other buildings."}, + :tags {:fi []}, + :name {:fi "Uima-allastila", :se "Simbassäng", :en "Swimming pool"}, + :type-code 3120, + :main-category 3000, + :status "active", + :sub-category 3100, + :geometry-type "Point", + :props + {:pool-tracks-count {:priority 0}, + :free-use? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :pool-width-m {:priority 0}, + :pool-min-depth-m {:priority 0}, + :swimming-pool-count {:priority 0}, + :pool-water-area-m2 {:priority 1}, + :pool-length-m {:priority 1}, + :pool-max-depth-m {:priority 0}, + :accessibility-info {:priority 0}, + :pool-temperature-c {:priority 0}, + :school-use? {:priority 0}}}, + 104 + {:description + {:fi + "Sijaitsevat kauempana taajamasta, automatkan päässä. Monipuolinen polku- ja reittiverkosto. Käyttö painottuu viikonloppuihin ja loma-aikoihin. Palvelevat usein useaa kuntaa. Kaavamerkintä VR.", + :se + "Ett område på bil avstånd från tätorten, Området har en stor variation av stig- och ruttnätverk. Användningen av området fokuserar sig mest till helgerna och semester tiderna. Området betjänar oftast mer än en kommun. Planbeteckning VR.", + :en + "Located further away from population centres, accessible by car. Complex network of paths and routes. Use concentrated during weekends and holidays. Often serves several municipalities. Symbol VR."}, + :tags {:fi ["virkistysalue"]}, + :name {:fi "Retkeilyalue", :se "Utflyktsområde", :en "Hiking area"}, + :type-code 104, + :main-category 0, + :status "deprecated", + :sub-category 1, + :geometry-type "Polygon", + :props + {:may-be-shown-in-excursion-map-fi? {:priority 0}, + :area-km2 {:priority 0}, + :school-use? {:priority 0}, + :free-use? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, + 2330 + {:description + {:fi "Pysyvästi pöytätennikseen varustettu tila.", + :se "Permanent utrustning för att träna bordtennis.", + :en "Space permanently equipped for table tennis."}, + :tags {:fi ["pingis" "pingispöytä"]}, + :name + {:fi "Pöytätennistila", + :se "Utrymme för bordtennis", + :en "Table tennis venue"}, + :type-code 2330, + :main-category 2000, + :status "active", + :sub-category 2300, + :geometry-type "Point", + :props + {:height-m {:priority 0}, + :surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :free-use? {:priority 0}, + :active-space-width-m {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :area-m2 {:priority 1}, + :active-space-length-m {:priority 0}, + :table-tennis-count {:priority 1}, + :school-use? {:priority 0}}}, + 2280 + {:description + {:fi + "Tenniksen pelaamiseen varusteltu halli. Kenttien lukumäärä ja pintamateriaali kerrotaan kohteen lisätiedoissa.", + :se "Antalet banor i karakteristika.", + :en "Number of courts specified in properties."}, + :tags {:fi []}, + :name {:fi "Tennishalli", :se "Tennishall", :en "Tennis hall"}, + :type-code 2280, + :main-category 2000, + :status "active", + :sub-category 2200, + :geometry-type "Point", + :props + {:height-m {:priority 1}, + :surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :stand-capacity-person {:priority 0}, + :free-use? {:priority 0}, + :tennis-courts-count {:priority 1}, + :field-length-m {:priority 0}, + :badminton-courts-count {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :padel-courts-count {:priority 0}, + :toilet? {:priority 0}, + :area-m2 {:priority 1}, + :field-width-m {:priority 0}, + :scoreboard? {:priority 0}, + :floorball-fields-count {:priority 0}, + :squash-courts-count {:priority 0}, + :customer-service-point? {:priority 0}, + :volleyball-fields-count {:priority 0}, + :school-use? {:priority 0}}}, + 6140 + {:description + {:fi "Raviurheilun harjoitus- tai kilparata.", + :se "Övnings- eller tävlingsbana för travsport.", + :en "Training or competition track for horse racing."}, + :tags {:fi []}, + :name {:fi "Ravirata", :se "Travbana", :en "Horse racing track"}, + :type-code 6140, + :main-category 6000, + :status "active", + :sub-category 6100, + :geometry-type "Point", + :props + {:surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :automated-timing? {:priority 0}, + :stand-capacity-person {:priority 0}, + :free-use? {:priority 0}, + :finish-line-camera? {:priority 0}, + :track-width-m {:priority 1}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :lighting-info {:priority 0}, + :scoreboard? {:priority 0}, + :loudspeakers? {:priority 0}, + :ligthing? {:priority 1}, + :covered-stand-person-count {:priority 0}, + :track-length-m {:priority 1}}}, + 2140 + {:description + {:fi + "Sali, jossa voi harrastaa kamppailulajeja kuten painia, nyrkkeilyä tai budolajeja. Tilan koko ja varustus kerrotaan kohteen lisätiedoissa.", + :se + "Sal där man kan utöva självförsvarsgrenar, t ex brottning, boxning. Storleken anges i karakteristika.", + :en + "Hall for self-defence sports, e.g., wrestling, boxing. Size specified in properties. "}, + :tags {:fi ["paini" "judo" "tatami"]}, + :name + {:fi "Kamppailulajien sali", + :se "Sal för kampsport", + :en "Martial arts hall"}, + :type-code 2140, + :main-category 2000, + :status "active", + :sub-category 2100, + :geometry-type "Point", + :props + {:surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :group-exercise-rooms-count {:priority 0}, + :space-divisible {:priority 0}, + :tatamis-count {:priority 0}, + :area-m2 {:priority 1}, + :wrestling-mats-count {:priority 0}, + :boxing-rings-count {:priority 0}, + :weight-lifting-spots-count {:priority 0}, + :customer-service-point? {:priority 0}, + :school-use? {:priority 0}, + :exercise-machines-count {:priority 0}}}, + 4220 + {:description + {:fi + "Hiihtoon tarkoitettu katettu tila (esim. tunneli, putki, halli).", + :se + "Utrymme avsett för skidåkning under tak (tunnel, rör, hall el dyl).", + :en + "Covered space (tunnel, tube, hall, etc.) intended for skiing."}, + :tags {:fi []}, + :name {:fi "Hiihtotunneli", :se "Skidtunnel", :en "Ski tunnel"}, + :type-code 4220, + :main-category 4000, + :status "active", + :sub-category 4200, + :geometry-type "Point", + :props + {:surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :free-use? {:priority 0}, + :ski-service? {:priority 0}, + :altitude-difference {:priority 1}, + :route-width-m {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :area-m2 {:priority 0}, + :equipment-rental? {:priority 0}, + :accessibility-info {:priority 0}, + :route-length-km {:priority 1}}}, + 2230 + {:description + {:fi + "Ensisijaisesti jalkapalloiluun tarkoitettu halli. Halli voi olla ympärivuotisessa käytössä tai erikseen talviajalle pystytettävä kevythalli. Kentän pintamateriaalina on yleensä tekonurmi.", + :se + "Hall avsedd för fotboll. Ytmaterial, antalet planer och storlek i karakteristika.", + :en + "Hall intended for football. Surface material, number and size of courts specified in properties."}, + :tags {:fi []}, + :name + {:fi "Jalkapallohalli", :se "Fotbollshall", :en "Football hall"}, + :type-code 2230, + :main-category 2000, + :status "active", + :sub-category 2200, + :geometry-type "Point", + :props + {:height-m {:priority 1}, + :heating? {:priority 0}, + :surface-material {:priority 1}, + :basketball-fields-count {:priority 0}, + :surface-material-info {:priority 0}, + :stand-capacity-person {:priority 0}, + :free-use? {:priority 0}, + :tennis-courts-count {:priority 0}, + :field-length-m {:priority 1}, + :match-clock? {:priority 0}, + :sprint-track-length-m {:priority 0}, + :badminton-courts-count {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :area-m2 {:priority 1}, + :field-width-m {:priority 1}, + :scoreboard? {:priority 0}, + :football-fields-count {:priority 0}, + :auxiliary-training-area? {:priority 0}, + :loudspeakers? {:priority 0}, + :customer-service-point? {:priority 0}, + :volleyball-fields-count {:priority 0}, + :school-use? {:priority 0}}}, + 1350 + {:description + {:fi + "Suuri jalkapallokenttä, katsomoita. Vähintään kansallisen tason pelipaikka.", + :se + "Stor fotbollsplan, flera läktare. Minimikrav: spelplats på nationell nivå.", + :en + "Large football field, stands. Can host at least national-level games."}, + :tags {:fi ["jalkapallokenttä"]}, + :name + {:fi "Jalkapallostadion", + :se "Fotbollsstadion", + :en "Football stadium"}, + :type-code 1350, + :main-category 1000, + :status "active", + :sub-category 1300, + :geometry-type "Point", + :props + {:heating? {:priority 0}, + :surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :stand-capacity-person {:priority 0}, + :free-use? {:priority 0}, + :field-length-m {:priority 1}, + :match-clock? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :area-m2 {:priority 1}, + :field-width-m {:priority 1}, + :lighting-info {:priority 0}, + :year-round-use? {:priority 0}, + :scoreboard? {:priority 0}, + :loudspeakers? {:priority 0}, + :customer-service-point? {:priority 0}, + :water-point {:priority 0}, + :ligthing? {:priority 1}, + :covered-stand-person-count {:priority 0}, + :school-use? {:priority 0}, + :light-roof? {:priority 0}}}, + 4840 + {:description + {:fi + "Maastoon rakennettu jousiammuntarata. Radan käyttö edellyttää erillistä lupaa, seuran jäsenyyttä tai harjoitusvuoroa. ", + :se "Bågskyttebana byggd i terrängen.", + :en "Archery course built in rough terrain."}, + :tags {:fi ["jousiampumarata"]}, + :name + {:fi "Jousiammuntamaastorata", + :se "Terrängbana för bågskytte", + :en "Field archery course"}, + :type-code 4840, + :main-category 4000, + :status "active", + :sub-category 4800, + :geometry-type "Point", + :props + {:free-use? {:priority 0}, + :free-customer-use? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :shooting-positions-count {:priority 1}, + :lighting-info {:priority 0}, + :ligthing? {:priority 1}, + :track-length-m {:priority 1}}}, + 113 + {:description + {:fi + "Vapaa-ajankalastukseen sopiva alue. Kohteessa voi olla palvelurakenteita.", + :se + "Område eller en plats i ett naturligt vattendrag som ställts i ordning för fritidsfiske.", + :en + "Natural aquatic destination equipped and maintained for recreational fishing."}, + :tags {:fi ["kalastusalue" "kalastuspaikka"]}, + :name + {:fi "Kalastuskohde (alue)", + :se "Område eller plats för fiske", + :en "Fishing area/spot "}, + :type-code 113, + :main-category 0, + :status "active", + :sub-category 1, + :geometry-type "Polygon", + :props + {:free-use? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :pier? {:priority 0}, + :customer-service-point? {:priority 0}, + :equipment-rental? {:priority 0}}}, + 1510 + {:description + {:fi + "Koneellisesti tai keinotekoisesti jäähdytetty ulkokenttä. Kentän koko ja varustustiedot löytyvät lisätiedoista. Käytössä talvikaudella.", + :se + "En utomhusbana som är mekaniskt eller artificiellt kyld. Information om banans storlek och utrustning finns i ytterligare information. Används under vintersäsongen.", + :en + "An outdoor rink that is mechanically or artificially cooled. Details about the size and equipment of the rink can be found in the additional information. Used during the winter season."}, + :tags {:fi ["luistelukenttä" "luistelu"]}, + :name + {:fi "Tekojääkenttä/tekojäärata", + :se "Konstis", + :en "Mechanically frozen open-air ice rink"}, + :type-code 1510, + :main-category 1000, + :status "active", + :sub-category 1500, + :geometry-type "Point", + :props + {:surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :stand-capacity-person {:priority 0}, + :free-use? {:priority 0}, + :field-length-m {:priority 1}, + :match-clock? {:priority 0}, + :fields-count {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :ice-rinks-count {:priority 0}, + :toilet? {:priority 0}, + :changing-rooms? {:priority 0}, + :area-m2 {:priority 1}, + :field-width-m {:priority 1}, + :lighting-info {:priority 0}, + :changing-rooms-m2 {:priority 0}, + :customer-service-point? {:priority 0}, + :ligthing? {:priority 1}, + :school-use? {:priority 0}, + :light-roof? {:priority 0}}}, + 5350 + {:description + {:fi + "Pääasiallisesti kiihdytysautoiluun tai kiihdytysmoottoripyöräilyyn käytetty rata.", + :se "Huvudsakligen för accelerationskörning.", + :en "Mainly for drag racing."}, + :tags {:fi []}, + :name + {:fi "Kiihdytysrata", :se "Accelerationsbana", :en "Dragstrip"}, + :type-code 5350, + :main-category 5000, + :status "active", + :sub-category 5300, + :geometry-type "Point", + :props + {:surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :automated-timing? {:priority 0}, + :stand-capacity-person {:priority 0}, + :free-use? {:priority 0}, + :track-width-m {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :area-m2 {:priority 0}, + :lighting-info {:priority 0}, + :year-round-use? {:priority 0}, + :scoreboard? {:priority 0}, + :loudspeakers? {:priority 0}, + :ligthing? {:priority 0}, + :covered-stand-person-count {:priority 0}, + :track-length-m {:priority 1}}}, + 2225 + {:description + {:fi + "Sisäleikkipuistot ovat yleensä pienille lapsille tarkoitettuja liikunnallisia leikkipaikkoja. Sisäaktiviteettipuistot ovat tyypillisesti lapsille ja nuorille tarkoitettuja liikuntakeskuksia, jotka sisältävät erilaisia liikunnallisia kohteita."}, + :tags {:fi []}, + :name {:fi "Sisäleikki-/sisäaktiviteettipuisto"}, + :type-code 2225, + :main-category 2000, + :status "active", + :sub-category 2200, + :geometry-type "Point", + :props + {:customer-service-point? {:priority 0}, + :height-m {:priority 0}, + :area-m2 {:priority 0}}}, + 4440 + {:description + {:fi + "Hiihtolatu, jossa on aina tai tiettyinä aikoina koirahiihto sallittua. Perinteinen tyyli tai vapaa tyyli.", + :se + "Ett skidspår där det alltid eller vissa tider är tillåtet att åka med hundspann. Klassisk stil eller fristil.", + :en + "Ski track on which dog skijoring is allowed either always or at given times. Traditional or free style."}, + :tags {:fi ["koiralatu"]}, + :name + {:fi "Koirahiihtolatu", + :se "Spår för hundspann", + :en "Dog skijoring track"}, + :type-code 4440, + :main-category 4000, + :status "active", + :sub-category 4400, + :geometry-type "LineString", + :props + {:surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :free-use? {:priority 0}, + :ski-track-traditional? {:priority 0}, + :route-width-m {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :rest-places-count {:priority 0}, + :lit-route-length-km {:priority 1}, + :ski-track-freestyle? {:priority 0}, + :school-use? {:priority 0}, + :route-length-km {:priority 1}}}, + 2520 + {:description + {:fi + "Kilpajäähalli on jääurheilun kilpailu- ja ottelutapahtumiin soveltuva jäähalli. Katsomon koko, kenttien lukumäärä ja muut tarkemmat tiedot kuvataan lisätiedoissa.", + :se + "Läktare finns, storleken på läktaren anges i karakteristika, likaså antalet planer.", + :en + "Includes bleachers, whose size is specified in properties. Number of fields, heating, changing rooms, etc., specified in properties."}, + :tags {:fi ["jäähalli"]}, + :additional-type + {:small {:fi "Pieni kilpahalli > 500 hlö", :en nil, :se nil}, + :competition {:fi "Kilpahalli < 3000 hlö", :en nil, :se nil}, + :large {:fi "Suurhalli > 3000 hlö", :en nil, :se nil}}, + :name + {:fi "Kilpajäähalli", + :se "Tävlingsishall", + :en "Competition ice arena"}, + :type-code 2520, + :keywords {:fi ["Jäähalli"], :en [], :se []}, + :main-category 2000, + :status "active", + :sub-category 2500, + :geometry-type "Point", + :props + {:surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :automated-timing? {:priority 0}, + :stand-capacity-person {:priority 0}, + :free-use? {:priority 0}, + :finish-line-camera? {:priority 0}, + :match-clock? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :ice-rinks-count {:priority 1}, + :field-2-flexible-rink? {:priority 0}, + :toilet? {:priority 0}, + :area-m2 {:priority 1}, + :curling-lanes-count {:priority 0}, + :scoreboard? {:priority 0}, + :auxiliary-training-area? {:priority 0}, + :ringette-boundary-markings? {:priority 0}, + :field-1-flexible-rink? {:priority 0}, + :loudspeakers? {:priority 0}, + :school-use? {:priority 0}, + :field-3-flexible-rink? {:priority 0}}}, + 4710 + {:description + {:fi + "Rakennettu kiipeilyseinä ulkona, köysikiipeilyrata tai vastaava kiipeilyä varten rakennettu paikka. Myös rakennetut boulderointipaikat. Paikan tarkempi kuvaus ominaisuustietoihin.", + :se + "Byggd klättervägg utomhus, klätterbana eller annan plats byggd för klättring. Även platser för bouldering. Precisering i karakteristika.", + :en + "Built outdoor climbing wall, rope climbing path or other place built for climbing. Also bouldering venues. Clarification in 'properties'."}, + :tags {:fi ["kiipeilyseinä" "köysikiipeily"]}, + :name + {:fi "Ulkokiipeilypaikka", + :se "Utomhusklätterplats", + :en "Open-air climbing venue"}, + :type-code 4710, + :main-category 4000, + :status "active", + :sub-category 4700, + :geometry-type "Point", + :props + {:surface-material {:priority 0}, + :surface-material-info {:priority 0}, + :free-use? {:priority 0}, + :climbing-routes-count {:priority 0}, + :ice-climbing? {:priority 0}, + :climbing-wall-height-m {:priority 1}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :area-m2 {:priority 1}, + :lighting-info {:priority 0}, + :climbing-wall-width-m {:priority 1}, + :ligthing? {:priority 0}, + :school-use? {:priority 0}}}, + 304 + {:description + {:fi + "Tavallisen arkiliikunnan taukopaikka, päiväkäyttöön. Lisätietoihin merkitään kohteessa olevat palvelut, esim. kahvio, vuokrauspiste tai opastuspiste.", + :se "Rastplats för bruk under dagen, vardagsmotion.", + :en "Rest area for regular daily sports, for daytime use."}, + :tags {:fi ["tupa" "taukopaikka" "ulkoilumaja" "hiihtomaja"]}, + :name + {:fi "Ulkoilumaja/hiihtomaja", + :se "Friluftsstuga/skidstuga", + :en "Outdoor/ski lodge "}, + :type-code 304, + :main-category 0, + :status "active", + :sub-category 2, + :geometry-type "Point", + :props + {:toilet? {:priority 0}, + :may-be-shown-in-excursion-map-fi? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :customer-service-point? {:priority 0}, + :equipment-rental? {:priority 0}, + :free-use? {:priority 0}}}, + 4412 + {:description + {:fi + "Pyöräilyreitti, joka kulkee enimmäkseen päällystetyillä teillä tai sorateillä. Reitti voi olla merkitty maastoon tai se on digitaalisesti opastettu.", + :se "Cykelled, ej för mountainbikar.", + :en "Biking route, not intended for cross-country biking."}, + :tags {:fi []}, + :name {:fi "Pyöräilyreitti", :se "Cykelled", :en "Biking route"}, + :type-code 4412, + :main-category 4000, + :status "active", + :sub-category 4400, + :geometry-type "LineString", + :props + {:surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :free-use? {:priority 0}, + :may-be-shown-in-excursion-map-fi? {:priority 0}, + :route-width-m {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :rest-places-count {:priority 0}, + :lit-route-length-km {:priority 1}, + :route-length-km {:priority 1}}}, + 4820 + {:description + {:fi + "Ampumarata jossa myös palveluita. SM-kisojen järjestäminen mahdollista.", + :se "Skjutbana med tjänster. Möjligt att arrangera FM-tävlingar.", + :en + "Shooting range with services. National competitions possible."}, + :tags {:fi ["ampumapaikka" "ammunta"]}, + :name + {:fi "Ampumaurheilukeskus", + :se "Sportskyttecentrum", + :en "Shooting sports centre"}, + :type-code 4820, + :main-category 4000, + :status "active", + :sub-category 4800, + :geometry-type "Point", + :props + {:stand-capacity-person {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :air-gun-shooting? {:priority 0}, + :toilet? {:priority 0}, + :pistol-shooting? {:priority 0}, + :shooting-positions-count {:priority 1}, + :area-m2 {:priority 0}, + :lighting-info {:priority 0}, + :rifle-shooting? {:priority 0}, + :year-round-use? {:priority 0}, + :scoreboard? {:priority 0}, + :loudspeakers? {:priority 0}, + :shotgun-shooting? {:priority 0}, + :free-rifle-shooting? {:priority 0}, + :ligthing? {:priority 1}, + :accessibility-info {:priority 0}, + :track-length-m {:priority 1}}}, + 1170 + {:description + {:fi "Ratapyöräilyä varten rakennettu paikka, ulkona (velodromi).", + :se "Utomhus, velodrom.", + :en "For track racing outdoors (velodrome)."}, + :tags {:fi ["velodromi"]}, + :name + {:fi "Pyöräilyrata/velodromi", + :se "Velodrom", + :en "Velodrome"}, + :type-code 1170, + :main-category 1000, + :status "active", + :sub-category 1100, + :geometry-type "Point", + :props + {:surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :free-use? {:priority 0}, + :track-width-m {:priority 1}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :area-m2 {:priority 0}, + :lighting-info {:priority 0}, + :ligthing? {:priority 1}, + :school-use? {:priority 0}, + :track-length-m {:priority 1}}}, + 6150 + {:description + {:fi "Islanninhevosten askellajiratsastukseen varattu rata ulkona.", + :se + "En bana utomhus avsedd för gångartstävlingar med islandshästar.", + :en + "An outdoor track designated for gaited riding competitions with Icelandic horses."}, + :tags + {:fi + ["islanninhevosrata" + "islanninhevosratsastus" + "ovaalibaana" + "askellajiratsastus" + "askellajirata"], + :se + ["islandshästbana" + "islandshästridning" + "ovalbana" + "gångartstävling" + "gångartsbana"], + :en + ["Icelandic horse track" + "Icelandic horse riding" + "oval track" + "gaited riding" + "gaited track"]}, + :name {:fi "Ovaalirata", :se "Ovalbana", :en "Oval Track"}, + :type-code 6150, + :main-category 6000, + :status "active", + :sub-category 6100, + :geometry-type "LineString", + :props + {:surface-material {:priority 0}, + :surface-material-info {:priority 0}, + :track-width-m {:priority 0}, + :free-use {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :customer-service-point? {:priority 0}, + :ligthing? {:priority 0}, + :track-length-m {:priority 0}}}, + 4404 + {:description + {:fi + "Erityisesti luontoharrastusta varten rakennettu ulkoilureitti. Reitin varrella opasteita tai infotauluja alueen luonnosta.", + :se + "I synnerhet för naturintresse, info- och orienteringstavlor längs leden.", + :en + "Intended particularly for nature activities; signposts or info boards along the route."}, + :tags {:fi ["retkeily"]}, + :name {:fi "Luontopolku", :se "Naturstig", :en "Nature trail"}, + :type-code 4404, + :main-category 4000, + :status "active", + :sub-category 4400, + :geometry-type "LineString", + :props + {:surface-material {:priority 0}, + :surface-material-info {:priority 0}, + :free-use? {:priority 0}, + :may-be-shown-in-excursion-map-fi? {:priority 0}, + :route-width-m {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :rest-places-count {:priority 0}, + :lit-route-length-km {:priority 0}, + :accessibility-info {:priority 0}, + :school-use? {:priority 0}, + :route-length-km {:priority 1}}}, + 108 + {:description + {:fi + "Metsähallituksen päätöksellä perustettu virkistysmetsä. Metsätaloudessa huomioidaan mm. maisemalliset arvot. Metsähallitus tietolähde.", + :se + "Grundad enligt Forststyrelsens beslut. I skogsbruket tas hänsyn till bl a landskapsvärden. Källa: Forststyrelsen.", + :en + "Recreational forest designated by Metsähallitus. E.g. scenic value is considered in forestry. Source of information Metsähallitus."}, + :tags {:fi []}, + :name + {:fi "Virkistysmetsä", + :se "Friluftsskog", + :en "Recreational forest"}, + :type-code 108, + :main-category 0, + :status "deprecated", + :sub-category 1, + :geometry-type "Polygon", + :props + {:area-km2 {:priority 0}, + :school-use? {:priority 0}, + :free-use? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, + 4401 + {:description + {:fi + "Kuntoiluun tarkoitettu hoidettu liikuntareitti asutuksen läheisyydessä. Usein ainakin osittain valaistu.", + :se "Led avsedd för konditionssport i närheten av bebyggelse.", + :en "Route intended for jogging in or near a residential area."}, + :tags {:fi ["pururata"]}, + :name {:fi "Kuntorata", :se "Konditionsbana", :en "Jogging track"}, + :type-code 4401, + :main-category 4000, + :status "active", + :sub-category 4400, + :geometry-type "LineString", + :props + {:surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :free-use? {:priority 0}, + :may-be-shown-in-excursion-map-fi? {:priority 0}, + :outdoor-exercise-machines? {:priority 0}, + :route-width-m {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :rest-places-count {:priority 0}, + :shooting-positions-count {:priority 0}, + :lit-route-length-km {:priority 1}, + :accessibility-info {:priority 0}, + :school-use? {:priority 0}, + :route-length-km {:priority 1}}}, + 2350 + {:description + {:fi + "Pysyvästi tanssi-, ilmaisu- tai ryhmäliikuntaan varustettu itsenäinen tila, joka ei ole osa esim. kuntokeskusta. Myös boutique-, fitness- ja mikrostudiot ovat tanssi- tai ryhmäliikuntatiloja.", + :se "Permanent utrustning för dans och kreativ motion.", + :en + "Space permanently equipped for dance or expressive movement exercise."}, + :tags {:fi ["peilisali" "baletti" "tanssisali"]}, + :name + {:fi "Tanssi-/ryhmäliikuntatila", + :se "Utrymme för dans", + :en "Dance studio"}, + :type-code 2350, + :main-category 2000, + :status "active", + :sub-category 2300, + :geometry-type "Point", + :props + {:height-m {:priority 0}, + :surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :free-use? {:priority 0}, + :active-space-width-m {:priority 0}, + :mirror-wall? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :group-exercise-rooms-count {:priority 0}, + :area-m2 {:priority 1}, + :active-space-length-m {:priority 0}, + :school-use? {:priority 0}}}, + 2340 + {:description + {:fi "Pysyvästi miekkailuun varustettu tila.", + :se "Permanent utrustning för fäktning.", + :en "Space permanently equipped for fencing."}, + :tags {:fi []}, + :name + {:fi "Miekkailutila", + :se "Utrymme för fäktning", + :en "Fencing venue"}, + :type-code 2340, + :main-category 2000, + :status "active", + :sub-category 2300, + :geometry-type "Point", + :props + {:height-m {:priority 0}, + :surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :free-use? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :area-m2 {:priority 1}, + :fencing-bases-count {:priority 1}, + :school-use? {:priority 0}}}, + 2120 + {:description + {:fi + "Liikuntatila, jossa on useita kuntosalilaitteita pysyvästi sijoitettuna.", + :se "Gymredskap osv. Storleken anges i karakteristika.", + :en "Gym equipment, etc. Size specified in properties."}, + :tags {:fi ["kuntoilu" "voimailu"]}, + :name {:fi "Kuntosali", :se "Gym", :en "Gym"}, + :type-code 2120, + :main-category 2000, + :status "active", + :sub-category 2100, + :geometry-type "Point", + :props + {:surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :free-customer-use? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :group-exercise-rooms-count {:priority 0}, + :area-m2 {:priority 1}, + :weight-lifting-spots-count {:priority 0}, + :customer-service-point? {:priority 0}, + :spinning-hall? {:priority 0}, + :school-use? {:priority 0}, + :exercise-machines-count {:priority 0}}}, + 109 + {:description + {:fi + "Ulkoilulailla perustetut, retkeilyä ja luonnon virkistyskäyttöä varten. Metsähallitus tietolähteenä.", + :se + "Grundat enligt lagen om friluftsliv för att användas för friluftsliv och rekreation i naturen. Källa: Forststyrelsen.", + :en + "Established based on the Outdoor Recreation Act for hiking and recreational use of nature. Source of information Metsähallitus."}, + :tags {:fi []}, + :name + {:fi "Valtion retkeilyalue", + :se "Statens friluftsområde", + :en "National hiking area"}, + :type-code 109, + :main-category 0, + :status "active", + :sub-category 1, + :geometry-type "Polygon", + :props + {:area-km2 {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, + 1650 + {:description + {:fi + "Ensisijaisesti golfin pelaamiseen tarkoitettu alue kesäkaudella. Reikien määrä merkitään lisätietoihin.", + :se "Officiell golfbana. Antalet hål anges i karakteristika.", + :en + "Official golf course. Number of holes included in properties."}, + :tags {:fi ["greeni" "puttialue" "range"]}, + :name {:fi "Golfkenttä (alue)", :se "Golfbana", :en "Golf course"}, + :type-code 1650, + :main-category 1000, + :status "active", + :sub-category 1600, + :geometry-type "Polygon", + :props + {:holes-count {:priority 1}, + :free-use? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :lighting-info {:priority 0}, + :customer-service-point? {:priority 0}, + :green? {:priority 0}, + :ligthing? {:priority 1}, + :school-use? {:priority 0}, + :range? {:priority 0}}}, + 4441 + {:description + {:fi "Koiravaljakoille ylläpidetty reitti.", + :se "En rutt underhållen för hundspann.", + :en "A route maintained for dog sledding."}, + :tags {:fi ["valjakkoajo" "valjakkoreitti"], :se [], :en []}, + :name + {:fi "Koiravaljakkoreitti", + :se "Hundspannsrutt", + :en "Dog Sledding Route"}, + :type-code 4441, + :main-category 4000, + :status "active", + :sub-category 4400, + :geometry-type "LineString", + :props + {:surface-material {:priority 0}, + :surface-material-info {:priority 0}, + :route-length-km {:priority 0}, + :lit-route-length-km {:priority 0}, + :route-width-m {:priority 0}, + :free-use {:priority 0}, + :year-round-use? {:priority 0}}}, + 5160 + {:description + {:fi + "Soudun ja melonnan sisäharjoittelutila on erityisesti näihin lajeihin pysyvästi tarkoitettu liikuntapaikka.", + :se "Separat, ej normal bassäng.", + :en "Separate training facility, not a regular swimming pool."}, + :tags {:fi ["kajakki" "kanootti" "melonta"]}, + :name + {:fi "Soudun ja melonnan sisäharjoittelutila", + :se "Inomhusträningsutrymme för rodd och paddling", + :en "Indoor training facility for rowing and canoeing"}, + :type-code 5160, + :main-category 5000, + :status "active", + :sub-category 5100, + :geometry-type "Point", + :props + {:area-m2 {:priority 0}, + :free-use? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, + 1550 + {:description + {:fi + "Luisteluun tarkoitettu luonnonjäälle tai maalle rakennettava huollettu luistelureitti. Rakennetaan talvisin samalle alueelle. ", + :se + "Byggs varje vinter på samma område t ex i en idrottspark eller på havsis.", + :en + "Built yearly in the same area, e.g., in a sports park or on frozen lake/sea."}, + :tags {:fi ["luistelu" "retkiluistelu" "retkiluistelurata"]}, + :name + {:fi "Luistelureitti", :se "Skridskoled", :en "Ice-skating route"}, + :type-code 1550, + :main-category 1000, + :status "active", + :sub-category 1500, + :geometry-type "Point", + :props + {:surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :free-use? {:priority 0}, + :may-be-shown-in-excursion-map-fi? {:priority 0}, + :track-width-m {:priority 1}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :lighting-info {:priority 0}, + :equipment-rental? {:priority 0}, + :customer-service-point? {:priority 0}, + :ligthing? {:priority 1}, + :school-use? {:priority 0}, + :track-length-m {:priority 1}}}, + 3230 + {:description + {:fi + "Pieni yleinen uimaranta tai uimapaikka, jossa pelastusväline ja ilmoitustaulu. Veden laadun seuranta ja alueen hoito järjestetty.", + :se + "Liten allmän badstrand eller badplats. Räddningsutrustning och en anslagstavla finns. Kvaliteten på vattnet följs upp och området underhålls.", + :en + "Small public beach or swimming site. Rescue equipment and a notice board are available. The quality of the water is monitored and the area is maintained."}, + :tags {:fi ["uimaranta"]}, + :name {:fi "Uimapaikka", :se "Badplats", :en "Swimming site"}, + :type-code 3230, + :main-category 3000, + :status "active", + :sub-category 3200, + :geometry-type "Point", + :props + {:free-use? {:priority 0}, + :pier? {:priority 0}, + :may-be-shown-in-excursion-map-fi? {:priority 0}, + :beach-length-m {:priority 1}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :shower? {:priority 0}, + :changing-rooms? {:priority 0}, + :sauna? {:priority 0}, + :other-platforms? {:priority 0}, + :school-use? {:priority 0}}}, + 5130 + {:description + {:fi "Pysyvä moottorivenekilpailujen rata-alue.", + :se "Permanent banområde för hastighetstävlingar.", + :en "Permanent track area for speed competitions."}, + :tags {:fi []}, + :name + {:fi "Moottoriveneurheilualue", + :se "Område för motorbåtsport", + :en "Motor boat sports area"}, + :type-code 5130, + :main-category 5000, + :status "active", + :sub-category 5100, + :geometry-type "Point", + :props + {:pier? {:priority 0}, + :area-km2 {:priority 0}, + :boat-places-count {:priority 0}, + :free-use? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, + 5110 + {:description + {:fi + "Soutustadion sisältää pysyvästi soutuun käytettäviä rakenteita. Soutustadionissa on katsomo ja valmius ratamerkintöihin.", + :se + "Byggt för rodd, permanent. Läktare och förberett för banmärkning.", + :en + "Permanent construction for rowing. Bleachers, track markings possible."}, + :tags {:fi []}, + :name {:fi "Soutustadion", :se "Roddstadion", :en "Rowing stadium"}, + :type-code 5110, + :main-category 5000, + :status "active", + :sub-category 5100, + :geometry-type "Point", + :props + {:automated-timing? {:priority 0}, + :stand-capacity-person {:priority 0}, + :free-use? {:priority 0}, + :pier? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :area-m2 {:priority 0}, + :scoreboard? {:priority 0}, + :track-length-m {:priority 1}}}, + 3240 + {:description + {:fi + "Talviuintipaikka voi sijaita avannossa, avovedessä tai maauimalassa talvikaudella. Talviuintipaikka merkitään omaksi liikuntapaikakseen.", + :se + "Vinterbadplats kan vara belägen i en vak, öppet vatten eller utomhuspool. Vinterbadplats är markerad som egen idrottsanläggning", + :en + "Winter swimming area may be located in an ice hole, open water or open air pool. Winter swimming area is marked as its own sports facility."}, + :tags {:fi ["avanto" "avantouinti" "talviuinti"]}, + :name + {:fi "Talviuintipaikka", + :se "Vinterbadplats", + :en "Winter swimming area"}, + :type-code 3240, + :main-category 3000, + :status "active", + :sub-category 3200, + :geometry-type "Point", + :props + {:free-use? {:priority 0}, + :pier? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :shower? {:priority 0}, + :changing-rooms? {:priority 0}, + :ice-reduction? {:priority 0}, + :sauna? {:priority 0}, + :school-use? {:priority 0}}}, + 4510 + {:description + {:fi + "Suunnistukseen käytetty alue. Lisätietoihin merkitään, jos aluetta käytetään mobo-, pyörä- tai hiihtosuunnistukseen. Suunnistusalueesta on saatavilla kartta ja maankäyttöön on maanomistajan suostumus.", + :se + "Anmält till orienteringsförbundet. Karta över området tillgänglig.", + :en + "The Finnish Orienteering Federation has been informed. A map of the area available."}, + :tags {:fi []}, + :name + {:fi "Suunnistusalue", + :se "Orienteringsområde", + :en "Orienteering area"}, + :type-code 4510, + :main-category 4000, + :status "active", + :sub-category 4500, + :geometry-type "Polygon", + :props + {:area-km2 {:priority 0}, + :school-use? {:priority 0}, + :free-use? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :mobile-orienteering? {:priority 0}, + :bike-orienteering? {:priority 0}, + :ski-orienteering? {:priority 0}}}, + 4240 + {:description + {:fi "Katettu laskettelurinne.", + :se "Slalombacke med tak. Höjdskillnad och längd i karakteristika.", + :en + "Covered ski slope. Height and length specified in attributes."}, + :tags {:fi []}, + :name + {:fi "Lasketteluhalli", + :se "Slalomhall", + :en "Downhill skiing hall"}, + :type-code 4240, + :main-category 4000, + :status "active", + :sub-category 4200, + :geometry-type "Point", + :props + {:surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :free-use? {:priority 0}, + :ski-service? {:priority 0}, + :altitude-difference {:priority 1}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :area-m2 {:priority 0}, + :equipment-rental? {:priority 0}, + :route-length-km {:priority 1}}}, + 2270 + {:description + {:fi + "Ensisijaisesti squashin pelaamiseen tarkoitettu halli. Yksittäisen kentän mitat 9,75 m x 6,4 m. Vapaa korkeus ja pintamateriaali ilmoitetaan lisätiedoissa.", + :se "En eller flera squashplaner. Antalet planer i karakteristika.", + :en + "One or more squash courts. Number of courts specified in properties."}, + :tags {:fi ["squash" "squash-kenttä" "squashkenttä" "squashhalli"]}, + :name {:fi "Squash-halli", :se "Squashhall", :en "Squash hall"}, + :type-code 2270, + :main-category 2000, + :status "active", + :sub-category 2200, + :geometry-type "Point", + :props + {:height-m {:priority 1}, + :surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :stand-capacity-person {:priority 0}, + :free-use? {:priority 0}, + :tennis-courts-count {:priority 0}, + :field-length-m {:priority 0}, + :badminton-courts-count {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :padel-courts-count {:priority 0}, + :toilet? {:priority 0}, + :area-m2 {:priority 1}, + :field-width-m {:priority 0}, + :scoreboard? {:priority 0}, + :floorball-fields-count {:priority 0}, + :squash-courts-count {:priority 1}, + :customer-service-point? {:priority 0}, + :volleyball-fields-count {:priority 0}, + :school-use? {:priority 0}}}, + 4210 + {:description + {:fi + "Pysyvästi lajiin varustettu tila, esim. curlingrata tai curlinghalli.", + :se "Curlingbana med tak och permanent utrustning för grenen.", + :en "Covered track permanently equipped for curling."}, + :tags {:fi ["curlinghalli" "curling-halli" "curling-rata"]}, + :name + {:fi "Curlingrata/-halli", :se "Curlingbana", :en "Curling sheet"}, + :type-code 4210, + :main-category 4000, + :status "active", + :sub-category 4200, + :geometry-type "Point", + :props + {:surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :stand-capacity-person {:priority 0}, + :free-use? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :changing-rooms? {:priority 0}, + :area-m2 {:priority 1}, + :curling-lanes-count {:priority 0}, + :changing-rooms-m2 {:priority 0}}}, + 301 + {:description + {:fi + "Päiväsaikainen levähdyspaikka retkeilijöille. Esimerkiksi kodalla tarkoitetaan kotamallista sääsuojaa tai levähdyspaikkaa ja laavu on kaltevakattoinen sääsuoja, joka sisältää tulipaikan. Lisätietoihin merkitään tieto tulentekopaikasta.", + :se "Viloplats för vandrare under dagtid.", + :en "Daytime rest stop for hikers."}, + :tags {:fi ["taukopaikka"]}, + :name + {:fi "Laavu, kota tai kammi", + :se "Vindskydd eller kåta", + :en "Lean-to, goahti (Lapp tent shelter) or 'kammi' earth lodge"}, + :type-code 301, + :main-category 0, + :status "active", + :sub-category 2, + :geometry-type "Point", + :props + {:may-be-shown-in-excursion-map-fi? {:priority 0}, + :toilet? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :water-point {:priority 0}, + :free-use? {:priority 0}}}, + 111 + {:description + {:fi + "Kansallispuistot ovat luonnonsuojelualueita, joiden perustamisesta ja tarkoituksesta on säädetty lailla. Kansallispuistoissa on merkittyjä reittejä, luontopolkuja ja tulentekopaikkoja. Kansallispuistoissa voi myös yöpyä, sillä niissä on telttailualueita tai yöpymiseen tarkoitettuja rakennuksia. LIPAS-aineisto perustuu Metsähallituksen tietoihin.", + :se + "Naturskyddsområden med lagstadgad status och uppgift. Areal minst 1000 ha. Källa: Forststyrelsen.", + :en + "Nature conservation areas whose establishment and purpose are based on legislation. Min. area 1,000 ha. Source of information Metsähallitus."}, + :tags {:fi []}, + :name + {:fi "Kansallispuisto", :se "Nationalpark", :en "National park"}, + :type-code 111, + :main-category 0, + :status "active", + :sub-category 1, + :geometry-type "Polygon", + :props + {:area-km2 {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, + 4630 + {:description + {:fi + "Hiihtokilpailujen järjestämiseen soveltuva kisakeskus, jossa on esimerkiksi lähtö- ja maalialue, huoltotilat ja riittävä latuverkosto.", + :se "Start- och målområden, serviceutrymmen, spårsystem.", + :en "Start and finish area, service premises. Tracks."}, + :tags {:fi ["hiihtostadion"]}, + :name + {:fi "Kilpahiihtokeskus", + :se "Maastohiihtokeskus", + :en "Ski competition centre"}, + :type-code 4630, + :main-category 4000, + :status "active", + :sub-category 4600, + :geometry-type "Point", + :props + {:stand-capacity-person {:priority 0}, + :free-use? {:priority 0}, + :ski-service? {:priority 0}, + :finish-line-camera? {:priority 0}, + :ski-track-traditional? {:priority 0}, + :route-width-m {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :shower? {:priority 0}, + :rest-places-count {:priority 0}, + :changing-rooms? {:priority 0}, + :lit-route-length-km {:priority 0}, + :scoreboard? {:priority 0}, + :sauna? {:priority 0}, + :loudspeakers? {:priority 0}, + :accessibility-info {:priority 0}, + :ski-track-freestyle? {:priority 0}, + :route-length-km {:priority 0}}}, + 4810 + {:description + {:fi "Ulkoampumarata yhdelle tai useammalle lajille.", + :se "Utomhusskjutbana för en eller flera grenar.", + :en "Outdoor shooting range for one or more sports. "}, + :tags {:fi ["ampumapaikka" "ammunta"]}, + :name + {:fi "Ampumarata", :se "Skjutbana", :en "Open-air shooting range"}, + :type-code 4810, + :main-category 4000, + :status "active", + :sub-category 4800, + :geometry-type "Point", + :props + {:stand-capacity-person {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :air-gun-shooting? {:priority 0}, + :toilet? {:priority 0}, + :pistol-shooting? {:priority 0}, + :shooting-positions-count {:priority 1}, + :area-m2 {:priority 0}, + :lighting-info {:priority 0}, + :rifle-shooting? {:priority 0}, + :year-round-use? {:priority 0}, + :scoreboard? {:priority 0}, + :loudspeakers? {:priority 0}, + :shotgun-shooting? {:priority 0}, + :free-rifle-shooting? {:priority 0}, + :ligthing? {:priority 1}, + :accessibility-info {:priority 0}, + :track-length-m {:priority 1}}}, + 1540 + {:description + {:fi + "Pikaluisteluun varusteltu luistelurata. Radan koko ja pituus lisätään ominaisuustietoihin. Käytössä talvikaudella.", + :se "Bana för hastighetsåkning. Används under vintersäsongen.", + :en "Track size and length specified in properties."}, + :tags {:fi ["luistelurata"]}, + :name + {:fi "Pikaluistelurata", + :se "Bana för hastighetsåkning på skridsko", + :en "Speed-skating track"}, + :type-code 1540, + :main-category 1000, + :status "active", + :sub-category 1500, + :geometry-type "Point", + :props + {:surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :stand-capacity-person {:priority 0}, + :free-use? {:priority 0}, + :track-width-m {:priority 1}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :area-m2 {:priority 0}, + :lighting-info {:priority 0}, + :changing-rooms-m2 {:priority 0}, + :customer-service-point? {:priority 0}, + :ligthing? {:priority 1}, + :school-use? {:priority 0}, + :track-length-m {:priority 1}}}, + 5320 + {:description + {:fi + "Pääasiassa moottoripyöräilyä varten rakennettu, luonnonmukainen ei-asfalttipintainen alue (esim. enduroreitit ja trial-harjoittelualueet maastoliikennealueilla).", + :se "Huvudsakligen för motorcykelsport.", + :en "Mainly for motorcycling."}, + :tags {:fi ["motocross"]}, + :name + {:fi "Moottoripyöräilyalue", + :se "Område för motorcykelsport", + :en "Motorcycling area"}, + :type-code 5320, + :main-category 5000, + :status "active", + :sub-category 5300, + :geometry-type "Point", + :props + {:surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :automated-timing? {:priority 0}, + :stand-capacity-person {:priority 0}, + :free-use? {:priority 0}, + :track-width-m {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :area-m2 {:priority 0}, + :lighting-info {:priority 0}, + :year-round-use? {:priority 0}, + :scoreboard? {:priority 0}, + :loudspeakers? {:priority 0}, + :ligthing? {:priority 0}, + :covered-stand-person-count {:priority 0}, + :track-length-m {:priority 1}}}, + 3210 + {:description + {:fi + "Maauimala tai vesipuisto on ulkona sijaitseva, vedenpuhdistusjärjestelmällä varustettu uintiin tarkoitettu ja hoidettu vesistö tai uima-altaita/allas. Lisäksi kohteessa voi olla vesiliukumäkiä.", + :se "Vattenreningssystem.", + :en "Water treatment system."}, + :tags {:fi ["uima-allas" "ulkoallas" "ulkouima-allas"]}, + :name + {:fi "Maauimala/vesipuisto", :se "Utebassäng", :en "Open-air pool "}, + :type-code 3210, + :main-category 3000, + :status "active", + :sub-category 3200, + :geometry-type "Point", + :props + {:pool-tracks-count {:priority 0}, + :stand-capacity-person {:priority 0}, + :free-use? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :pool-width-m {:priority 0}, + :pool-min-depth-m {:priority 0}, + :toilet? {:priority 0}, + :swimming-pool-count {:priority 1}, + :pool-water-area-m2 {:priority 1}, + :pool-length-m {:priority 0}, + :pool-max-depth-m {:priority 0}, + :loudspeakers? {:priority 0}, + :pool-temperature-c {:priority 0}, + :school-use? {:priority 0}}}, + 4640 + {:description + {:fi + "Hiihdon opetteluun ja harjoitteluun tarkoitettu paikka erityisesti lapsille. Erilaisia harjoittelupaikkoja, kuten latuja, mäkiä ym.", + :se "Träningsplats för skidåkning, teknikhaster mm.", + :en + "Ski training venue, an area of parallel short ski tracks for ski instruction, etc."}, + :tags {:fi []}, + :name + {:fi "Hiihtomaa", :se "Skidland", :en "Cross-country ski park"}, + :type-code 4640, + :main-category 4000, + :status "active", + :sub-category 4600, + :geometry-type "Point", + :props + {:free-use? {:priority 0}, + :ski-service? {:priority 0}, + :ski-track-traditional? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :rest-places-count {:priority 0}, + :lit-route-length-km {:priority 0}, + :scoreboard? {:priority 0}, + :equipment-rental? {:priority 0}, + :loudspeakers? {:priority 0}, + :accessibility-info {:priority 0}, + :ski-track-freestyle? {:priority 0}, + :school-use? {:priority 0}, + :route-length-km {:priority 0}}}, + 1150 + {:description + {:fi + "Rullaluistelua, skeittausta, potkulautailua varten varustettu paikka. Ominaisuustiedoissa tarkemmat tiedot kohteesta.", + :se + "Plats utrustad för rullskridskoåkning, skejtning och sparkcykelåkning.", + :en + "An area equipped for roller-blading, skateboarding, kick scooting."}, + :tags + {:fi ["ramppi" "skeittipaikka" "skeittipuisto" "skeittiparkki"]}, + :name + {:fi "Skeitti-/rullaluistelupaikka", + :se "Plats för skejtning/rullskridskoåkning", + :en "Skateboarding/roller-blading rink "}, + :type-code 1150, + :main-category 1000, + :status "active", + :sub-category 1100, + :geometry-type "Point", + :props + {:area-m2 {:priority 1}, + :surface-material-info {:priority 0}, + :surface-material {:priority 1}, + :ligthing? {:priority 1}, + :school-use? {:priority 0}, + :free-use? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :lighting-info {:priority 0}}}, + 2310 + {:description + {:fi + "Yksittäinen yleisurheilun olosuhde sisätiloissa esim. liikunta- tai monitoimihallin yhteydessä. Suorituspaikat kuvataan lisätiedoissa.", + :se + "Fristående, ej i anslutning till en friidrottshall. I karakteristika anges övningsplatserna.", + :en + "Stand-alone, not in an athletics hall. Venues specified under properties."}, + :tags {:fi ["yleisurheilu" "juoksurata"]}, + :name + {:fi "Yksittäinen yleisurheilun suorituspaikka", + :se "Enstaka övningsplats för friidrott", + :en "Stand-alone athletics venue"}, + :type-code 2310, + :main-category 2000, + :status "active", + :sub-category 2300, + :geometry-type "Point", + :props + {:height-m {:priority 0}, + :surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :free-use? {:priority 0}, + :javelin-throw-places-count {:priority 0}, + :sprint-track-length-m {:priority 0}, + :inner-lane-length-m {:priority 0}, + :discus-throw-places {:priority 0}, + :hammer-throw-places-count {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :polevault-places-count {:priority 0}, + :area-m2 {:priority 0}, + :shotput-count {:priority 0}, + :longjump-places-count {:priority 0}, + :school-use? {:priority 0}, + :highjump-places-count {:priority 0}}}, + 5210 + {:description + {:fi + "Harraste- tai urheiluilmailuun tarkoitettu alue, esim. lentopaikka.", + :se "Flygsportarena, t ex en flygplats.", + :en "Area for air sports, e.g. an airfield."}, + :tags + {:fi + ["lentäminen" + "lento" + "lentokone" + "ilmailu" + "ilmailualue" + "lentokenttä"]}, + :name + {:fi "Urheiluilmailualue", + :se "Område för flygsport", + :en "Sport aviation area"}, + :type-code 5210, + :main-category 5000, + :status "active", + :sub-category 5200, + :geometry-type "Point", + :props + {:track-length-m {:priority 0}, + :area-m2 {:priority 0}, + :surface-material-info {:priority 0}, + :surface-material {:priority 0}, + :track-width-m {:priority 0}, + :free-use? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, + 2380 + {:description + {:fi "Parkouria varten varustettu sisätila.", + :se "Inomhusutrymme utrustat för parkour.", + :en "Indoor space equipped for parkour. "}, + :tags {:fi ["parkour"]}, + :name {:fi "Parkour-sali", :se "Parkoursal", :en "Parkour hall"}, + :type-code 2380, + :main-category 2000, + :status "active", + :sub-category 2300, + :geometry-type "Point", + :props + {:surface-material {:priority 0}, + :surface-material-info {:priority 0}, + :free-use? {:priority 0}, + :parkour-hall-equipment-and-structures {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :area-m2 {:priority 1}, + :highest-obstacle-m {:priority 0}, + :auxiliary-training-area? {:priority 0}, + :school-use? {:priority 0}}}, + 103 + {:description + {:fi + "Voivat sijaita taajaman reunoilla, vyöhykkeittäin taajaman sisällä tai taajaman ulkopuolella. Kohteissa voi olla myös taajamasta lähteviä tai taajamaan palaavia reittejä tai polku- ja reittiverkosto. Kohteet sisältävät vaihtelevaa maastoa ja luonnonmukaisia tai puistomaisia alueita. Kohteet voivat myös sijaita vesialuiden lähellä kuten rannoilla tai saarissa. Kohteiden pääasiallinen käyttö on retkeilyä ja luonnossa virkistäytymistä, mutta niitä voidaan käyttää monipuolisesti erilaisen liikunnan kuten hiihdon, lenkkeilyn tai uinnin harrastamiseen. Kaavamerkintä esim. VR. HUOM! Uusien liikunta- ja ulkoilupaikkojen lisäksi Ulkoilu-/virkistysalueluokka sisältää ennen vuotta 2024 Ulkoilualueet ja Retkeilyalueet tyyppiluokkiin lisätyt olosuhteet", + :se + "Området befinner sig i utkanten av tätorter eller i zoner inom tätorten. På 1-10 kilometers avstånd från bebyggelse. Friluftsområdet används för t.ex. promenader, skidning, joggning, simning. Serverar oftast friluftsaktiviteter för en kommun. Området erbjuder en stor variation av motions möjligheter. Området kan bestå av skog, kärr, åkrar, naturenliga områden och parkliknande delar. Planbeteckning VR.", + :en + "On the edge of population centres or zoned within population centres. 1-10 km from residential areas. Used for e.g. walks, skiing, jogging, swimming. Serves usually recreational needs within one municipality, offers versatile sports facilities. May include forest, swamp, fields, natural areas and park areas. Symbol VR."}, + :tags {:fi ["puisto" "virkistysalue"]}, + :name + {:fi "Ulkoilu-/virkistysalue", + :se "Friluftsområde", + :en "Outdoor area"}, + :type-code 103, + :main-category 0, + :status "active", + :sub-category 1, + :geometry-type "Polygon", + :props + {:may-be-shown-in-excursion-map-fi? {:priority 0}, + :area-km2 {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :water-point {:priority 0}}}, + 201 + {:description + {:fi + "Vapaa-ajankalastukseen sopiva kohde. Kohteessa voi olla palvelurakenteita.", + :se + "Område eller en plats i ett naturligt vattendrag som ställts i ordning för fritidsfiske.", + :en + "Natural aquatic destination equipped and maintained for recreational fishing."}, + :tags {:fi ["kalastusalue" "kalastuspaikka"]}, + :name + {:fi "Kalastuskohde (piste)", + :se "Område eller plats för fiske", + :en "Fishing area/spot "}, + :type-code 201, + :main-category 0, + :status "active", + :sub-category 2, + :geometry-type "Point", + :props + {:toilet? {:priority 0}, + :free-use? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :pier? {:priority 0}, + :customer-service-point? {:priority 0}, + :equipment-rental? {:priority 0}}}, + 1220 + {:description + {:fi + "Hyvin varusteltu yleisurheilukenttä. Yleissurheilukentällä on ratoja ja yleisurheilun suorituspaikkoja. Myös kisakäyttö on mahdollista. Lyhytrataiset (juoksurata alle 400 m) yleisurheilukentät tallennettaan yleisurheilun harjoitusalueeksi. Yleisurheilukentällä sijaitseva jalkapallon tai muun lajin keskeinen suorituspaikka merkitään omaksi liikuntapaikakseen (esim. jalkapallostadion tai pallokenttä). ", + :se + "En plan, banor och träningsplatser för friidrott. Centrum, banor, ytbeläggningar samt träningsplatser med beskrivningar.", + :en + "Field, track and athletic venues/facilities. Centre, tracks, surfaces, venues specified in properties. "}, + :tags + {:fi + ["keihäs" + "keihäänheitto" + "moukari" + "pituushyppy" + "juoksurata" + "kolmiloikka" + "seiväs" + "kuula" + "urheilukenttä"]}, + :name + {:fi "Yleisurheilukenttä", + :se "Friidrottsplan", + :en "Athletics field"}, + :type-code 1220, + :main-category 1000, + :status "active", + :sub-category 1200, + :geometry-type "Point", + :props + {:heating? {:priority 0}, + :surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :automated-timing? {:priority 0}, + :stand-capacity-person {:priority 0}, + :free-use? {:priority 0}, + :sprint-lanes-count {:priority 0}, + :javelin-throw-places-count {:priority 0}, + :finish-line-camera? {:priority 0}, + :field-length-m {:priority 1}, + :circular-lanes-count {:priority 0}, + :match-clock? {:priority 0}, + :sprint-track-length-m {:priority 0}, + :inner-lane-length-m {:priority 0}, + :discus-throw-places {:priority 0}, + :hammer-throw-places-count {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :polevault-places-count {:priority 0}, + :toilet? {:priority 0}, + :running-track-surface-material {:priority 1}, + :area-m2 {:priority 1}, + :field-width-m {:priority 1}, + :lighting-info {:priority 0}, + :scoreboard? {:priority 0}, + :shotput-count {:priority 0}, + :longjump-places-count {:priority 0}, + :loudspeakers? {:priority 0}, + :customer-service-point? {:priority 0}, + :ligthing? {:priority 1}, + :covered-stand-person-count {:priority 0}, + :school-use? {:priority 0}, + :highjump-places-count {:priority 0}, + :training-spot-surface-material {:priority 0}}}, + 4411 + {:description + {:fi + "Maastopyöräilyyn tarkoitettu reitti, joka kulkee vaihtelevassa maastossa ja on merkitty maastoon. Reitti voi hyödyntää muita olemassa olevia ulkoilureittipohjia.", + :se "Led avsedd framför allt för mountainbikar, märkt.", + :en "Marked route intended especially for cross-country biking."}, + :tags {:fi []}, + :name + {:fi "Maastopyöräilyreitti", + :se "Mountainbikeled", + :en "Cross-country biking route"}, + :type-code 4411, + :main-category 4000, + :status "active", + :sub-category 4400, + :geometry-type "LineString", + :props + {:surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :free-use? {:priority 0}, + :may-be-shown-in-excursion-map-fi? {:priority 0}, + :route-width-m {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :rest-places-count {:priority 0}, + :lit-route-length-km {:priority 1}, + :school-use? {:priority 0}, + :route-length-km {:priority 1}}}, + 1140 + {:description + {:fi "Parkouria varten varustettu alue.", + :se "Område utrustat för parkour.", + :en "An area equipped for parkour."}, + :tags {:fi []}, + :name {:fi "Parkour-alue", :se "Parkourområde", :en "Parkour area"}, + :type-code 1140, + :main-category 1000, + :status "active", + :sub-category 1100, + :geometry-type "Point", + :props + {:surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :free-use? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :area-m2 {:priority 1}, + :lighting-info {:priority 0}, + :highest-obstacle-m {:priority 0}, + :ligthing? {:priority 1}, + :climbing-wall? {:priority 0}, + :school-use? {:priority 0}}}, + 4520 + {:description + {:fi + "Hiihtosuunnistukseen soveltuva alue, alueesta hiihtosuunnistuskartta saatavilla.", + :se "Skidorienteringskarta över området, ej för sommarorientering.", + :en + "A ski orienteering map of the area available; no summer orienteering."}, + :tags {:fi []}, + :name + {:fi "Hiihtosuunnistusalue", + :se "Skidorienteringsområde", + :en "Ski orienteering area"}, + :type-code 4520, + :main-category 4000, + :status "deprecated", + :sub-category 4500, + :geometry-type "Polygon", + :props + {:area-km2 {:priority 0}, + :school-use? {:priority 0}, + :free-use? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, + 107 + {:description + {:fi + "Matkailupalvelujen alueet ovat matkailua palveleville toiminnoille varattuja alueita, jotka sisältävät myös sisäiset liikenneväylät ja -alueet, alueen toimintoja varten tarpeelliset palvelut ja virkistysalueet sekä yhdyskuntateknisen huollon alueet. Kohteet voivat toimia myös retkeilyauto- ja pyörämatkailijoiden tauko- ja yöpymispaikkoina. Kaavamerkintä RM.", + :se + "Områden med turisttjänster har reserverats för turist- och semestercentra, semesterbyar, semesterhotell och motsvarande aktörer. De har egna trafikleder och -områden samt områden för egna serviceenheter och egen infrastruktur för aktiviteter. Planbeteckning RM.", + :en + "Area reserved for tourism and holiday centres, holiday villages, hotels, etc., also including internal traffic routes and areas; services and recreational areas needed for operations, as well as technical maintenance areas. Symbol RM."}, + :tags {:fi ["ulkoilualue" "virkistysalue" "leirintäalue"]}, + :name + {:fi "Matkailupalveluiden alue", + :se "Område med turisttjänster", + :en "Tourist services area"}, + :type-code 107, + :main-category 0, + :status "active", + :sub-category 1, + :geometry-type "Polygon", + :props + {:area-km2 {:priority 0}, + :free-use? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}}}, + 6110 + {:description + {:fi "Ratsastukseen varustettu kenttä.", + :se "Bana avsedd för ridning. Storlek i karakteristika.", + :en + "Field reserved for horseback riding. Size specified in properties."}, + :tags {:fi []}, + :name {:fi "Ratsastuskenttä", :se "Ridbana", :en "Equestrian field"}, + :type-code 6110, + :main-category 6000, + :status "active", + :sub-category 6100, + :geometry-type "Point", + :props + {:surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :free-use? {:priority 0}, + :field-length-m {:priority 1}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :show-jumping? {:priority 0}, + :area-m2 {:priority 1}, + :field-width-m {:priority 1}, + :lighting-info {:priority 0}, + :ligthing? {:priority 1}, + :school-use? {:priority 0}}}, + 1120 + {:description + {:fi + "Lähiliikuntapaikka on tarkoitettu päivittäiseen ulkoiluun ja liikuntaan. Se sijaitsee asutuksen läheisyydessä, on pienimuotoinen ja alueelle on vapaa pääsy. Yleensä tarjolla on erilaisia suorituspaikkoja. Suorituspaikat tulee tallentaa omiksi liikuntapaikoikseen (esim. pallokenttä, ulkokuntosali tai parkour-alue). Lähiliikuntapaikka voi olla myös koulun tai päiväkodin piha, jos liikuntapaikan käyttö on mahdollista kouluajan ulkopuolella.", + :se + "Ett näridrottsområde är avsett för daglig utomhusaktivitet och motion. Det ligger nära bostadsområden, är småskaligt och har fri tillgång. Vanligtvis erbjuds olika aktivitetsplatser. Aktivitetsplatserna bör registreras som egna idrottsplatser (t.ex. bollplan, utomhusgym eller parkourområde). Ett näridrottsområde kan också vara en skolgård eller en daghemsgård om idrottsplatsen kan användas utanför skoltid.", + :en + "A local sports facility is intended for daily outdoor activities and exercise. It is located near residential areas, is small-scale, and has free access. Usually, various activity sites are available. Activity sites should be recorded as individual sports facilities (e.g., ball field, outdoor gym, or parkour area). A local sports facility can also be a school or daycare yard if the sports facility can be used outside school hours."}, + :tags + {:fi + ["ässäkenttä" "monitoimikenttä" "monitoimikaukalo" "lähipuisto"]}, + :name + {:fi "Lähiliikuntapaikka", + :se "Näridrottsplats", + :en "Neighbourhood sports area"}, + :type-code 1120, + :main-category 1000, + :status "active", + :sub-category 1100, + :geometry-type "Point", + :props + {:surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :fields-count {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :ice-rinks-count {:priority 0}, + :area-m2 {:priority 1}, + :lighting-info {:priority 0}, + :ligthing? {:priority 1}, + :accessibility-info {:priority 0}, + :playground? {:priority 0}, + :school-use? {:priority 0}, + :exercise-machines-count {:priority 0}}}, + 1390 + {:description + {:fi + "Padelin pelaamiseen tarkoitettu kenttä ulkona. Pintamateriaali hiekkatekonurmi. Lajivaatimusten mukaiset seinät. Voi olla myös katettu.", + :se + "En utomhusbana avsedd för padelspel. Underlagsmaterialet är sandkonstgräs. Väggar enligt sportens krav. Kan även vara täckt.", + :en + "An outdoor court intended for playing padel. The surface material is sand artificial grass. Walls meet the sport's requirements. It can also be covered."}, + :tags {:fi ["padel" "padel-kenttä"]}, + :name + {:fi "Padelkenttä", + :se "Område med padelbanor", + :en "Padel court area"}, + :type-code 1390, + :main-category 1000, + :status "active", + :sub-category 1300, + :geometry-type "Point", + :props + {:surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :free-use? {:priority 0}, + :field-length-m {:priority 1}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :area-m2 {:priority 1}, + :field-width-m {:priority 1}, + :lighting-info {:priority 0}, + :water-point {:priority 0}, + :ligthing? {:priority 1}, + :school-use? {:priority 0}, + :light-roof? {:priority 0}}}, + 5340 + {:description + {:fi "Pääasiallisesti kartingajoon tai supermotoon käytetty rata.", + :se "Huvudsakligen för karting.", + :en "Mainly for karting."}, + :tags {:fi []}, + :name {:fi "Karting-rata", :se "Kartingbana", :en "Kart circuit"}, + :type-code 5340, + :main-category 5000, + :status "active", + :sub-category 5300, + :geometry-type "Point", + :props + {:surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :automated-timing? {:priority 0}, + :free-use? {:priority 0}, + :track-width-m {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :area-m2 {:priority 0}, + :lighting-info {:priority 0}, + :year-round-use? {:priority 0}, + :ligthing? {:priority 0}, + :track-length-m {:priority 1}}}, + 302 + {:description + {:fi + "Autiotupa, varaustupa, taukotupa, päivätupa. Yöpymis- ja levähdyspaikka retkeilijöille. Autiotupa avoin, varaustupa lukittu ja maksullinen. Päivätupa päiväkäyttöön.", + :se + "Övernattningsstuga, reserveringsstuga, raststuga, dagstuga. Övernattnings- och rastplats för vandrare. Övernattningsstugan öppen, reserveringsstugan låst och avgiftsbelagd. Dagstuga för bruk under dagen.", + :en + "Open hut, reservable hut, rest hut, day hut. Overnight resting place for hikers. An open hut is freely available; a reservable hut locked and subject to a charge. A day hut is for daytime use."}, + :tags {:fi ["taukopaikka"]}, + :name {:fi "Tupa", :se "Stuga", :en "Hut"}, + :type-code 302, + :main-category 0, + :status "active", + :sub-category 2, + :geometry-type "Point", + :props + {:may-be-shown-in-excursion-map-fi? {:priority 0}, + :toilet? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :water-point {:priority 0}, + :free-use? {:priority 0}}}, + 4405 + {:description + {:fi + "Maastossa oleva retkeilyreitti, yleensä kauempana asutuksesta. Reitin varrella retkeilyn palveluita, esim. laavuja.", + :se + "Utflyktsled i terrängen, oftast längre borta från bebyggelse. Längs rutten friluftstjänster, t ex vindskydd.", + :en + "Natural hiking route, usually further away from residential areas. Provides hiking facilities, e.g. lean-to structures."}, + :tags {:fi ["retkeily" "vaellus" "vaelluspolku"]}, + :name {:fi "Retkeilyreitti", :se "Utflyktsled", :en "Hiking route"}, + :type-code 4405, + :main-category 4000, + :status "active", + :sub-category 4400, + :geometry-type "LineString", + :props + {:surface-material {:priority 0}, + :surface-material-info {:priority 0}, + :free-use? {:priority 0}, + :may-be-shown-in-excursion-map-fi? {:priority 0}, + :route-width-m {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :rest-places-count {:priority 0}, + :lit-route-length-km {:priority 1}, + :accessibility-info {:priority 0}, + :route-length-km {:priority 1}}}, + 6120 + {:description + {:fi "Kylmä tai lämmin katettu tila ratsastukseen.", + :se "Kallt eller varmt takförsett utrymme för ridning.", + :en "Cold or warm, covered space for horseback riding."}, + :tags {:fi ["ratsastushalli" "maneesi"]}, + :name {:fi "Ratsastusmaneesi", :se "Ridmanege", :en "Riding manège"}, + :type-code 6120, + :main-category 6000, + :status "active", + :sub-category 6100, + :geometry-type "Point", + :props + {:heating? {:priority 0}, + :surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :stand-capacity-person {:priority 0}, + :free-use? {:priority 0}, + :field-length-m {:priority 1}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :show-jumping? {:priority 0}, + :area-m2 {:priority 1}, + :field-width-m {:priority 1}, + :lighting-info {:priority 0}, + :school-use? {:priority 0}}}, + 4407 + {:description + {:fi + "Asfaltoitu rullahiihtoon lumettomana aikana tarkoitettu reitti. Reitti kulkee maastossa, ja sen käyttöä muilla kulkutavoilla on rajoitettu.", + :se + "En asfalterad bana avsedd för rullskidåkning under snöfria perioder. Banan går genom terrängen och användningen av andra färdsätt är begränsad.", + :en + "An asphalt track intended for roller skiing during snow-free periods. The track runs through terrain, and the use of other modes of travel is restricted."}, + :tags + {:fi ["rullahiihto"], :se ["rullskidåkning"], :en ["roller skiing"]}, + :name + {:fi "Rullahiihtorata", :se "Rullskidbana", :en "Roller Ski Track"}, + :type-code 4407, + :main-category 4000, + :status "active", + :sub-category 4400, + :geometry-type "LineString", + :props + {:surface-material {:priority 0}, + :surface-material-info {:priority 0}, + :outdoor-exercise-machines? {:priority 0}, + :free-use {:priority 0}, + :route-width-m {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :rest-places-count {:priority 0}, + :lit-route-length-km {:priority 0}, + :route-length-km {:priority 0}}}, + 1310 + {:description + {:fi + "Koripalloon varustettu kenttä, kiinteät tai siirrettävät koritelineet. Minikenttä ja yhden korin kenttä lisätiedoissa.", + :se + "Plan utrustad för basket med fasta eller flyttbara ställningar. Miniplan och enkorgsplan i tilläggsupgifter.", + :en + "A field equipped for basketball, with fixed or movable apparatus. 'Mini-court' and 'one-basket court' included in additional information. "}, + :tags {:fi []}, + :name + {:fi "Koripallokenttä", :se "Basketplan", :en "Basketball court"}, + :type-code 1310, + :main-category 1000, + :status "active", + :sub-category 1300, + :geometry-type "Point", + :props + {:surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :height-of-basket-or-net-adjustable? {:priority 0}, + :free-use? {:priority 0}, + :field-length-m {:priority 1}, + :match-clock? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :area-m2 {:priority 1}, + :field-width-m {:priority 1}, + :lighting-info {:priority 0}, + :scoreboard? {:priority 0}, + :water-point {:priority 0}, + :ligthing? {:priority 1}, + :basketball-field-type {:priority 0}, + :school-use? {:priority 0}}}, + 202 + {:description + {:fi "Telttailualue tai muu leiriytymiseen osoitettu paikka.", + :se "Tältplats eller annat område ordnat för tältning.", + :en "Camping site for tents or other encampment. "}, + :tags + {:fi ["yöpyminen" "taukopaikka" "telttapaikka" "leirintäalue"]}, + :name + {:fi "Telttailu ja leiriytyminen", + :se "Tältning och läger", + :en "Camping"}, + :type-code 202, + :main-category 0, + :status "active", + :sub-category 2, + :geometry-type "Point", + :props + {:toilet? {:priority 0}, + :may-be-shown-in-excursion-map-fi? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :water-point {:priority 0}, + :free-use? {:priority 0}}}, + 1190 + {:description + {:fi + "Yleinen mäenlaskuun esimerkiksi pulkalla tai liukurilla tarkoitettu mäki. Kohde on ylläpidetty ja hoidettu, ja se voi muodostua luonnon mäestä tai rakennetuista kumpareista.", + :se + "En allmän backe avsedd för åkning med till exempel pulka eller stjärtlapp. Backen är underhållen och skött och kan bestå av en naturlig backe eller konstruerade högar.", + :en + "A common hill intended for sledding with, for example, a sled or a slider. The hill is maintained and taken care of, and it can consist of a natural hill or constructed mounds."}, + :tags {:fi ["pulkkailu" "pulkka" "mäenlasku"]}, + :name {:fi "Pulkkamäki", :se "Pulkabacke", :en "Sledding hill"}, + :type-code 1190, + :main-category 1000, + :status "active", + :sub-category 1100, + :geometry-type "Point", + :props + {:ligthing? {:priority 0}, + :school-use? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :lighting-info {:priority 0}}}, + 1620 + {:description + {:fi + "Ensisijaisesti golfin pelaamiseen tarkoitettu alue kesäkaudella. Reikien määrä merkitään lisätietoihin.", + :se "Officiell golfbana. Antalet hål anges i karakteristika.", + :en + "Official golf course. Number of holes included in properties."}, + :tags {:fi ["greeni" "puttialue" "range"]}, + :name {:fi "Golfkenttä (piste)", :se "Golfbana", :en "Golf course"}, + :type-code 1620, + :main-category 1000, + :status "active", + :sub-category 1600, + :geometry-type "Point", + :props + {:holes-count {:priority 1}, + :free-use? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :lighting-info {:priority 0}, + :customer-service-point? {:priority 0}, + :green? {:priority 0}, + :ligthing? {:priority 1}, + :school-use? {:priority 0}, + :range? {:priority 0}}}, + 2250 + {:description + {:fi + "Ensisijaisesti skeittausta varten varustettu halli. Hallia voidaan käyttää bmx-pyöräilyn tai muiden soveltuvien lajien harrastamiseen.", + :se + "Hall utrustad för skejtning, rullskridskoåkning, bmx-åkning osv.", + :en "An area for skateboarding, roller-blading, BMX biking, etc."}, + :tags {:fi ["ramppi"]}, + :name + {:fi "Skeittihalli", :se "Skateboardhall", :en "Indoor skatepark"}, + :type-code 2250, + :main-category 2000, + :status "active", + :sub-category 2200, + :geometry-type "Point", + :props + {:height-m {:priority 0}, + :surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :free-use? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :area-m2 {:priority 1}, + :scoreboard? {:priority 0}, + :customer-service-point? {:priority 0}, + :school-use? {:priority 0}}}, + 2530 + {:description + {:fi "Pikaluisteluun tarkoitettu halli.", + :se + "Hall avsedd för hastighetsåkning på skridsko. Storlek > 333 1/3 m.", + :en "Hall intended for speed-skating. Size > 333.3 m."}, + :tags {:fi ["jäähalli"]}, + :name + {:fi "Pikaluisteluhalli", + :se "Skridskohall", + :en "Speed-skating hall"}, + :type-code 2530, + :main-category 2000, + :status "active", + :sub-category 2500, + :geometry-type "Point", + :props + {:field-2-area-m2 {:priority 0}, + :surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :field-3-length-m {:priority 0}, + :field-2-length-m {:priority 0}, + :automated-timing? {:priority 0}, + :stand-capacity-person {:priority 0}, + :free-use? {:priority 0}, + :field-1-length-m {:priority 0}, + :finish-line-camera? {:priority 0}, + :match-clock? {:priority 0}, + :field-1-width-m {:priority 0}, + :field-3-width-m {:priority 0}, + :field-2-width-m {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :ice-rinks-count {:priority 1}, + :field-1-area-m2 {:priority 0}, + :toilet? {:priority 0}, + :area-m2 {:priority 1}, + :scoreboard? {:priority 0}, + :auxiliary-training-area? {:priority 0}, + :loudspeakers? {:priority 0}, + :field-3-area-m2 {:priority 0}, + :school-use? {:priority 0}}}, + 112 + {:description + {:fi + "Muut luonnonsuojelualueet kuin kansallispuistot. Tietoja kerätään vain sellaisilta luonnonsuojelualueilta ja luonnonpuistoilta, joiden virkistyskäyttö on mahdollista. Esim. kunta- tai yksityisomisteisille maille perustetut suojelualueet. Kaavamerkintä S, SL.", + :se + "Andra naturskyddsområden än nationalparker och naturparker. Endast de naturskyddsområden där friluftsanvändning är möjlig. T ex skyddsområden som grundats på kommunal eller privat mark. Planbeteckning S, SL.", + :en + "Nature conservation areas other than national parks and natural parks. Only nature conservation areas with opportunities for recreation. E.g. protection areas established on municipal and private land. Symbol S, SL."}, + :tags {:fi ["virkistysalue"]}, + :name + {:fi "Muu luonnonsuojelualue, jolla on virkistyspalveluita", + :se "Annat naturskyddsområde med rekreationstjänster", + :en "Other nature conservation area with recreational services"}, + :type-code 112, + :main-category 0, + :status "active", + :sub-category 1, + :geometry-type "Polygon", + :props + {:may-be-shown-in-excursion-map-fi? {:priority 0}, + :area-km2 {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, + 2130 + {:description + {:fi + "Painonnostoon tai toiminnalliseen voimaharjoitteluun varustettu kuntoilutila tai voimailusali. Esimerkiksi crossfit- ja painonnostosalit.", + :se + "Utrustad för tyngdlyftning och boxning. Storleken anges i karakteristika.", + :en + "Equipped for weightlifting and boxing. Size specified in properties."}, + :tags {:fi ["kuntosali" "kuntoilu" "painonnosto" "voimanosto"]}, + :name + {:fi "Voimailusali", + :se "Styrketräningssal", + :en "Weight training hall "}, + :type-code 2130, + :main-category 2000, + :status "active", + :sub-category 2100, + :geometry-type "Point", + :props + {:surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :free-customer-use? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :group-exercise-rooms-count {:priority 0}, + :tatamis-count {:priority 0}, + :area-m2 {:priority 1}, + :wrestling-mats-count {:priority 0}, + :boxing-rings-count {:priority 0}, + :weight-lifting-spots-count {:priority 0}, + :customer-service-point? {:priority 0}, + :school-use? {:priority 0}, + :exercise-machines-count {:priority 0}}}, + 4406 + {:description + {:fi + "Talvisin tai ympärivuotisesti käytössä oleva maastoreitti, joka soveltuu usealle kulkutavalle (esim. jalan, lumikengille, läskipyörälle). Lisätietoihin merkitään, jos reitti on ympärivuotisessa käytössä ja mahdolliset kulkutavat.", + :se + "En terrängled som används på vintern eller året runt och som är lämplig för flera färdsätt (t.ex. till fots, med snöskor, fatbike). Ytterligare information anger om leden är i bruk året runt och möjliga färdsätt.", + :en + "A terrain trail used in winter or year-round, suitable for multiple modes of travel (e.g., on foot, with snowshoes, fat bike). Additional information indicates if the trail is in year-round use and possible modes of travel."}, + :tags + {:fi ["yhteiskäyttöreitti" "talvipolku"], + :se ["gemensam led" "vinterstig"], + :en ["shared trail" "winter path"]}, + :name + {:fi "Monikäyttöreitti", + :se "Multianvändningsled", + :en "Multi-use Trail"}, + :type-code 4406, + :main-category 4000, + :status "active", + :sub-category 4400, + :geometry-type "LineString", + :props + {:surface-material {:priority 0}, + :surface-material-info {:priority 0}, + :travel-mode-info {:priority 0}, + :route-width-m {:priority 0}, + :toilet? {:priority 0}, + :rest-places-count {:priority 0}, + :lit-route-length-km {:priority 0}, + :travel-modes {:priority 0}, + :year-round-use? {:priority 0}, + :route-length-km {:priority 0}}}, + 3220 + {:description + {:fi + "Yleinen uimaranta, EU-uimaranta. Pelastusväline ja ilmoitustaulu, jäteastia ja käymälä. Veden laadun seuranta ja alueen hoito järjestetty.", + :se + "Allmän badstrand, EU badstrand. Räddningsutrustning, en anslagstavla samt ett sopkärl och en toalett finns. Kvaliteten på vattnet följs upp och området underhålls.", + :en + "Public beach, EU bathing beach. Rescue equipment, a notice board, a waste bin, and a toilet are available. The quality of the water is monitored and the area is maintained."}, + :tags {:fi ["uimapaikka"]}, + :name {:fi "Uimaranta", :se "Badstrand", :en "Public beach"}, + :type-code 3220, + :main-category 3000, + :status "active", + :sub-category 3200, + :geometry-type "Point", + :props + {:free-use? {:priority 0}, + :pier? {:priority 0}, + :may-be-shown-in-excursion-map-fi? {:priority 0}, + :beach-length-m {:priority 1}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :shower? {:priority 0}, + :changing-rooms? {:priority 0}, + :sauna? {:priority 0}, + :other-platforms? {:priority 0}, + :school-use? {:priority 0}}}, + 5330 + {:description + {:fi + "Suuri rata-autoiluun tai moottoripyöräilyyn tarkoitettu asfaltoitu moottoriurheilupaikka.", + :se "Stor motorsportplats avsedd för bankörning.", + :en "Large motor sports venue for formula racing."}, + :tags {:fi ["autourheilu"]}, + :name + {:fi "Moottorirata", :se "Motorbana", :en "Formula race track"}, + :type-code 5330, + :main-category 5000, + :status "active", + :sub-category 5300, + :geometry-type "Point", + :props + {:surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :automated-timing? {:priority 0}, + :stand-capacity-person {:priority 0}, + :free-use? {:priority 0}, + :finish-line-camera? {:priority 0}, + :track-width-m {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :lighting-info {:priority 0}, + :year-round-use? {:priority 0}, + :scoreboard? {:priority 0}, + :loudspeakers? {:priority 0}, + :ligthing? {:priority 0}, + :track-length-m {:priority 1}}}, + 4230 + {:description + {:fi "Lumilautailua varten rakennettu halli.", + :se + "Tunnel avsedd för snowboardåkning. Olika användningsmöjligheter i tilläggsinformation.", + :en + "Tunnel intended for snowboarding. Different uses specified in additional information."}, + :tags {:fi ["laskettelu"]}, + :name + {:fi "Lumilautatunneli", + :se "Snowboardtunnel", + :en "Snowboarding tunnel"}, + :type-code 4230, + :main-category 4000, + :status "active", + :sub-category 4200, + :geometry-type "Point", + :props + {:height-m {:priority 0}, + :surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :free-use? {:priority 0}, + :ski-service? {:priority 0}, + :altitude-difference {:priority 1}, + :route-width-m {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :area-m2 {:priority 0}, + :equipment-rental? {:priority 0}, + :route-length-km {:priority 1}}}, + 4320 + {:description + {:fi + "Mäkihyppyyn soveltuva mäki, vauhtimäessä on jää-, keramiikka- tai muovilatu. Mäen koko, materiaalit ja mahdollinen kesäkäyttö kuvataan lisätiedoissa.", + :se + "Is-, keramik- eller plastspår. K-punkt samt sommar- och vinteranvändning i karakteristika. Minimikrav: en liten backe med k-punkt på 75 m eller mera.", + :en + "Ice, ceramic or plastic track. Summer and winter use specified in attributes, along with K point, etc. Minimum normal hill, K point minimum 75 m."}, + :tags {:fi ["mäkihyppy" "hyppyri"]}, + :name {:fi "Hyppyrimäki", :se "Hoppbacke", :en "Ski jumping hill"}, + :type-code 4320, + :main-category 4000, + :status "active", + :sub-category 4300, + :geometry-type "Point", + :props + {:skijump-hill-type {:priority 1}, + :lifts-count {:priority 0}, + :plastic-outrun? {:priority 0}, + :free-use? {:priority 0}, + :ski-service? {:priority 0}, + :skijump-hill-material {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :hs-point {:priority 0}, + :k-point {:priority 1}, + :toilet? {:priority 0}, + :changing-rooms? {:priority 0}, + :year-round-use? {:priority 0}, + :changing-rooms-m2 {:priority 0}, + :jumps-count {:priority 0}, + :inruns-material {:priority 0}}}, + 3130 + {:description + {:fi + "Monipuolinen uimala kuntoutus-, virkistys- tai hyvinvointipalveluilla. Vesipinta-ala ja allasmäärät/tyypit ominaisuuksiin.", + :se + "Mångsidig badinrättning med rehabiliterings- och rekreationstjänster. Vattenareal samt antal och typ av bassänger i karakteristika.", + :en + "Versatile spa with rehabilitation or wellness services. Water volume and number/types of pools specified in properties."}, + :tags {:fi []}, + :name {:fi "Kylpylä", :se "Badinrättning", :en "Spa"}, + :type-code 3130, + :main-category 3000, + :status "active", + :sub-category 3100, + :geometry-type "Point", + :props + {:free-use? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :area-m2 {:priority 1}, + :swimming-pool-count {:priority 1}, + :pool-water-area-m2 {:priority 1}, + :accessibility-info {:priority 0}, + :school-use? {:priority 0}}}, + 3110 + {:description + {:fi + "Halli, jossa on yksi tai useampia uima-altaita. Altaiden määrä ja vesipinta-ala kysytään ominaisuustiedoissa.", + :se + "Hall med en eller flera simbassänger. Antalet bassänger och vattenareal anges i karakteristika.", + :en + "Hall with one or several swimming pools. Number of pools and water surface area is requested in properties."}, + :tags {:fi []}, + :name + {:fi "Uimahalli", :se "Simhall", :en "Public indoor swimming pool"}, + :type-code 3110, + :main-category 3000, + :status "active", + :sub-category 3100, + :geometry-type "Point", + :props + {:automated-timing? {:priority 0}, + :stand-capacity-person {:priority 0}, + :free-use? {:priority 0}, + :finish-line-camera? {:priority 0}, + :match-clock? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :area-m2 {:priority 1}, + :swimming-pool-count {:priority 1}, + :pool-water-area-m2 {:priority 1}, + :scoreboard? {:priority 0}, + :loudspeakers? {:priority 0}, + :accessibility-info {:priority 0}, + :school-use? {:priority 0}}}, + 203 + {:description + {:fi + "Kohteessa on veneilyyn liittyviä palveluita kuten säilytysmahdollisuus, vesillelaskupaikka tai veneen kiinnitysmahdollisuus. Kohteelle määritetään venesatamaluokka, jonka palveluvarustus kuvataan lisätiedoissa. Jos kyse on melontalaiturista, se kirjataan kyseisen laituriluokan alle. Kohde tulee merkitä tärkeimmän laiturin läheisyyteen, jos sellainen kohteessa on.", + :se "Tjänster för båtfarare. Precisering i karakteristika.", + :en "Facilities related to boating. Specififed in 'attributes'."}, + :tags {:fi ["satama" "laituri"]}, + :name + {:fi "Veneilyn palvelupaikka", + :se "Serviceplats för båtfarare", + :en "Boating services"}, + :type-code 203, + :main-category 0, + :status "active", + :sub-category 2, + :geometry-type "Point", + :props + {:free-use? {:priority 0}, + :pier? {:priority 0}, + :may-be-shown-in-excursion-map-fi? {:priority 0}, + :boat-launching-spot? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :boating-service-class {:priority 1}, + :customer-service-point? {:priority 0}, + :water-point {:priority 0}, + :accessibility-info {:priority 0}}}, + 4620 + {:description + {:fi + "Vähintään kansallisen tason kilpailujen järjestämiseen soveltuva ampumahiihtokeskus. Ampumahiihtokeskuksessa useita ampumapaikkoja ja latuverkosto.", + :se "Tillräckligt stort för åtminstone nationella tävlingar.", + :en "For minimum national level competitions."}, + :tags {:fi ["ampumapaikka"]}, + :name + {:fi "Ampumahiihtokeskus", + :se "Skidskyttecentrum", + :en "Biathlon centre"}, + :type-code 4620, + :main-category 4000, + :status "active", + :sub-category 4600, + :geometry-type "Point", + :props + {:stand-capacity-person {:priority 0}, + :free-use? {:priority 0}, + :ski-service? {:priority 0}, + :finish-line-camera? {:priority 0}, + :ski-track-traditional? {:priority 0}, + :route-width-m {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :shower? {:priority 0}, + :rest-places-count {:priority 0}, + :changing-rooms? {:priority 0}, + :shooting-positions-count {:priority 1}, + :lit-route-length-km {:priority 0}, + :year-round-use? {:priority 0}, + :scoreboard? {:priority 0}, + :sauna? {:priority 0}, + :loudspeakers? {:priority 0}, + :accessibility-info {:priority 0}, + :ski-track-freestyle? {:priority 0}, + :route-length-km {:priority 0}}}, + 5360 + {:description + {:fi + "Pääasiallisesti jokamiesajoa, rallicrossia tai moottoripyöräilyä varten.", + :se "Huvudsakligen för allemanskörning och/eller rallycross.", + :en "Mainly for everyman racing and/or rallycross."}, + :tags {:fi []}, + :name + {:fi "Jokamies- ja rallicross-rata", + :se "Allemans- och rallycrossbana", + :en "Everyman racing and rallycross track "}, + :type-code 5360, + :main-category 5000, + :status "active", + :sub-category 5300, + :geometry-type "Point", + :props + {:surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :automated-timing? {:priority 0}, + :stand-capacity-person {:priority 0}, + :free-use? {:priority 0}, + :finish-line-camera? {:priority 0}, + :track-width-m {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :area-m2 {:priority 0}, + :lighting-info {:priority 0}, + :year-round-use? {:priority 0}, + :scoreboard? {:priority 0}, + :loudspeakers? {:priority 0}, + :ligthing? {:priority 0}, + :covered-stand-person-count {:priority 0}, + :track-length-m {:priority 1}}}, + 2290 + {:description + {:fi "Petanque-peliin tarkoitettu halli.", + :se + "Hall avsedd för petanque. Storlek, antalet planer och utrustning i karakteristika.", + :en "Hall intended for petanque."}, + :tags {:fi ["petankki"]}, + :name + {:fi "Petanque-halli", :se "Petanquehall", :en "Petanque hall"}, + :type-code 2290, + :main-category 2000, + :status "active", + :sub-category 2200, + :geometry-type "Point", + :props + {:height-m {:priority 0}, + :surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :free-use? {:priority 0}, + :fields-count {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :area-m2 {:priority 1}, + :scoreboard? {:priority 0}, + :customer-service-point? {:priority 0}, + :school-use? {:priority 0}}}, + 2260 + {:description + {:fi + "Ensisijaisesti sulkapallon pelaamiseen tarkoitettu halli. Vapaa korkeus ilmoitetaan lisätiedoissa.", + :se "Hall i första hand avsedd för badminton.", + :en "Hall intended primarily for badminton."}, + :tags {:fi []}, + :name + {:fi "Sulkapallohalli", :se "Badmintonhall", :en "Badminton hall"}, + :type-code 2260, + :main-category 2000, + :status "active", + :sub-category 2200, + :geometry-type "Point", + :props + {:height-m {:priority 1}, + :surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :stand-capacity-person {:priority 0}, + :free-use? {:priority 0}, + :tennis-courts-count {:priority 0}, + :field-length-m {:priority 0}, + :badminton-courts-count {:priority 1}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :padel-courts-count {:priority 0}, + :toilet? {:priority 0}, + :area-m2 {:priority 1}, + :field-width-m {:priority 0}, + :scoreboard? {:priority 0}, + :floorball-fields-count {:priority 0}, + :squash-courts-count {:priority 0}, + :customer-service-point? {:priority 0}, + :volleyball-fields-count {:priority 0}, + :school-use? {:priority 0}}}, + 1160 + {:description + {:fi + "Pyöräilyä ja temppuilua varten varattu alue, esim. bmx-, pump track- tai dirt-pyöräilyalue.", + :se "Ett område avsett för cykling och trick, till exempel BMX-, pump track- eller dirtcyklingsområde.", + :en "An area designated for cycling and stunts, such as a BMX, pump track, or dirt biking area."}, + :tags {:fi ["pumptrack" "bmx" "pump" "track"]}, + :name + {:fi "Pyöräilyalue", :se "Cykelåkningsområde", :en "Cycling area"}, + :type-code 1160, + :main-category 1000, + :status "active", + :sub-category 1100, + :geometry-type "Point", + :props + {:surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :stand-capacity-person {:priority 0}, + :free-use? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :area-m2 {:priority 1}, + :lighting-info {:priority 0}, + :customer-service-point? {:priority 0}, + :ligthing? {:priority 1}, + :accessibility-info {:priority 0}, + :covered-stand-person-count {:priority 0}, + :school-use? {:priority 0}}}, + 1210 + {:description + {:fi + "Yleisurheilun harjoitusalueeksi merkitään kohde, jossa on yleisurheilun harjoitteluun soveltuvia suorituspaikkoja, esim. kenttä, ratoja tai eri lajien suorituspaikkoja, mutta ei virallisen yleisurheilukentän kaikkia suorituspaikkoja. Lyhytrataiset (juoksurata alle 400 m) yleisurheilukentät tallennetaan yleisurheilun harjoitusalueeksi.", + :se + "Ett område för friidrottsträning markeras där det finns anläggningar som är lämpliga för friidrottsträning, till exempel en plan, banor eller platser för olika grenar, men inte alla anläggningar för en officiell friidrottsarena. Kortbaniga friidrottsarenor (löparbana under 400 m) registreras som friidrottsträningsområden.", + :en + "An athletics training area is designated for locations with facilities suitable for athletics training, such as a field, tracks, or various event areas, but not all facilities of an official athletics stadium. Short track athletics fields (running track under 400 m) are recorded as athletics training areas."}, + :tags + {:fi + ["keihäs" + "keihäänheitto" + "moukari" + "pituushyppy" + "juoksurata" + "kolmiloikka" + "seiväs" + "kuula" + "urheilukenttä" + "yleisurheilukenttä"]}, + :name + {:fi "Yleisurheilun harjoitusalue", + :se "Träningsområde för friidrott", + :en "Athletics training area"}, + :type-code 1210, + :main-category 1000, + :status "active", + :sub-category 1200, + :geometry-type "Point", + :props + {:heating? {:priority 0}, + :surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :free-use? {:priority 0}, + :sprint-lanes-count {:priority 0}, + :javelin-throw-places-count {:priority 0}, + :field-length-m {:priority 0}, + :circular-lanes-count {:priority 0}, + :sprint-track-length-m {:priority 0}, + :inner-lane-length-m {:priority 0}, + :discus-throw-places {:priority 0}, + :hammer-throw-places-count {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :polevault-places-count {:priority 0}, + :toilet? {:priority 0}, + :running-track-surface-material {:priority 0}, + :area-m2 {:priority 1}, + :field-width-m {:priority 0}, + :lighting-info {:priority 0}, + :shotput-count {:priority 0}, + :longjump-places-count {:priority 0}, + :ligthing? {:priority 1}, + :school-use? {:priority 0}, + :highjump-places-count {:priority 0}, + :training-spot-surface-material {:priority 0}}}, + 5140 + {:description + {:fi + "Rakennettu pysyvästi vesihiihdolle. Vesihiihtoalueella on laituri.", + :se "Byggt för vattenskidåkning, permanent. Minimikrav: brygga.", + :en + "Permanent construction for water skiing. Minimum equipment pier."}, + :tags {:fi []}, + :name + {:fi "Vesihiihtoalue", + :se "Område för vattenskidåkning", + :en "Water ski area"}, + :type-code 5140, + :main-category 5000, + :status "active", + :sub-category 5100, + :geometry-type "Point", + :props + {:pier? {:priority 0}, + :area-km2 {:priority 0}, + :free-use? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, + 4310 + {:description + {:fi + "Mäkihypyn harjoitteluun rakennettu mäki. K-piste ominaisuustietoihin, materiaalit, kesä- ja talvikäyttö ominaisuuksiin. ", + :se + "K-punkt, material samt sommar- och vinteranvändning i karakteristika.", + :en + "K point in properties; materials, summer and winter use specified in attributes. "}, + :tags {:fi ["mäkihyppy" "hyppyri" "hyppyrimäki"]}, + :name + {:fi "Harjoitushyppyrimäki", + :se "Träningshoppbacke", + :en "Ski jumping hill for training"}, + :type-code 4310, + :main-category 4000, + :status "deprecated", + :sub-category 4300, + :geometry-type "Point", + :props + {:skijump-hill-type {:priority 1}, + :lifts-count {:priority 0}, + :plastic-outrun? {:priority 0}, + :free-use? {:priority 0}, + :ski-service? {:priority 0}, + :skijump-hill-material {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :k-point {:priority 1}, + :toilet? {:priority 0}, + :year-round-use? {:priority 0}, + :p-point {:priority 0}, + :inruns-material {:priority 0}, + :school-use? {:priority 0}}}, + 207 + {:description + {:fi + "Opastuspiste on ulkoilureitin, virkistysalueen tai muun liikuntapaikan yhteydessä oleva lisätieto. Paikassa voi olla esimerkiksi opastustaulu ja kartta tai laajempi palvelupiste. Opastuspiste-merkintää voidaan käyttää myös ilmoittamaan reitin lähtöpisteen.", + :se + "En informationspunkt är en extra information vid en friluftsled, ett rekreationsområde eller en annan idrottsplats. På platsen kan det till exempel finnas en informationstavla och karta eller en mer omfattande servicestation. Informationspunkt-markeringen kan också användas för att ange startpunkten för en rutt.", + :en + "An information point is additional information associated with an outdoor trail, recreational area, or other sports facility. The location may include, for example, an information board and map or a more extensive service point. The information point marking can also be used to indicate the starting point of a route."}, + :tags {:fi ["info" "opastaulu" "infopiste"]}, + :name {:fi "Opastuspiste", :se "Informationspunkt", :en "Info"}, + :type-code 207, + :main-category 0, + :status "deprecated", + :sub-category 2, + :geometry-type "Point", + :props + {:parking-place? {:priority 0}, + :may-be-shown-in-excursion-map-fi? {:priority 0}, + :toilet? {:priority 0}, + :school-use? {:priority 0}, + :free-use? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, + 1130 + {:description + {:fi + "Ulkokuntoilupaikka on esimerkiksi kuntoilulaitteita, voimailulaitteita tai kuntoportaat sisältävä liikuntapaikka. Kohde voi olla osa liikuntapuistoa, liikuntareitin varrella oleva kuntoilupaikka tai ns. ulkokuntosali.", + :se + "En utomhusträningsplats är en idrottsplats som innehåller till exempel träningsutrustning, styrketräningsutrustning eller träningsstegar. Platsen kan vara en del av en idrottspark, en träningsplats längs en motionsslinga eller en så kallad utomhusgym.", + :en + "An outdoor fitness area is a sports facility that includes, for example, exercise equipment, strength training equipment, or fitness stairs. The location can be part of a sports park, a fitness spot along a trail, or a so-called outdoor gym"}, + :tags + {:fi + ["kuntoilulaite" + "ulkokuntoilupiste" + "kuntoilupiste" + "kuntoilupaikka" + "kuntoportaat"]}, + :name + {:fi "Ulkokuntoilupaikka", + :se "Konditionspark för utomhusaktiviteter", + :en "Street workout park"}, + :type-code 1130, + :main-category 1000, + :status "active", + :sub-category 1100, + :geometry-type "Point", + :props + {:surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :free-use? {:priority 0}, + :fitness-stairs-length-m {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :area-m2 {:priority 1}, + :lighting-info {:priority 0}, + :ligthing? {:priority 1}, + :playground? {:priority 0}, + :school-use? {:priority 0}, + :exercise-machines-count {:priority 1}}}, + 5120 + {:description + {:fi "Pysyvästi purjehdusta varten varustettu alue.", + :se "Byggt för segling, permanent.", + :en "Permanent construction for sailing."}, + :tags {:fi []}, + :name + {:fi "Purjehdusalue", :se "Seglingsområde", :en "Sailing area"}, + :type-code 5120, + :main-category 5000, + :status "active", + :sub-category 5100, + :geometry-type "Point", + :props + {:area-km2 {:priority 0}, + :pier? {:priority 0}, + :boat-places-count {:priority 0}, + :free-use? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, + 4110 + {:description + {:fi + "Laskettelun suorituspaikka on lasketteluun tai lumilautailuun tarkoitettu liikuntapaikka, esim. laskettelukeskus. Laskettelun suorituspaikassa voi olla laskettelurinteitä, parkkeja tai muita rinnerakenteita ja hiihtohissejä.", + :se + "Slalombacke, rodelbana, pipe, puckelpist, freestyle ramp, trickbana.", + :en "Ski slopes, half pipes and other slope structures."}, + :tags {:fi ["rinne" "laskettelu" "laskettelurinne"]}, + :name + {:fi "Laskettelun suorituspaikka", + :se "Slalombackar och alpina skidcentra", + :en "Ski slopes and downhill ski resorts"}, + :type-code 4110, + :main-category 4000, + :status "active", + :sub-category 4100, + :geometry-type "Point", + :props + {:lifts-count {:priority 1}, + :freestyle-slope? {:priority 0}, + :free-use? {:priority 0}, + :ski-service? {:priority 0}, + :sledding-hill? {:priority 0}, + :longest-slope-m {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :snowpark-or-street? {:priority 0}, + :max-vertical-difference {:priority 1}, + :toilet? {:priority 0}, + :halfpipe-count {:priority 0}, + :equipment-rental? {:priority 0}, + :slopes-count {:priority 1}, + :shortest-slope-m {:priority 0}, + :jumps-count {:priority 0}, + :customer-service-point? {:priority 0}, + :lit-slopes-count {:priority 1}, + :accessibility-info {:priority 0}}}, + 4452 + {:description + {:fi + "Merkitty vesireitti, ei kuitenkaan veneväylä. Vesireitti on reittiehdotus-tyyppinen suositeltu vesiretkeilyyn soveltuva reitti. Esim. kirkkovenesoutureitti.", + :se + "Märkt vattenled, endast ruttförslag t ex för kyrkbåtsrodd, inte som farled för småbåtar.", + :en + "Marked water route, not a navigation channel. Route suggestions included. E.g., route for \"church rowing boats\"."}, + :tags {:fi ["kanootti" "kajakki" "melonta"]}, + :name + {:fi "Vesiretkeilyreitti", + :se "Utflyktsled i vattendrag", + :en "Water route"}, + :type-code 4452, + :main-category 4000, + :status "active", + :sub-category 4400, + :geometry-type "LineString", + :props + {:may-be-shown-in-excursion-map-fi? {:priority 0}, + :route-length-km {:priority 1}, + :rest-places-count {:priority 0}, + :school-use? {:priority 0}, + :free-use? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :jumps-count {:priority 0}}}, + 5370 + {:description + {:fi "Pääasiallisesti jääspeedwayta varten.", + :se "Huvudsakligen för isracing.", + :en "Speedway mainly for ice racing."}, + :tags {:fi ["speedway"]}, + :name + {:fi "Speedway-/jääspeedwayrata", + :se "Isracingbana", + :en "Ice speedway track"}, + :type-code 5370, + :main-category 5000, + :status "active", + :sub-category 5300, + :geometry-type "Point", + :props + {:surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :automated-timing? {:priority 0}, + :stand-capacity-person {:priority 0}, + :free-use? {:priority 0}, + :finish-line-camera? {:priority 0}, + :track-width-m {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :lighting-info {:priority 0}, + :year-round-use? {:priority 0}, + :scoreboard? {:priority 0}, + :loudspeakers? {:priority 0}, + :ligthing? {:priority 0}, + :track-length-m {:priority 1}}}, + 2240 + {:description + {:fi + "Ensisijaisesti salibandyyn tarkoitettu halli. Kenttien määrä ja pintamateriaali kirjataan lisätietoihin.", + :se + "Hall i första hand avsedd för innebandy. Antalet planer samt ytmaterial i karakteristika.", + :en + "Hall primarily intended for floorball. Number of courts and surface material specified in properties."}, + :tags {:fi ["sähly"]}, + :name + {:fi "Salibandyhalli", :se "Innebandyhall", :en "Floorball hall"}, + :type-code 2240, + :main-category 2000, + :status "active", + :sub-category 2200, + :geometry-type "Point", + :props + {:height-m {:priority 0, :derived? true}, + :surface-material {:priority 1, :derived? true}, + :surface-material-info {:priority 0, :derived? true}, + :stand-capacity-person {:priority 0, :derived? true}, + :free-use? {:priority 0}, + :field-length-m {:priority 1, :derived? true}, + :badminton-courts-count {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :area-m2 {:priority 1, :derived? true}, + :field-width-m {:priority 1, :derived? true}, + :scoreboard? {:priority 0}, + :floorball-fields-count {:priority 1, :derived? true}, + :auxiliary-training-area? {:priority 0}, + :customer-service-point? {:priority 0}, + :school-use? {:priority 0}}}, + 2510 + {:description + {:fi + "Harjoitusjäähalli on pääasiassa jääurheilun harjoitteluun ja jääliikuntaan käytettävä jäähalli.", + :se + "Antalet planer och omklädningshytter, uppvärmning osv anges i karakteristika.", + :en + "Number of fields, heating, changing rooms, etc., specified in properties."}, + :tags {:fi ["jäähalli"]}, + :name + {:fi "Harjoitusjäähalli", + :se "Övningsishall", + :en "Training ice arena"}, + :type-code 2510, + :keywords {:fi ["Jäähalli"], :en [], :se []}, + :main-category 2000, + :status "active", + :sub-category 2500, + :geometry-type "Point", + :props + {:surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :automated-timing? {:priority 0}, + :stand-capacity-person {:priority 0}, + :free-use? {:priority 0}, + :finish-line-camera? {:priority 0}, + :match-clock? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :ice-rinks-count {:priority 1}, + :field-2-flexible-rink? {:priority 0}, + :toilet? {:priority 0}, + :area-m2 {:priority 1}, + :curling-lanes-count {:priority 0}, + :scoreboard? {:priority 0}, + :auxiliary-training-area? {:priority 0}, + :ringette-boundary-markings? {:priority 0}, + :field-1-flexible-rink? {:priority 0}, + :loudspeakers? {:priority 0}, + :school-use? {:priority 0}, + :field-3-flexible-rink? {:priority 0}}}, + 1640 + {:description + {:fi "Ratagolfliiton hyväksymät ratagolf-/minigolfradat.", + :se "Bangolf / minigolf, enligt Finlands Bangolfförbundets regler.", + :en + "A course built for miniature golf, accepted by the Ratagolf Union."}, + :tags {:fi ["minigolf"]}, + :name {:fi "Ratagolf", :se "Bangolf", :en "Minigolf course"}, + :type-code 1640, + :main-category 1000, + :status "active", + :sub-category 1600, + :geometry-type "Point", + :props + {:holes-count {:priority 1}, + :free-use? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :lighting-info {:priority 0}, + :customer-service-point? {:priority 0}, + :green? {:priority 0}, + :ligthing? {:priority 1}, + :school-use? {:priority 0}, + :range? {:priority 0}}}, + 1380 + {:description + {:fi "Rullakiekon pelaamiseen varustettu kenttä.", + :se "Plan utrustad för inlinehockey.", + :en "Field equipped for roller hockey."}, + :tags {:fi ["rullakiekko"]}, + :name + {:fi "Rullakiekkokenttä", + :se "Inlinehockeyplan", + :en "Roller hockey field"}, + :type-code 1380, + :main-category 1000, + :status "active", + :sub-category 1300, + :geometry-type "Point", + :props + {:surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :free-use? {:priority 0}, + :field-length-m {:priority 1}, + :match-clock? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :area-m2 {:priority 1}, + :field-width-m {:priority 1}, + :lighting-info {:priority 0}, + :water-point {:priority 0}, + :ligthing? {:priority 1}, + :school-use? {:priority 0}}}, + 4451 + {:description + {:fi + "Erityisesti melontaan tarkoitettu vesistöreitti. Reitistä on laadittu reittikuvaus ja maastossa löytyy opasteita (esim. rantautumispaikoista). Reittiehdotus-tyyppinen, ei navigointiin.", + :se + "Särskilt för paddling, märkt med ruttförslag, ej för navigering.", + :en + "Marked route particularly for canoeing. Route suggestions are not intended for navigation."}, + :tags {:fi ["kanootti" "kajakki"]}, + :name {:fi "Melontareitti", :se "Paddlingsled", :en "Canoe route"}, + :type-code 4451, + :main-category 4000, + :status "active", + :sub-category 4400, + :geometry-type "LineString", + :props + {:route-length-km {:priority 1}, + :rest-places-count {:priority 0}, + :may-be-shown-in-excursion-map-fi? {:priority 0}, + :free-use? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, + 4403 + {:description + {:fi + "Jalkaisin tapahtuvaan ulkoiluun tarkoitettu reitti. Suhteellisen leveä ja helppokulkuinen reitti, yleensä valaistu ja pinnoitettu.", + :se + "Promenadled. Relativt bred och lättilgänglig, eventuellt belyst och asfalterad.", + :en + "Route intended for outdoor pedestrian activities. Relatively broad and passable. Potentially lit and surfaced."}, + :tags {:fi ["ulkoilu" "kävely" "ulkoilureitti" "kävelyreitti"]}, + :name + {:fi "Kävelyreitti/ulkoilureitti", + :se "Promenadled/friluftsled", + :en "Walking route/outdoor route"}, + :type-code 4403, + :main-category 4000, + :status "active", + :sub-category 4400, + :geometry-type "LineString", + :props + {:surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :free-use? {:priority 0}, + :may-be-shown-in-excursion-map-fi? {:priority 0}, + :outdoor-exercise-machines? {:priority 0}, + :route-width-m {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :rest-places-count {:priority 0}, + :lit-route-length-km {:priority 1}, + :accessibility-info {:priority 0}, + :route-length-km {:priority 1}}}, + 5150 + {:description + {:fi + "Melontaan tarkoitettu palvelupaikka, jossa voi olla esim. vuokrauspalveluita. Melontakeskuksesta voi lähteä melontareitti tai sen yhteydessä voi olla melontaratoja.", + :se "", + :en ""}, + :tags {:fi ["melonta" "kajakki" "kanootti" "melontakeskus"]}, + :name + {:fi "Melontakeskus", + :se "Centrum för paddling", + :en "Canoeing centre"}, + :type-code 5150, + :main-category 5000, + :status "active", + :sub-category 5100, + :geometry-type "Point", + :props + {:free-use? {:priority 0}, + :pier? {:priority 0}, + :canoeing-club? {:priority 0}, + :altitude-difference {:priority 0}, + :rapid-canoeing-centre? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :equipment-rental? {:priority 0}, + :activity-service-company? {:priority 0}}}, + 1630 + {:description + {:fi + "Golfia varten varustettu sisäharjoittelutila. Voi olla useita erilaisia suorituspaikkoja.", + :se "Övningsutrymme byggt för golf. Storlek i karakteristika.", + :en "Training space built for golf. Size specified in properties."}, + :tags {:fi ["greeni" "puttialue"]}, + :name + {:fi "Golfin harjoitushalli", + :se "Övningshall för golf", + :en "Golf training hall"}, + :type-code 1630, + :main-category 2000, + :status "active", + :sub-category 2200, + :geometry-type "Point", + :props + {:height-m {:priority 1}, + :holes-count {:priority 0}, + :free-use? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :area-m2 {:priority 1}, + :customer-service-point? {:priority 0}, + :green? {:priority 0}, + :school-use? {:priority 0}, + :range? {:priority 0}}}, + 2295 + {:description + {:fi + "Yksi tai useampi padelkenttä sisällä. Pintamateriaali tekonurmi (hiekkatekonurmi). Lajivaatimusten mukaiset seinät. Vapaa korkeus ilmoitetaan lisätiedoissa.", + :se + "En eller flera padelbanor inomhus. Ytmaterial konstgräs (med sand), 20 x 10 m. Väggar måste uppfylla spelets krav. Höjd anges i karakteristika.", + :en + "One or more indoor padel courts. The court has an artificial grass surface and its measurements are 20 x 10 metres. The walls must meet the requirements for the sport. Height given in 'properties'."}, + :tags {:fi ["padel" "padel-halli"]}, + :name {:fi "Padelhalli", :se "Padelhall", :en "Padel hall"}, + :type-code 2295, + :main-category 2000, + :status "active", + :sub-category 2200, + :geometry-type "Point", + :props + {:height-m {:priority 1}, + :surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :stand-capacity-person {:priority 0}, + :free-use? {:priority 0}, + :field-length-m {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :padel-courts-count {:priority 1}, + :toilet? {:priority 0}, + :area-m2 {:priority 1}, + :field-width-m {:priority 0}, + :scoreboard? {:priority 0}, + :school-use? {:priority 0}}}, + 2370 + {:description + {:fi "Kiipeilyyn varustettu sisätila. Myös boulderointipaikat.", + :se + "Inomhusutrymme utrustat för klättring, även platser för bouldering.", + :en "Indoor space equipped for climbing. Also bouldering venues."}, + :tags {:fi ["kiipeilyseinä"]}, + :name + {:fi "Sisäkiipeilyseinä", + :se "Klättervägg inomhus", + :en "Indoor climbing wall"}, + :type-code 2370, + :main-category 2000, + :status "active", + :sub-category 2300, + :geometry-type "Point", + :props + {:surface-material {:priority 0}, + :surface-material-info {:priority 0}, + :climbing-routes-count {:priority 0}, + :climbing-wall-height-m {:priority 1}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :area-m2 {:priority 1}, + :climbing-wall-width-m {:priority 1}, + :school-use? {:priority 0}}}, + 1340 + {:description + {:fi + "Palloiluun tarkoitettu kenttä, jonka pintamateriaali on esim. hiekka, nurmi tai hiekkatekonurmi. Kentällä on mahdollista pelata yhtä tai useampaa palloilulajia. Kentän koko merkitään lisätietoihin. Kevyt poistettava kate on mahdollinen.", + :se + "Plan avsedd för bollspel. Sand, konstgräs med sand el dyl, storleken varierar. En eller flera bollspelsgrenar möjliga.", + :en + "A field intended for ball games. Sand, grass, artificial turf, etc., size varies. One or more types of ball games possible."}, + :tags {:fi []}, + :name {:fi "Pallokenttä", :se "Bollplan", :en "Ball field"}, + :type-code 1340, + :main-category 1000, + :status "active", + :sub-category 1300, + :geometry-type "Point", + :props + {:heating? {:priority 0}, + :surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :stand-capacity-person {:priority 0}, + :free-use? {:priority 0}, + :field-length-m {:priority 1}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :changing-rooms? {:priority 0}, + :area-m2 {:priority 1}, + :field-width-m {:priority 1}, + :lighting-info {:priority 0}, + :year-round-use? {:priority 0}, + :customer-service-point? {:priority 0}, + :water-point {:priority 0}, + :ligthing? {:priority 1}, + :school-use? {:priority 0}, + :light-roof? {:priority 0}}}, + 1610 + {:description + {:fi + "Golfin harjoittelua varten varustettu alue. Harjoitusalue voi sisältää useampia suorituspaikkoja, kuten rangen ja puttausviheriön. Harjoitusalue sijaitsee ulkona.", + :se + "Ett område utrustat för golfträning. Träningsområdet kan innehålla flera träningsplatser, såsom en range och en puttningsgreen. Träningsområdet ligger utomhus.", + :en "An area equipped for golf practice. The practice area may include multiple facilities, such as a driving range and a putting green. The practice area is located outdoors."}, + :tags {:fi ["greeni" "puttialue" "range"]}, + :name + {:fi "Golfin harjoitusalue", + :se "Träningsområde för golf", + :en "Golf training area"}, + :type-code 1610, + :main-category 1000, + :status "active", + :sub-category 1600, + :geometry-type "Point", + :props + {:holes-count {:priority 1}, + :free-use? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :lighting-info {:priority 0}, + :customer-service-point? {:priority 0}, + :green? {:priority 0}, + :ligthing? {:priority 1}, + :school-use? {:priority 0}, + :range? {:priority 0}}}, + 4421 + {:description + {:fi + "Reittitoimituksella hyväksytty, virallinen moottorikelkkailureitti.", + :se "En officiell rutt som godkänts genom en ruttexpedition.", + :en "Officially approved route (in compliance with Act 670/1991)."}, + :tags {:fi []}, + :name + {:fi "Moottorikelkkareitti", + :se "Snöskoterled", + :en "Official snowmobile route"}, + :type-code 4421, + :main-category 4000, + :status "active", + :sub-category 4400, + :geometry-type "LineString", + :props + {:rest-places-count {:priority 0}, + :route-width-m {:priority 0}, + :may-be-shown-in-excursion-map-fi? {:priority 0}, + :route-length-km {:priority 1}, + :free-use? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, + 2220 + {:description + {:fi + "Monitoimihalli on suuri liikuntatila, joka on merkittävä monien lajien kilpailu- ja tapahtumapaikka. Liikuntapinta-ala on suurempi kuin 5 000 m2.", + :se "Större tävlingsplats för ett flertal grenar, >= 5 000 m2.", + :en "Significant competition venue for various sports, >=5000 m2."}, + :tags {:fi ["liikuntahalli" "urheilutalo" "urheiluhalli"]}, + :name + {:fi "Monitoimihalli/areena", + :se "Allaktivitetshall/multiarena", + :en "Multipurpose hall/arena"}, + :type-code 2220, + :main-category 2000, + :status "active", + :sub-category 2200, + :geometry-type "Point", + :props + {:height-m {:priority 1}, + :surface-material {:priority 1}, + :basketball-fields-count {:priority 0}, + :surface-material-info {:priority 0}, + :automated-timing? {:priority 0}, + :stand-capacity-person {:priority 0}, + :free-use? {:priority 0}, + :sprint-lanes-count {:priority 0}, + :javelin-throw-places-count {:priority 0}, + :tennis-courts-count {:priority 0}, + :field-length-m {:priority 1}, + :circular-lanes-count {:priority 0}, + :match-clock? {:priority 0}, + :sprint-track-length-m {:priority 0}, + :inner-lane-length-m {:priority 0}, + :discus-throw-places {:priority 0}, + :badminton-courts-count {:priority 0}, + :hammer-throw-places-count {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :padel-courts-count {:priority 0}, + :polevault-places-count {:priority 0}, + :space-divisible {:priority 0}, + :toilet? {:priority 0}, + :gymnastics-space? {:priority 0}, + :running-track-surface-material {:priority 0}, + :area-m2 {:priority 1}, + :field-width-m {:priority 1}, + :scoreboard? {:priority 0}, + :shotput-count {:priority 0}, + :longjump-places-count {:priority 0}, + :football-fields-count {:priority 0}, + :floorball-fields-count {:priority 0}, + :auxiliary-training-area? {:priority 0}, + :squash-courts-count {:priority 0}, + :loudspeakers? {:priority 0}, + :customer-service-point? {:priority 0}, + :accessibility-info {:priority 0}, + :handball-fields-count {:priority 0}, + :volleyball-fields-count {:priority 0}, + :climbing-wall? {:priority 0}, + :school-use? {:priority 0}, + :highjump-places-count {:priority 0}}}, + 1320 + {:description + {:fi + "Lentopalloon varustettu kenttä, jossa on kiinteät lentopallotolpat.", + :se "Plan utrustad för volleyboll. Fasta volleybollställningar.", + :en "A field equipped for volleyball. Fixed volleyball apparatus."}, + :tags {:fi []}, + :name + {:fi "Lentopallokenttä", + :se "Volleybollplan", + :en "Volleyball court"}, + :type-code 1320, + :main-category 1000, + :status "active", + :sub-category 1300, + :geometry-type "Point", + :props + {:surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :height-of-basket-or-net-adjustable? {:priority 0}, + :free-use? {:priority 0}, + :field-length-m {:priority 1}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :area-m2 {:priority 1}, + :field-width-m {:priority 1}, + :lighting-info {:priority 0}, + :water-point {:priority 0}, + :ligthing? {:priority 1}, + :school-use? {:priority 0}}}, + 4402 + {:description + {:fi + "Talvikaudella hiihtoa varten ylläpidetty reitti. Hiihtotyylit kerrotaan ominaisuustiedoissa.", + :se + "Led avsedd för skidåkning. Ej sommaranvändning och -underhåll. Åkstilar anges i karakteristika.", + :en + "Route intended for skiing. Not in use and unmaintained in summer. Ski styles provided in properties."}, + :tags {:fi ["hiihto" "hiihtolatu"]}, + :name {:fi "Hiihtolatu", :se "Skidspår", :en "Ski track"}, + :type-code 4402, + :main-category 4000, + :status "active", + :sub-category 4400, + :geometry-type "LineString", + :props + {:surface-material {:priority 1}, + :surface-material-info {:priority 0}, + :free-use? {:priority 0}, + :may-be-shown-in-excursion-map-fi? {:priority 0}, + :outdoor-exercise-machines? {:priority 0}, + :ski-track-traditional? {:priority 0}, + :route-width-m {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 0}, + :rest-places-count {:priority 0}, + :shooting-positions-count {:priority 0}, + :lit-route-length-km {:priority 1}, + :ski-track-freestyle? {:priority 0}, + :school-use? {:priority 0}, + :route-length-km {:priority 1}}}}) (def active (reduce-kv (fn [m k v] (if (not= "active" (:status v)) (dissoc m k) m)) all all)) (def unknown - new/unknown) + {:name {:fi "Ei tietoa" :se "Unknown" :en "Unknown"} + :type-code -1 + :main-category -1 + :sub-category -1}) (def by-main-category (group-by :main-category (vals active))) (def by-sub-category (group-by :sub-category (vals active))) diff --git a/webapp/src/cljc/lipas/data/types_new.cljc b/webapp/src/cljc/lipas/data/types_new.cljc index 5714a5c16..9e21f5d14 100644 --- a/webapp/src/cljc/lipas/data/types_new.cljc +++ b/webapp/src/cljc/lipas/data/types_new.cljc @@ -825,7 +825,26 @@ )) -(def all all7) +(def all8 + (-> all7 + (update-in [4810 :props] dissoc :free-use?) + (update-in [4820 :props] dissoc :free-use?) + (assoc-in [5120 :description :fi] "Pysyvästi purjehdusta varten varustettu alue.") + (assoc-in [202 :props :free-use?] {:priority 0}) + (assoc-in [203 :props :free-use?] {:priority 0}) + (assoc-in [204 :props :free-use?] {:priority 0}) + (assoc-in [206 :props :free-use?] {:priority 0}) + (assoc-in [301 :props :free-use?] {:priority 0}) + (assoc-in [302 :props :free-use?] {:priority 0}) + (assoc-in [304 :props :free-use?] {:priority 0}) + (assoc-in [4412 :description :fi] "Pyöräilyreitti, joka kulkee enimmäkseen päällystetyillä teillä tai sorateillä. Reitti voi olla merkitty maastoon tai se on digitaalisesti opastettu.") + (assoc-in [5370 :name :fi] "Speedway-/jääspeedwayrata") + (assoc-in [6130 :name :fi] "Esteratsastuskenttä/-alue") + (assoc-in [3210 :name :fi] "Maauimala/vesipuisto") + + )) + +(def all all8) (def active (reduce-kv (fn [m k v] (if (not= "active" (:status v)) (dissoc m k) m)) all all)) @@ -843,5 +862,9 @@ (utils/index-by (comp :fi :name) (vals sub-categories))) (comment - (all 2620) + (require '[clojure.pprint :as pprint]) + #?(:clj (spit "/tmp/types.edn" (with-out-str (pprint/pprint all)))) + #?(:clj (spit "/tmp/sub-cats.edn" (with-out-str (pprint/pprint sub-categories)))) + #?(:clj (spit "/tmp/main-cats.edn" (with-out-str (pprint/pprint main-categories)))) + ) diff --git a/webapp/src/cljs/lipas/ui/sports_sites/views.cljs b/webapp/src/cljs/lipas/ui/sports_sites/views.cljs index 53b78ac88..461961660 100644 --- a/webapp/src/cljs/lipas/ui/sports_sites/views.cljs +++ b/webapp/src/cljs/lipas/ui/sports_sites/views.cljs @@ -509,17 +509,18 @@ [:<> [lui/checkbox {:label label + :tooltip tooltip :value @checkbox-state :on-change #(reset! checkbox-state %)}] (when @checkbox-state [lui/text-field - {:value value - :label helper-text - :disabled disabled? - :tooltip tooltip - :spec spec - :type "number" - :on-change on-change}])]) + {:value value + :label helper-text + :disabled disabled? + #_#_:tooltip tooltip + :spec spec + :type "number" + :on-change on-change}])]) ) ;; Used from activities -> lipas-property now From 1032999efbe9a1033fefcaeb1b917141327f1fbb Mon Sep 17 00:00:00 2001 From: Valtteri Harmainen Date: Sat, 26 Oct 2024 14:53:35 +0300 Subject: [PATCH 13/68] Add missing translations --- webapp/src/cljc/lipas/data/prop_types.cljc | 236 ++++++++++----------- webapp/src/cljc/lipas/data/types.cljc | 11 +- 2 files changed, 124 insertions(+), 123 deletions(-) diff --git a/webapp/src/cljc/lipas/data/prop_types.cljc b/webapp/src/cljc/lipas/data/prop_types.cljc index d8971ac99..fc543e503 100644 --- a/webapp/src/cljc/lipas/data/prop_types.cljc +++ b/webapp/src/cljc/lipas/data/prop_types.cljc @@ -12,14 +12,14 @@ :description {:fi "Sisäliikuntatilan korkeus metreinä (matalin kohta)", :se "Motionssalens höjd i meter (från lägsta punkten)", - :en ""}}, + :en "Height of the indoor sports facility in meters (lowest point)"}}, :heating? {:name {:fi "Lämmitys", :se "Uppvärmning", :en "Heating"}, :data-type "boolean", :description {:fi "Onko liikuntapaikassa lämmitys", :se "Är idrottsplatsen utrustad med uppvärmning", - :en ""}}, + :en "Is there heating in the sports facility"}}, :field-2-area-m2 {:name {:fi "2. kentän ala m2", @@ -29,7 +29,7 @@ :description {:fi "2. kentän pinta-ala neliömetreinä", :se "Andra planens areal i kvadratmeter", - :en ""}}, + :en "2. field's area in square meters"}}, :surface-material {:name {:fi "Pintamateriaali", :se "Ytmaterial", :en "Surface material"}, @@ -38,8 +38,8 @@ {:fi "Liikunta-alueiden pääasiallinen pintamateriaali - tarkempi kuvaus liikuntapaikan eri tilojen pintamateriaalista voidaan antaa pintamateriaalin lisätietokentässä", :se - "Idrotts områdets ytmaterial. Friidrottsplanens mittplans pålägg.", - :en ""}}, + "Huvudsakligt ytskikt för idrottsområden - en mer detaljerad beskrivning av ytskiktet i olika delar av idrottsanläggningen kan ges i tilläggsinformationsfältet för ytskikt.", + :en "Primary surface material of sports areas - a more detailed description of the surface material in different parts of the sports facility can be provided in the additional information field for surface material."}}, :basketball-fields-count {:name {:fi "Koripallokentät lkm", @@ -49,7 +49,7 @@ :description {:fi "Koripallokenttien lukumäärä", :se "Antalet korgbollsplaner i salen", - :en ""}}, + :en "The number of basketball courts"}}, :surface-material-info {:name {:fi "Pintamateriaali lisätieto", @@ -59,8 +59,8 @@ :description {:fi "Syötä pintamateriaalin tarkempi kuvaus- esim. tekonurmen yleisnimitys ”esim. Kumirouhetekonurmi”, tuotenimi ja tieto täytemateriaalin laadusta (esim. biohajoava/perinteinen kumirouhe).", - :se "Ytterilgare information om ytmaterialen", - :en ""}}, + :se "Ange en mer detaljerad beskrivning av ytskiktet - till exempel den allmänna beteckningen för konstgräs t.ex. gummigranulatkonstgräs, produktnamn och information om fyllnadsmaterialets kvalitet (t.ex. biologiskt nedbrytbart/traditionellt gummigranulat).", + :en "Enter a more detailed description of the surface material - for example, the general name for artificial turf “e.g., rubber granulate artificial turf,” product name, and information about the quality of the infill material (e.g., biodegradable/traditional rubber granulate)."}}, :height-of-basket-or-net-adjustable? {:name {:fi "Korin tai verkon korkeus säädettävissä", @@ -86,14 +86,14 @@ {:fi "Hyppyrimäen tyyppi (harjoitus, pienmäki, normaali, suurmäki)", :se "Typ av hoppbacke (övningsbacke, liten, normalbacke, storbacke)", - :en ""}}, + :en "Type of ski jump (training hill, small hill, normal hill, large hill)"}}, :lifts-count {:name {:fi "Hissit lkm", :se "Antalet skidliftar", :en "Lifts"}, :data-type "numeric", :description {:fi "Hiihtohissien lukumäärä", :se "Antal skidliftar i skidcentrumet", - :en ""}}, + :en "Number of ski lifts"}}, :field-3-length-m {:name {:fi "3. kentän pituus m", @@ -103,17 +103,17 @@ :description {:fi "3. kentän pituus metreinä", :se "Tredje planens längd i meter", - :en ""}}, + :en "Length of the third field in meters"}}, :pool-tracks-count {:name {:fi "1. altaan radat lkm", :se "Första bassängens antal banor", - :en "Courses in 1. pool"}, + :en "Lanes in 1. pool"}, :data-type "numeric", :description {:fi "1. altaan ratojen lukumäärä", :se "Antal banor i första bassängen", - :en ""}}, + :en "Number of lanes in the first pool"}}, :field-2-length-m {:name {:fi "2. kentän pituus m", @@ -123,7 +123,7 @@ :description {:fi "2. kentän pituus metreinä", :se "Andra planens längd i meter", - :en ""}}, + :en "Length of the second field in meters"}}, :plastic-outrun? {:name {:fi "Muovitettu alastulo", @@ -133,7 +133,7 @@ :description {:fi "Muovitettu hyppyrimäen alastulopaikka", :se "Hoppbacken har plast-belagd landningsplats", - :en ""}}, + :en "Plastic-coated landing area of the ski jump"}}, :automated-timing? {:name {:fi "Automaattinen ajanotto", @@ -143,28 +143,28 @@ :description {:fi "Varustus automaattiseen ajanottoon", :se "Utrustning för automatisk tidtagning", - :en ""}}, + :en "Equipment for automatic timing"}}, :freestyle-slope? {:name {:fi "Kumparerinne", :se "Puckelpist", :en "Freestyle slope"}, :data-type "boolean", :description {:fi "Hiihtokeskuksessa on kumparerinne", :se "Skidcentret har en puckelpist", - :en ""}}, + :en "The ski resort has a mogul slope."}}, :kiosk? {:name {:fi "Kioski", :se "Kiosk", :en "Kiosk"}, :data-type "boolean", :description {:fi "Onko liikuntapaikalla kioski tai vastaava", :se "Har idrottsplatsen en kiosk eller något liknande", - :en ""}}, + :en "Is there a kiosk or similar facility at the sports venue"}}, :summer-usage? {:name {:fi "Kesäkäyttö", :se "I sommarbruk", :en "Summer usage"}, :data-type "boolean", :description {:fi "Käytössä myös kesäisin", - :se "Används också under sommaren", - :en ""}}, + :se "Tillgänglig även på sommaren", + :en "Available also in the summer"}}, :stand-capacity-person {:name {:fi "Katsomon kapasiteetti hlö", @@ -174,7 +174,7 @@ :description {:fi "Katsomon koko kapasiteetti, henkilölukumäärä", :se "Läktarens hela person kapasitet", - :en ""}}, + :en "Total capacity of the stands, number of people"}}, :free-use? {:name {:fi "Kohde on vapaasti käytettävissä", @@ -295,7 +295,7 @@ :description {:fi "Tenniskenttien lukumäärä", :se "Antalet tennisplaner", - :en ""}}, + :en "Number of tennis courts"}}, :ski-service? {:name {:fi "Suksihuolto", :se "Skidservice", :en "Ski service"}, :data-type "boolean", @@ -312,21 +312,21 @@ :description {:fi "1. kentän pituus metreinä", :se "Första planens längd i meter", - :en ""}}, + :en "Length of the first field in meters"}}, :mirror-wall? {:name {:fi "Peiliseinä", :se "Spegelvägg", :en "Mirror wall"}, :data-type "boolean", :description {:fi "Liikuntatilassa vähintään yhdellä seinällä on kiinteät peilit", - :se "", - :en ""}}, + :se "I idrottsutrymmet finns fasta speglar på minst en vägg.", + :en "The sports facility has fixed mirrors on at least one wall."}}, :finish-line-camera? {:name {:fi "Maalikamera", :se "Målkamera", :en "Finish line camera"}, :data-type "boolean", :description {:fi "Liikuntapaikalla on maalikamera", :se "Idrottsplatsen har en målkamera", - :en ""}}, + :en "The sports facility has a finish line camera."}}, :travel-mode-info {:name {:fi "Kulkutavat, lisätieto", @@ -344,7 +344,7 @@ :description {:fi "Parkkipaikka käytettävissä", :se "Tillgänglig parkeringsplats", - :en ""}}, + :en "Parking available"}}, :canoeing-club? {:name {:fi "Melontaseura", :se "", :en "Canoeing club"}, :data-type "boolean", @@ -373,7 +373,7 @@ :description {:fi "Kiipeilyreittien lukumäärä", :se "Antalet klättringsrutter", - :en ""}}, + :en "Number of climbing routes"}}, :outdoor-exercise-machines? {:name {:fi "Kuntoilutelineitä", @@ -383,7 +383,7 @@ :description {:fi "Onko reitin varrella kuntoilulaitteita", :se "Finns det gym apparater längs rutten", - :en ""}}, + :en "Are there fitness equipment along the route"}}, :automated-scoring? {:name {:fi "Kirjanpitoautomaatti", @@ -393,7 +393,7 @@ :description {:fi "Keilaradalla on sähköinen pistelasku", :se "Bowlingbanan har elektroniskt poängräknings system", - :en ""}}, + :en "The bowling alley has electronic scoring."}}, :mobile-orienteering? {:name {:fi "Mobiilisuunnistusmahdollisuus", @@ -408,14 +408,14 @@ :description {:fi "Juoksuradan, pyöräilyradan tms. leveys metreinä", :se "Löpbanan, rundbanan el.dyl. bredd i meter", - :en ""}}, + :en "Width of the running track, cycling track, etc., in meters"}}, :ice-climbing? {:name {:fi "Jääkiipeily", :se "Isklättring", :en "Ice climbing"}, :data-type "boolean", :description {:fi "Onko jääkiipeily mahdollista kiipeilypaikalla", :se "Finns det möjlighet för isklättring vid klättringsplatsen", - :en ""}}, + :en "Is ice climbing possible at the climbing site"}}, :free-use {:name {:fi "Kohde on vapaasti käytettävissä"}}, :field-length-m {:name @@ -426,7 +426,7 @@ :description {:fi "Kentän/kenttien pituus mahdollisine turva-alueineen metreinä", :se "Planens/planernas längd i meter", - :en ""}}, + :en "Length of the field(s) including any safety areas in meters"}}, :skijump-hill-material {:name {:fi "Vauhtimäen rakennemateriaali", @@ -436,7 +436,7 @@ :description {:fi "Vauhtimäen rakennemateriaali", :se "Överbackens konstruktionsmaterial (backhoppning)", - :en ""}}, + :en "Construction material of the inrun"}}, :carom-tables-count {:name {:fi "Karapöydät lkm", @@ -453,7 +453,7 @@ :description {:fi "Pisimmän rinteen pituus metreinä", :se "Längsta slalombackens längd i meter", - :en ""}}, + :en "Length of the longest slope in meters"}}, :circular-lanes-count {:name {:fi "Kiertävät radat lkm", @@ -463,7 +463,7 @@ :description {:fi "Kiertävien juoksuratojen lukumäärä", :se "Antalet cirkulerande löpbanor", - :en ""}}, + :en "Number of circular running tracks"}}, :boat-launching-spot? {:name {:fi "Veneen vesillelaskupaikka", @@ -473,7 +473,7 @@ :description {:fi "Mahdollisuus veneen vesillelaskuun", :se "Sjösättningsplats för båtar", - :en ""}}, + :en "Possibility for boat launching"}}, :parkour-hall-equipment-and-structures {:name {:fi "Parkour-salin varustelu ja rakenteet", @@ -529,8 +529,8 @@ "Område utrustat med gymmaskiner och utrustning för styrketräning."}}}, :description {:fi "Valitse parkour-salissa olevat rakenteet tai varusteet", - :se "", - :en ""}}, + :se "Välj de strukturer eller utrustningar som finns i parkourhallen", + :en "Select the structures or equipment available in the parkour gym"}}, :ski-track-traditional? {:name {:fi "Perinteinen latu", @@ -540,7 +540,7 @@ :description {:fi "Perinteisen tyylin hiihtomahdollisuus/latu-ura", :se "Möjlighet att skida klassisk stil", - :en ""}}, + :en "Classic style skiing track available"}}, :altitude-difference {:name {:fi "Korkeusero m", @@ -550,7 +550,7 @@ :description {:fi "Reitin korkeusero metreinä", :se "Ruttens höjdskillnad i meter", - :en ""}}, + :en "Elevation difference of the route in meters"}}, :climbing-wall-height-m {:name {:fi "Kiipeilyseinän korkeus m", @@ -560,7 +560,7 @@ :description {:fi "Kiipeilyseinän korkeus metreinä (max)", :se "Klätterväggens höjd i meter (max)", - :en ""}}, + :en "Height of the climbing wall in meters (max)"}}, :route-width-m {:name {:fi "Reitin leveys m", @@ -588,14 +588,14 @@ :description {:fi "Hoidetun rannan pituus metreinä", :se "Skötta strandens längd i meter", - :en ""}}, + :en "Length of the maintained beach in meters"}}, :match-clock? {:name {:fi "Ottelukello", :se "Matchklocka", :en "Match clock"}, :data-type "boolean", :description {:fi "Onko liikuntapaikalla ottelukello", :se "Finns det en matchklocka vid idrottsplatsen", - :en ""}}, + :en "Is there a match clock at the sports facility"}}, :sprint-track-length-m {:name {:fi "Etusuoran pituus m", @@ -605,7 +605,7 @@ :description {:fi "Juoksuradan etusuoran pituus", :se "Längden på löpbanans raksträcka", - :en ""}}, + :en "Length of the home straight of the running track"}}, :inner-lane-length-m {:name {:fi "Sisäradan pituus m", @@ -615,7 +615,7 @@ :description {:fi "Sisäradan pituus kiertävissä radoissa", :se "Längden på innerbanan i de cirkulerande banorna", - :en ""}}, + :en "Length of the inside lane in circular tracks"}}, :discus-throw-places {:name {:fi "Kiekonheittopaikat lkm", @@ -625,7 +625,7 @@ :description {:fi "Kiekonheittopaikkojen lukumäärä", :se "Antalet diskuskastningsplatser", - :en ""}}, + :en "Number of discus throw areas"}}, :fields-count {:name {:fi "Kenttien lkm", :se "Antalet planer", :en "Number of fields"}, @@ -633,7 +633,7 @@ :description {:fi "Montako saman tyypin kenttää liikuntapaikassa on", :se "Hur många planer av samma typ har motionsplatsen", - :en ""}}, + :en "How many of the same type of fields are there at the sports facility"}}, :field-1-width-m {:name {:fi "1. kentän leveys m", @@ -643,7 +643,7 @@ :description {:fi "1. kentän leveys metreinä", :se "Första planens bredd i meter", - :en ""}}, + :en "Width of the first field in meters"}}, :field-3-width-m {:name {:fi "3. kentän leveys m", @@ -653,7 +653,7 @@ :description {:fi "3. kentän leveys metreinä", :se "Tredje planens bredd i meter", - :en ""}}, + :en "Width of the third field in meters"}}, :field-2-width-m {:name {:fi "2. kentän leveys m", @@ -663,7 +663,7 @@ :description {:fi "2. kentän leveys metreinä", :se "Andra planens bredd i meter", - :en ""}}, + :en "Width of the second field in meters"}}, :badminton-courts-count {:name {:fi "Sulkapallokentät lkm", @@ -673,7 +673,7 @@ :description {:fi "Sulkapallokenttien lukumäärä salissa", :se "Antalet badmintonsplaner i salen", - :en ""}}, + :en "Number of badminton courts in the hall"}}, :fitness-stairs-length-m {:name {:fi "Kuntoportaiden pituus m", @@ -690,8 +690,8 @@ :description {:fi "Liikuntapaikka on asiakkaiden käytettävissä esim. kulkukortilla ilman henkilökunnan läsnäoloa. Vapaa asiakaskäyttö voi olla rajattu tiettyihin kellonaikoihin.", - :se "", - :en ""}}, + :se "Idrottsanläggningen är tillgänglig för kunder, t.ex. med ett passerkort, utan personal närvarande. Fri kundanvändning kan vara begränsad till vissa tider.", + :en "The sports facility is available for customer use, e.g., with an access card, without staff presence. Free customer access may be limited to certain hours."}}, :hammer-throw-places-count {:name {:fi "Moukarinheittopaikat lkm", @@ -701,7 +701,7 @@ :description {:fi "Moukarinheittopaikkojen lukumäärä", :se "Antal platser för att släggkastning", - :en ""}}, + :en "Number of hammer throw areas"}}, :may-be-shown-in-harrastuspassi-fi? {:name {:fi "Saa julkaista Harrastuspassi.fi-sovelluksessa", @@ -733,7 +733,7 @@ :description {:fi "1. altaan syvyys matalimmasta päästä metreinä", :se "Första bassängens grundaste punkt i meter.", - :en ""}}, + :en "The depth of the shallowest end of the pool in meters."}}, :padel-courts-count {:name {:fi "Padelkentät lkm", @@ -754,7 +754,7 @@ :description {:fi "Kaukaloiden lukumäärä", :se "Antalet rinkar (hockey) det finns vid idrottsplatsen", - :en ""}}, + :en "The number of rinks."}}, :field-1-area-m2 {:name {:fi "1. kentän ala m2", @@ -764,14 +764,14 @@ :description {:fi "1. kentän pinta-ala neliömetreinä", :se "Första planens areal i kvadratmeter", - :en ""}}, + :en "The area of the field in square meters."}}, :k-point {:name {:fi "K-piste", :se "K-punkt", :en "K point"}, :data-type "numeric", :description {:fi "Hyppyrimäen k-piste metreinä", :se "Hoppbackens k-punkt i meter", - :en ""}}, + :en "The K-point of the ski jumping hill in meters"}}, :polevault-places-count {:name {:fi "Seiväshyppypaikat lkm", @@ -781,7 +781,7 @@ :description {:fi "Seiväshyppypaikkojen lukumäärä", :se "Antalet stavhoppningsplatser", - :en ""}}, + :en "The number of pole vault areas."}}, :group-exercise-rooms-count {:name {:fi "Ryhmäliikuntatilat lkm", @@ -791,7 +791,7 @@ :description {:fi "Liikuntasalien ja ryhmäliikuntatilojen lukumäärä", :se "Antalet gymnastiksalar och gruppmotions utrymmen", - :en ""}}, + :en "The number of sports halls and group exercise spaces"}}, :snowpark-or-street? {:name {:fi "Parkki", :se "Trick/street pist", :en "Snow park/street"}, @@ -800,7 +800,7 @@ {:fi "Onko rinnehiihtokeskuksessa ns. temppurinne, snowpark tai vastaava", :se "Har skidcentrumet en trickbana, snowpark eller något liknande", - :en ""}}, + :en "Is there a so-called adventure slope, snowpark, or similar area in the ski resort"}}, :field-2-flexible-rink? {:name {:fi "2. kenttä: onko joustokaukalo?", @@ -835,7 +835,7 @@ :description {:fi "Suurin korkeusero rinteissä", :se "Största höjdskillnaden i slalombackorna", - :en ""}}, + :en "The greatest elevation difference in the slopes"}}, :bowling-lanes-count {:name {:fi "Keilaradat lkm", @@ -853,7 +853,7 @@ :description {:fi "Ilma-aseammuntamahdollisuus", :se "Möjlighet för luftgevärsskytte", - :en ""}}, + :en "Availability of air gun shooting"}}, :gymnastic-routines-count {:name {:fi "Telinevoimistelusarjat lkm", @@ -863,14 +863,14 @@ :description {:fi "Telinevoimistelun telinesarjojen lukumäärä", :se "Antalet redskap för redskapsgymnastik", - :en ""}}, + :en "The number of apparatus for gymnastics routines"}}, :toilet? {:name {:fi "Yleisö-wc", :se "Allmän toalett", :en "Toilet"}, :data-type "boolean", :description {:fi "Onko kohteessa yleiseen käyttöön tarkoitettuja wc-tiloja?", :se "Är allmänna toaletten i användning", - :en ""}}, + :en "Are there public restroom facilities available at the location"}}, :gymnastics-space? {:name {:fi "Telinevoimistelutila", @@ -880,7 +880,7 @@ :description {:fi "Onko liikuntasalissa myös telinevoimistelutila", :se "Har motionssalen också område/utrymme för redskapsgymnastik", - :en ""}}, + :en "Is there also a gymnastics area in the sports hall"}}, :snooker-tables-count {:name {:fi "Snookerpöydät lkm", @@ -895,14 +895,14 @@ {:fi "Onko ratsastuskentällä/maneesissa esteratsastukseen soveltuva varustus", :se "Har ridplanen/ridhuset utrustning för banhoppning", - :en ""}}, + :en "Is there equipment suitable for show jumping in the riding arena/indoor arena"}}, :shower? {:name {:fi "Suihku", :se "Dusch", :en "Shower"}, :data-type "boolean", :description {:fi "Onko suihku käytettävissä", :se "Är duschen i användning", - :en ""}}, + :en "Is there a shower available"}}, :rest-places-count {:name {:fi "Taukopaikat lkm", @@ -912,7 +912,7 @@ :description {:fi "Montako taukopaikkaa reitin varrella on", :se "Hur många viloplatser finns det längs med rutten", - :en ""}}, + :en "How many rest areas are there along the route"}}, :changing-rooms? {:name {:fi "Pukukopit", :se "Omklädningsrum", :en "Changing rooms"}, :data-type "boolean", @@ -925,7 +925,7 @@ :description {:fi "Pistooliammuntamahdollisuus", :se "Möjlighet för pistolskytte", - :en ""}}, + :en "Availability of pistol shooting"}}, :halfpipe-count {:name {:fi "Halfpipe lkm", :se "Antal halfpipe", :en "Halfpipe count"}, @@ -933,7 +933,7 @@ :description {:fi "Halfpipe, superpipe lukumäärät", :se "Antal halfpipe", - :en ""}}, + :en "The number of halfpipes and superpipes"}}, :shooting-positions-count {:name {:fi "Ampumapaikat lkm", @@ -943,7 +943,7 @@ :description {:fi "Montako ampumapaikkaa liikuntareitin varrella on", :se "Hur många skytteplatser finns det längs motionsrutten", - :en ""}}, + :en "How many shooting spots are there along the exercise route"}}, :running-track-surface-material {:name {:fi "Juoksuradan pintamateriaali", @@ -953,7 +953,7 @@ :description {:fi "Juoksuradan pintamateriaali/päällyste", :se "Löpbanans ytmaterial/pålägg", - :en ""}}, + :en "The surface material/overlay of the running track"}}, :boating-service-class {:name {:fi "Venesatama- tai laituriluokka", @@ -1046,7 +1046,7 @@ :description {:fi "Montako kilometriä reitistä on valaistua", :se "Hur många km av rutten är uppbelyst", - :en ""}}, + :en "How many kilometers of the route are illuminated"}}, :area-m2 {:name {:fi "Liikuntapinta-ala m2", @@ -1056,7 +1056,7 @@ :description {:fi "Liikuntapaikan liikuntapinta-ala, neliömetreinä", :se "Idrottsplatsens areal i kvadratmeter", - :en ""}}, + :en "The sports area of the facility in square meters"}}, :field-width-m {:name {:fi "Kentän leveys m", :se "Planens bredd m", :en "Width of field"}, @@ -1064,14 +1064,14 @@ :description {:fi "Kentän/kenttien leveys mahdollisine turva-alueineen metreinä", :se "Planens/planernas bredd i meter", - :en ""}}, + :en "The width of the field(s), including any safety zones, in meters"}}, :cosmic-bowling? {:name {:fi "Hohtokeilaus", :se "Discobowling", :en "Cosmic bowling"}, :data-type "boolean", :description {:fi "Onko keilaradalla hohtokeilausmahdollisuus", :se "Har bowlingsbanan möjlighet för discobowling", - :en ""}}, + :en "Is there an option for glow bowling at the bowling alley"}}, :travel-modes {:name {:fi "Kulkutavat", :se "Resesätt", :en "Travel Modes"}, :data-type "enum-coll", @@ -1126,7 +1126,7 @@ "Uimaranta, joka täyttää EU-kriteerit uimaveden laadusta ja valvonnasta", :se "Badstrand, som fyller EU-kriterierna med kvaliteten och övervakningen av badvattnet", - :en ""}}, + :en "A swimming beach that meets EU criteria for bathing water quality and monitoring"}}, :rifle-shooting? {:name {:fi "Kivääriammunta", :se "Gevärbana", :en "Rifle shooting places"}, @@ -1134,7 +1134,7 @@ :description {:fi "Kivääriammuntamahdollisuus", :se "Möjlighet för gevärskytte", - :en ""}}, + :en "Availability of rifle shooting"}}, :swimming-pool-count {:name {:fi "Altaiden lukumäärä", @@ -1145,7 +1145,7 @@ {:fi "Altaiden lukumäärä yhteensä. Syötä tieto tai laske automaattisesti.", :se "Antalet simbassänger, också terapi bassänger", - :en ""}}, + :en "Total number of pools. Enter the information or calculate automatically."}}, :pool-water-area-m2 {:name {:fi "Vesipinta-ala m2", @@ -1326,7 +1326,7 @@ :description {:fi "1. altaan/pääaltaan pituus metreinä", :se "Första/huvudbassängens längd i meter", - :en ""}}, + :en "The length of the pool/main pool in meters."}}, :other-pools-count {:name {:fi "Muut altaat lkm", @@ -1363,7 +1363,7 @@ :description {:fi "Squash-kenttien lukumäärä", :se "Antalet squash-planer", - :en ""}}, + :en "The number of squash courts"}}, :changing-rooms-m2 {:name {:fi "Pukukoppien kokonaispinta-ala m²", @@ -1388,14 +1388,14 @@ :description {:fi "Nyrkkeilykehien lukumäärä", :se "Antalet boxningsringar", - :en ""}}, + :en "The number of boxing rings"}}, :ice-reduction? {:name {:fi "Jäätymisenesto", :se "Frostskydd", :en "Ice reduction"}, :data-type "boolean", :description {:fi "Jäätymisenestojärjestelmä talviuintipaikassa", :se "Har vinterbadplatsen mekanism för frostskydd", - :en ""}}, + :en "Anti-freeze system at the winter swimming location"}}, :activity-service-company? {:name {:fi "Ohjelmapalveluyritys", :se "", :en "Activity service company"}, @@ -1418,7 +1418,7 @@ :description {:fi "Miekkailualustojen lukumäärä", :se "Antal underlägg avsedda för fäktning", - :en ""}}, + :en "The number of fencing mats"}}, :weight-lifting-spots-count {:name {:fi "Painonnostopaikat/nostolavat lkm", @@ -1441,7 +1441,7 @@ :description {:fi "Alastulomonttujen lukumäärä", :se "Antalet landnigsgropar", - :en ""}}, + :en "The number of landing pits"}}, :bike-orienteering? {:name {:fi "Pyöräsuunnistus mahdollista", @@ -1455,14 +1455,14 @@ :description {:fi "Onko rinnehiihtokeskuksessa ohjaskelkkamäki", :se "Har skidcentrumet en rodelbana", - :en ""}}, + :en "Is there a guided sledding slope at the ski resort?"}}, :sauna? {:name {:fi "Sauna", :se "Bastu", :en "Sauna"}, :data-type "boolean", :description {:fi "Onko sauna käytettävissä", :se "Är bastun i användning", - :en ""}}, + :en "Is there a sauna available"}}, :jumps-count {:name {:fi "Hyppyrien lkm", @@ -1480,7 +1480,7 @@ :description {:fi "Pingis-/pöytätennispöytien lukumäärä", :se "Antal bordtennisbord (pingisbord)", - :en ""}}, + :en "The number of table tennis tables"}}, :pool-max-depth-m {:name {:fi "1. altaan syvyys max m", @@ -1490,7 +1490,7 @@ :description {:fi "1. altaan syvyys syvimmästä päästä metreinä", :se "Första bassängens djupaste punkt i meter", - :en ""}}, + :en "The depth of the deepest end of the pool in meter"}}, :loudspeakers? {:name {:fi "Äänentoisto", :se "Ljudåtergivning", :en "Loudspeakers"}, :data-type "boolean", @@ -1499,7 +1499,7 @@ "Onko liikuntapaikalla välineistö ja valmius kenttäkuulutuksiin", :se "Har motionsplatsen utrustning och färdighet till att göra utrop", - :en ""}}, + :en "Does the sports facility have equipment and readiness for making announcements"}}, :customer-service-point? {:name {:fi "Myynti- tai asiakaspalvelupiste", @@ -1522,7 +1522,7 @@ :description {:fi "Haulikkoammuntamahdollisuus", :se "Möjlighet för hagelskytte", - :en ""}}, + :en "Availability of shotgun shooting"}}, :water-point {:name {:fi "Vesipiste", :en "Water point", :se "Vattenpunkt"}, :description {:fi "", :se "", :en ""}, @@ -1544,14 +1544,14 @@ :description {:fi "Montako rinnettä on valaistu", :se "Hur många belysta slalombackar finns det", - :en ""}}, + :en "How many slopes are illuminated"}}, :green? {:name {:fi "Puttausviheriö", :se "Puttnings green", :en "Green"}, :data-type "boolean", :description {:fi "Onko golfkentällä puttausviheriö", :se "Finns det en puttnings green vid golfbanan", - :en ""}}, + :en "Is there a putting green on the golf course"}}, :free-rifle-shooting? {:name {:fi "Pienoiskivääriammunta", @@ -1561,7 +1561,7 @@ :description {:fi "Pienoiskivääriammuntamahdollisuus", :se "Möjlighet förminiatyrgevärskytte", - :en ""}}, + :en "Availability of small bore rifle shooting"}}, :winter-usage? {:name {:fi "Talvikäyttö", :se "Vinterbruk", :en "Winter usage"}, :data-type "boolean", @@ -1575,7 +1575,7 @@ :description {:fi "Onko liikuntapaikka valaistu", :se "Är idrottsplatsen uppbelyst", - :en ""}}, + :en "Is the sports facility illuminated"}}, :field-3-area-m2 {:name {:fi "3. kentän ala m2", @@ -1585,7 +1585,7 @@ :description {:fi "3. kentän pinta-ala neliömetreinä", :se "Tredje planens areal i kvadratmeter", - :en ""}}, + :en "The area of the field in square meters"}}, :accessibility-info {:name {:fi "Linkki esteettömyystietoon", @@ -1608,14 +1608,14 @@ :description {:fi "Katetun katsomon henkilömäärä", :se "Hur mycket av läktaren är täckt med tak, antalet personer", - :en ""}}, + :en "The seating capacity of the covered grandstand"}}, :playground? {:name {:fi "Leikkipuisto", :se "Lekpark", :en "Playground"}, :data-type "boolean", :description {:fi "Onko liikuntapaikan yhteydessä leikkipuisto", :se "Finns det en lekpark i samband med idrottsplatsen", - :en ""}}, + :en "Is there a playground associated with the sports facility"}}, :handball-fields-count {:name {:fi "Käsipallokentät lkm", @@ -1625,14 +1625,14 @@ :description {:fi "Käsipallokenttien lukumäärä salissa", :se "Antalet handbollsplaner som ryms i salen/hallen", - :en ""}}, + :en "The number of handball courts in the hall"}}, :p-point {:name {:fi "P-piste", :se "P-punkt", :en "P point"}, :data-type "numeric", :description {:fi "Hyppyrimäen P-piste metreinä", :se "Hoppbackens P-punkt i meter", - :en ""}}, + :en "The P-point of the ski jumping hill in meters"}}, :inruns-material {:name {:fi "Vauhtimäen latumateriaali", @@ -1642,7 +1642,7 @@ :description {:fi "Hyppyrimäen vauhtimäen materiaali", :se "Hoppbackens spårmaterial vid överbacken", - :en ""}}, + :en "The material of the take-off ramp of the ski jumping hill"}}, :pyramid-tables-count {:name {:fi "Pyramidipöydät lkm", @@ -1661,7 +1661,7 @@ "Onko liikuntapaikka normaali koripallokenttä, minikoripallokenttä vai yhden korin koripallokenttä", :se "Har idrottsplaten en normal korgbollsplan, mini-korgbollsplan eller bara en korg", - :en ""}}, + :en "Is the sports facility a standard basketball court, a mini basketball court, or a one-basket basketball court"}}, :kaisa-tables-count {:name {:fi "Kaisapöydät lkm", @@ -1678,7 +1678,7 @@ :description {:fi "Lentopallokenttien lukumäärä", :se "Antalet volleybollplaner", - :en ""}}, + :en "The number of volleyball courts"}}, :boat-places-count {:name {:fi "Venepaikat lkm", :se "Antalet båtplats", :en "Boat places"}, @@ -1694,7 +1694,7 @@ :description {:fi "1. altaan veden lämpötila celsiusasteina", :se "Första bassängens vatten temperatur i celcius", - :en ""}}, + :en "The water temperature of the pool in degrees Celsius"}}, :climbing-wall? {:name {:fi "Kiipeilyseinä", :se "Klättervägg", :en "Climbing wall"}, :data-type "boolean", @@ -1709,14 +1709,14 @@ :description {:fi "Vapaan tyylin latu-ura/luistelu-ura", :se "Skidspår för fristil", - :en ""}}, + :en "Free style track/skating track"}}, :spinning-hall? {:name {:fi "Spinning-sali", :se "Spinning sal", :en "Spinning hall"}, :data-type "boolean", :description {:fi "Salissa spinning-varustus", :se "Salen har spinning utrustning", - :en ""}}, + :en "Spinning equipment in the hall"}}, :other-platforms? {:name {:fi "Muut hyppytelineet", @@ -1726,7 +1726,7 @@ :description {:fi "Uimahyppytelineet rannalla", :se "Hopptornen vid stranden", - :en ""}}, + :en "Diving boards at the beach"}}, :school-use? {:name {:fi "Koululiikuntapaikka", @@ -1736,7 +1736,7 @@ :description {:fi "Liikuntapaikkaa käytetään koulujen liikuntatunneilla", :se "Idrottsplatsen används under skolornas gymnastiktimmar", - :en ""}}, + :en "The sports facility is used for school physical education classes"}}, :highjump-places-count {:name {:fi "Korkeushyppypaikat lkm", @@ -1746,7 +1746,7 @@ :description {:fi "Korkeushppypaikkojen lukumäärä", :se "Antalet höjdhoppsplatser", - :en ""}}, + :en "The number of high jump areas"}}, :light-roof? {:name {:fi "Kevytkate", :se "Lättvikts takläggning", :en "Light roof"}, @@ -1755,7 +1755,7 @@ {:fi "Kentälle voidaan asentaa kevytkate tai muu tilapäinen katos", :se "På planen kan installeras en lättvikts takläggning eller något annat tillfälligt tak", - :en ""}}, + :en "A lightweight cover or another temporary canopy can be installed on the field"}}, :route-length-km {:name {:fi "Reitin pituus km", @@ -1765,7 +1765,7 @@ :description {:fi "Reitin pituus kilometreinä", :se "Ruttens längd i kilometer", - :en ""}}, + :en "The length of the route in kilometers"}}, :field-3-flexible-rink? {:name {:fi "3. kenttä: onko joustokaukalo?", @@ -1782,11 +1782,11 @@ :description {:fi "Kuntoilulaitteiden lukumäärä", :se "Antalet gym apparater", - :en ""}}, + :en "The number of exercise machines"}}, :track-type {:name {:fi "Ratatyyppi", :se "Typ av bana", :en "Type of track"}, :data-type "string", - :description {:fi "Radan tyyppi", :se "Banans typ", :en ""}}, + :description {:fi "Radan tyyppi", :se "Banans typ", :en "The type of the track"}}, :training-spot-surface-material {:name {:fi "Suorituspaikan pintamateriaali", @@ -1796,7 +1796,7 @@ :description {:fi "Esim. keihäänheittopaikan pintamateriaali/päällys", :se "T.ex. spjutkastningsplatsens ytmaterial/överläggning", - :en ""}}, + :en "E.g. the surface material/overlay of the javelin throw area."}}, :range? {:name {:fi "Harjoitusalue/range", :se "Övningszon/Range", :en "Range"}, @@ -1804,7 +1804,7 @@ :description {:fi "Onko golfin harjoitusalue/range", :se "Finns det övningsområde/range för golf", - :en ""}}, + :en "Is there a golf practice area/range"}}, :track-length-m {:name {:fi "Radan pituus m", @@ -1814,7 +1814,7 @@ :description {:fi "Juoksuradan, pyöräilyradan tms. pituus metreinä", :se "Löpbanans, rundbanans el.dyl. längd i meter", - :en ""}}}) + :en "The length of the running track, cycling track, etc., in meters"}}}) (def used (let [used (set (mapcat (comp keys :props second) types/all))] diff --git a/webapp/src/cljc/lipas/data/types.cljc b/webapp/src/cljc/lipas/data/types.cljc index 96c20c40c..73021b607 100644 --- a/webapp/src/cljc/lipas/data/types.cljc +++ b/webapp/src/cljc/lipas/data/types.cljc @@ -1766,9 +1766,10 @@ "Includes bleachers, whose size is specified in properties. Number of fields, heating, changing rooms, etc., specified in properties."}, :tags {:fi ["jäähalli"]}, :additional-type - {:small {:fi "Pieni kilpahalli > 500 hlö", :en nil, :se nil}, - :competition {:fi "Kilpahalli < 3000 hlö", :en nil, :se nil}, - :large {:fi "Suurhalli > 3000 hlö", :en nil, :se nil}}, + {:small {:fi "Pieni kilpahalli > 500 hlö", :en "Small competition hall > 500 people", :se "Liten tävlingshall > 500 personer"}, + :competition {:fi "Kilpahalli < 3000 hlö", :en "Competition hall < 3000 people", :se "Tävlingshall < 3000 personer"}, + :large {:fi "Suurhalli > 3000 hlö", :en "Large hall > 3000 people", :se "Större hall > 3000 personer"}} +, :name {:fi "Kilpajäähalli", :se "Tävlingsishall", @@ -4309,8 +4310,8 @@ {:description {:fi "Melontaan tarkoitettu palvelupaikka, jossa voi olla esim. vuokrauspalveluita. Melontakeskuksesta voi lähteä melontareitti tai sen yhteydessä voi olla melontaratoja.", - :se "", - :en ""}, + :se "En paddlingsanläggning med uthyrningstjänster. Från paddlingscentret kan det finnas paddelleder eller paddelbanor i närheten.", + :en "A canoeing facility with rental services. From the canoeing center, there may be canoeing routes or paddling tracks nearby."}, :tags {:fi ["melonta" "kajakki" "kanootti" "melontakeskus"]}, :name {:fi "Melontakeskus", From c5fa93626eb85985e9d1e4e41c47dd2b3b227ea9 Mon Sep 17 00:00:00 2001 From: Valtteri Harmainen Date: Sun, 27 Oct 2024 19:46:29 +0200 Subject: [PATCH 14/68] Tweak symbol colors --- webapp/src/cljc/lipas/data/styles.cljc | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/webapp/src/cljc/lipas/data/styles.cljc b/webapp/src/cljc/lipas/data/styles.cljc index ac29dffa2..ed190bf9f 100644 --- a/webapp/src/cljc/lipas/data/styles.cljc +++ b/webapp/src/cljc/lipas/data/styles.cljc @@ -412,7 +412,7 @@ :stroke {:color "#000000"}}, 103 {:shape "polygon", - :fill {:color "#57fba0"}, + :fill {:color "#57fbc4"}, :stroke {:color "#000000", :width 1.5}}, 201 {:shape "circle", @@ -743,7 +743,7 @@ 4407 {:shape "linestring", :stroke - {:color "#f77ec3", + {:color "#827e3b", :width 3.5, :line-cap "round", :line-join "round", @@ -779,12 +779,12 @@ 1190 {:shape "circle", :radius 9, - :fill {:color "#f2d3ef"}, + :fill {:color "#f0c0eb"}, :stroke {:color "#000000"}} ;; Golfkenttä (alue) 1650 {:shape "polygon", - :fill {:color "#9efa52"}, + :fill {:color "#c9ff05"}, :stroke {:color "#000000" :width 1.5}} ;; Sisäleikki-/aktiviteettipuisto: 2225 @@ -798,16 +798,17 @@ :radius 9, :fill {:color "#9afcc0"}, :stroke {:color "#000000"}} + ;; Vesiurheilukeskus 3250 {:shape "circle", :radius 9, - :fill {:color "#6e6d91"}, + :fill {:color "#60669c"}, :stroke {:color "#000000"}} ;; Jousiammuntamaastorata 4840 {:shape "circle", :radius 9, - :fill {:color "#948938"}, + :fill {:color "#dcc210"}, :stroke {:color "#000000"}} ;; Monikäyttöalueet ja virkistysmetsät, joissa on virkistyspalveluita 106 From cbd47400e04c9f5ddc9e31c9606ff1f99689050b Mon Sep 17 00:00:00 2001 From: Valtteri Harmainen Date: Mon, 28 Oct 2024 21:48:36 +0200 Subject: [PATCH 15/68] More symbol color tweaking --- webapp/src/cljc/lipas/data/styles.cljc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/webapp/src/cljc/lipas/data/styles.cljc b/webapp/src/cljc/lipas/data/styles.cljc index ed190bf9f..d53dd86a8 100644 --- a/webapp/src/cljc/lipas/data/styles.cljc +++ b/webapp/src/cljc/lipas/data/styles.cljc @@ -300,7 +300,7 @@ :stroke {:color "#000000"}}, 109 {:shape "polygon", - :fill {:color "#94d024"}, + :fill {:color "#1f805f"}, :stroke {:color "#000000", :width 1.5}}, 5160 {:shape "square", @@ -453,7 +453,7 @@ :stroke {:color "#000000"}}, 107 {:shape "polygon", - :fill {:color "#daab0c"}, + :fill {:color "#c18bd6"}, :stroke {:color "#000000", :width 1.5}}, 6110 {:shape "circle", @@ -743,7 +743,7 @@ 4407 {:shape "linestring", :stroke - {:color "#827e3b", + {:color "#b0a92c", :width 3.5, :line-cap "round", :line-join "round", @@ -784,7 +784,7 @@ ;; Golfkenttä (alue) 1650 {:shape "polygon", - :fill {:color "#c9ff05"}, + :fill {:color "#daab0c"}, :stroke {:color "#000000" :width 1.5}} ;; Sisäleikki-/aktiviteettipuisto: 2225 From 63754740ae6949939a9af08fe5f96f88b6547791 Mon Sep 17 00:00:00 2001 From: Valtteri Harmainen Date: Mon, 28 Oct 2024 22:08:56 +0200 Subject: [PATCH 16/68] Format --- webapp/src/cljs/lipas/ui/sports_sites/subs.cljs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/webapp/src/cljs/lipas/ui/sports_sites/subs.cljs b/webapp/src/cljs/lipas/ui/sports_sites/subs.cljs index d1a7569d8..76903ae2b 100644 --- a/webapp/src/cljs/lipas/ui/sports_sites/subs.cljs +++ b/webapp/src/cljs/lipas/ui/sports_sites/subs.cljs @@ -282,8 +282,7 @@ :distance-m (* 1000 distance-km)}))))))))))) -(rf/reg-sub - ::elevation-stats +(rf/reg-sub ::elevation-stats (fn [[_ lipas-id]] (rf/subscribe [:lipas.ui.sports-sites.subs/elevation lipas-id])) (fn [elevation _] From 757cf46e4eb82cf21bc9a1a95dde1342eba2ddfc Mon Sep 17 00:00:00 2001 From: Valtteri Harmainen Date: Wed, 30 Oct 2024 21:56:21 +0200 Subject: [PATCH 17/68] Fix Ovaalirata geom type --- webapp/src/cljc/lipas/data/types.cljc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/src/cljc/lipas/data/types.cljc b/webapp/src/cljc/lipas/data/types.cljc index 73021b607..a90e2e710 100644 --- a/webapp/src/cljc/lipas/data/types.cljc +++ b/webapp/src/cljc/lipas/data/types.cljc @@ -1971,7 +1971,7 @@ :main-category 6000, :status "active", :sub-category 6100, - :geometry-type "LineString", + :geometry-type "Point", :props {:surface-material {:priority 0}, :surface-material-info {:priority 0}, From 7268d7d8b6ae0f5587c411de8d6d9f6a60712a92 Mon Sep 17 00:00:00 2001 From: Juho Teperi Date: Fri, 1 Nov 2024 15:10:33 +0200 Subject: [PATCH 18/68] Code formatting --- webapp/src/cljs/lipas/ui/map/styles.cljs | 28 +++---- .../src/cljs/lipas/ui/sports_sites/subs.cljs | 80 +++++++++---------- .../src/cljs/lipas/ui/sports_sites/views.cljs | 21 +++-- 3 files changed, 63 insertions(+), 66 deletions(-) diff --git a/webapp/src/cljs/lipas/ui/map/styles.cljs b/webapp/src/cljs/lipas/ui/map/styles.cljs index b5495044f..820ed89bf 100644 --- a/webapp/src/cljs/lipas/ui/map/styles.cljs +++ b/webapp/src/cljs/lipas/ui/map/styles.cljs @@ -108,22 +108,22 @@ :width 1}) stroke-planned (Stroke. - #js{:color "#b1b7c4" - :lineDash #js[2 20] - ; :lineDashOffset 1 - :width (case (:shape m) - ("polygon" "linestring") 7 - ("circle") 5 - ("square") 4)}) + #js {:color "#b1b7c4" + :lineDash #js [2 20] + ; :lineDashOffset 1 + :width (case (:shape m) + ("polygon" "linestring") 7 + ("circle") 5 + ("square") 4)}) stroke-planning (Stroke. - #js{:color "#ee00ee" - :lineDash #js[2 20] - ; :lineDashOffset 1 - :width (case (:shape m) - ("polygon" "linestring") 7 - ("circle") 5 - ("square") 4)}) + #js {:color "#ee00ee" + :lineDash #js [2 20] + ; :lineDashOffset 1 + :width (case (:shape m) + ("polygon" "linestring") 7 + ("circle") 5 + ("square") 4)}) stroke (Stroke. #js {:color stroke-color :lineDash (when (or selected? hover?) diff --git a/webapp/src/cljs/lipas/ui/sports_sites/subs.cljs b/webapp/src/cljs/lipas/ui/sports_sites/subs.cljs index 76903ae2b..46fe0184e 100644 --- a/webapp/src/cljs/lipas/ui/sports_sites/subs.cljs +++ b/webapp/src/cljs/lipas/ui/sports_sites/subs.cljs @@ -1,14 +1,13 @@ (ns lipas.ui.sports-sites.subs - (:require - ["@turf/helpers" :refer [lineString]] - ["@turf/length$default" :as turf-length] - [clojure.spec.alpha :as s] - [lipas.data.prop-types :as prop-types] - [lipas.data.types :as types] - [lipas.roles :as roles] - [lipas.ui.utils :as utils] - [lipas.utils :as cutils] - [re-frame.core :as rf])) + (:require ["@turf/helpers" :refer [lineString]] + ["@turf/length$default" :as turf-length] + [clojure.spec.alpha :as s] + [lipas.data.prop-types :as prop-types] + [lipas.data.types :as types] + [lipas.roles :as roles] + [lipas.ui.utils :as utils] + [lipas.utils :as cutils] + [re-frame.core :as rf])) (rf/reg-sub ::sports-sites (fn [db _] @@ -281,22 +280,21 @@ :distance-km distance-km :distance-m (* 1000 distance-km)}))))))))))) - (rf/reg-sub ::elevation-stats - (fn [[_ lipas-id]] - (rf/subscribe [:lipas.ui.sports-sites.subs/elevation lipas-id])) - (fn [elevation _] - (for [segment elevation] - (->> segment - (map :elevation-m) - (partition 2 1) - (reduce (fn [res [prev curr]] - (let [d (- curr prev)] - (cond - (zero? d) res - (pos? d) (update res :ascend-m + d) - (neg? d) (update res :descend-m + (Math/abs d))))) - {:ascend-m 0 :descend-m 0}))))) + (fn [[_ lipas-id]] + (rf/subscribe [:lipas.ui.sports-sites.subs/elevation lipas-id])) + (fn [elevation _] + (for [segment elevation] + (->> segment + (map :elevation-m) + (partition 2 1) + (reduce (fn [res [prev curr]] + (let [d (- curr prev)] + (cond + (zero? d) res + (pos? d) (update res :ascend-m + d) + (neg? d) (update res :descend-m + (Math/abs d))))) + {:ascend-m 0 :descend-m 0}))))) (rf/reg-sub ::display-site (fn [[_ lipas-id] _] @@ -335,16 +333,16 @@ city (get cities (-> latest :location :city :city-code)) status (statuses (-> latest :status)) - get-material #(get-in materials [% locale]) - get-travel-mode #(get-in prop-types/all [:travel-modes :opts % :label locale]) + get-material #(get-in materials [% locale]) + get-travel-mode #(get-in prop-types/all [:travel-modes :opts % :label locale]) - get-parkour-structure #(get-in prop-types/all [:parkour-hall-equipment-and-structures :opts % :label locale]) + get-parkour-structure #(get-in prop-types/all [:parkour-hall-equipment-and-structures :opts % :label locale]) - get-boating-service-class #(get-in prop-types/all [:boating-service-class :opts % :label locale]) + get-boating-service-class #(get-in prop-types/all [:boating-service-class :opts % :label locale]) - get-water-point #(get-in prop-types/all [:water-point :opts % :label locale]) + get-water-point #(get-in prop-types/all [:water-point :opts % :label locale]) - get-sport-specification #(get-in prop-types/all [:sport-specification :opts % :label locale]) ] + get-sport-specification #(get-in prop-types/all [:sport-specification :opts % :label locale])] (merge {:status (-> status locale) @@ -368,16 +366,16 @@ :construction-year (-> latest :construction-year) :renovation-years (-> latest :renovation-years) - :properties (-> latest - :properties - (update :surface-material #(map get-material %)) - (update :running-track-surface-material get-material) - (update :training-spot-surface-material get-material) - (update :travel-modes #(map get-travel-mode %)) - (update :parkour-hall-equipment-and-structures #(map get-parkour-structure %)) - (update :boating-service-class get-boating-service-class) - (update :water-point get-water-point) - (update :sport-specification get-sport-specification)) + :properties (-> latest + :properties + (update :surface-material #(map get-material %)) + (update :running-track-surface-material get-material) + (update :training-spot-surface-material get-material) + (update :travel-modes #(map get-travel-mode %)) + (update :parkour-hall-equipment-and-structures #(map get-parkour-structure %)) + (update :boating-service-class get-boating-service-class) + (update :water-point get-water-point) + (update :sport-specification get-sport-specification)) :location {:address (-> latest :location :address) diff --git a/webapp/src/cljs/lipas/ui/sports_sites/views.cljs b/webapp/src/cljs/lipas/ui/sports_sites/views.cljs index 461961660..f05435320 100644 --- a/webapp/src/cljs/lipas/ui/sports_sites/views.cljs +++ b/webapp/src/cljs/lipas/ui/sports_sites/views.cljs @@ -520,8 +520,7 @@ #_#_:tooltip tooltip :spec spec :type "number" - :on-change on-change}])]) - ) + :on-change on-change}])])) ;; Used from activities -> lipas-property now ;; Regular perustiedot uses the properties-form directly, which doesn't use this @@ -610,15 +609,15 @@ :label-fn (comp locale :name second)}] (= "enum-coll" data-type k) [lui/multi-select - {:items (:opts prop-type) - :deselect? true - :value value - :helper-text tooltip - :on-change on-change - :label label - :disabled disabled? - :value-fn first - :label-fn (comp locale :name second)}] + {:items (:opts prop-type) + :deselect? true + :value value + :helper-text tooltip + :on-change on-change + :label label + :disabled disabled? + :value-fn first + :label-fn (comp locale :name second)}] :else [lui/text-field {:value value From d33c5d4612888ac75594efa5478982e6697ee5a9 Mon Sep 17 00:00:00 2001 From: Juho Teperi Date: Fri, 1 Nov 2024 15:21:04 +0200 Subject: [PATCH 19/68] Cleanup --- webapp/src/cljs/lipas/ui/map/styles.cljs | 32 +++++++++---------- .../src/cljs/lipas/ui/sports_sites/subs.cljs | 4 +-- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/webapp/src/cljs/lipas/ui/map/styles.cljs b/webapp/src/cljs/lipas/ui/map/styles.cljs index 820ed89bf..f2d656b26 100644 --- a/webapp/src/cljs/lipas/ui/map/styles.cljs +++ b/webapp/src/cljs/lipas/ui/map/styles.cljs @@ -107,23 +107,21 @@ stroke-black (Stroke. #js {:color "#00000" :width 1}) - stroke-planned (Stroke. - #js {:color "#b1b7c4" - :lineDash #js [2 20] - ; :lineDashOffset 1 - :width (case (:shape m) - ("polygon" "linestring") 7 - ("circle") 5 - ("square") 4)}) - - stroke-planning (Stroke. - #js {:color "#ee00ee" - :lineDash #js [2 20] - ; :lineDashOffset 1 - :width (case (:shape m) - ("polygon" "linestring") 7 - ("circle") 5 - ("square") 4)}) + stroke-planned (Stroke. #js {:color "#b1b7c4" + :lineDash #js [2 20] + ; :lineDashOffset 1 + :width (case (:shape m) + ("polygon" "linestring") 7 + ("circle") 5 + ("square") 4)}) + + stroke-planning (Stroke. #js {:color "#ee00ee" + :lineDash #js [2 20] + ; :lineDashOffset 1 + :width (case (:shape m) + ("polygon" "linestring") 7 + ("circle") 5 + ("square") 4)}) stroke (Stroke. #js {:color stroke-color :lineDash (when (or selected? hover?) diff --git a/webapp/src/cljs/lipas/ui/sports_sites/subs.cljs b/webapp/src/cljs/lipas/ui/sports_sites/subs.cljs index 46fe0184e..be77ee4df 100644 --- a/webapp/src/cljs/lipas/ui/sports_sites/subs.cljs +++ b/webapp/src/cljs/lipas/ui/sports_sites/subs.cljs @@ -333,7 +333,7 @@ city (get cities (-> latest :location :city :city-code)) status (statuses (-> latest :status)) - get-material #(get-in materials [% locale]) + get-material #(get-in materials [% locale]) get-travel-mode #(get-in prop-types/all [:travel-modes :opts % :label locale]) get-parkour-structure #(get-in prop-types/all [:parkour-hall-equipment-and-structures :opts % :label locale]) @@ -426,7 +426,7 @@ (fn [v] (get-in audience-stand-access [v locale]))))) :locker-rooms (:locker-rooms latest) - :audits (:audits latest)}) + :audits (:audits latest)}) ;; TODO maybe check activities for type (when true From f996949a9614ab5e47cfcb83dc8b3e788ee4a878 Mon Sep 17 00:00:00 2001 From: Valtteri Harmainen Date: Sun, 3 Nov 2024 14:00:34 +0200 Subject: [PATCH 20/68] Add migration to populate new 'year-round-use' prop ...based on old `summer-usage?` and `winter-usage?` props. --- .../migrations/20241103113824-year-round-use.down.sql | 7 +++++++ .../migrations/20241103113824-year-round-use.up.sql | 7 +++++++ 2 files changed, 14 insertions(+) create mode 100644 webapp/resources/migrations/20241103113824-year-round-use.down.sql create mode 100644 webapp/resources/migrations/20241103113824-year-round-use.up.sql diff --git a/webapp/resources/migrations/20241103113824-year-round-use.down.sql b/webapp/resources/migrations/20241103113824-year-round-use.down.sql new file mode 100644 index 000000000..d29bf0038 --- /dev/null +++ b/webapp/resources/migrations/20241103113824-year-round-use.down.sql @@ -0,0 +1,7 @@ +UPDATE sports_site +SET document = jsonb_set( + document, + '{properties}', + (document::jsonb->'properties')::jsonb - 'year-round-use?' +) +WHERE document::jsonb->'properties' ? 'year-round-use?'; diff --git a/webapp/resources/migrations/20241103113824-year-round-use.up.sql b/webapp/resources/migrations/20241103113824-year-round-use.up.sql new file mode 100644 index 000000000..b69dcec18 --- /dev/null +++ b/webapp/resources/migrations/20241103113824-year-round-use.up.sql @@ -0,0 +1,7 @@ +UPDATE sports_site +SET document = jsonb_set(document, '{properties, year-round-use?}', 'true') +WHERE id IN ( + SELECT id + FROM sports_site_current + WHERE document::jsonb->'properties'->>'winter-usage?' = 'true' OR + document::jsonb->'properties'->>'summer-usage?' = 'true') From 9352db5cd3959333351d60d17f23217bfaff9514 Mon Sep 17 00:00:00 2001 From: Valtteri Harmainen Date: Sun, 3 Nov 2024 14:31:14 +0200 Subject: [PATCH 21/68] Add missing specs for new prop types --- webapp/dev/user.clj | 6 +++ .../src/cljc/lipas/data/prop_types_new.cljc | 2 +- webapp/src/cljc/lipas/schema/core.cljc | 40 +++++++++++++++---- 3 files changed, 39 insertions(+), 9 deletions(-) diff --git a/webapp/dev/user.clj b/webapp/dev/user.clj index 3173db25f..c4278864e 100644 --- a/webapp/dev/user.clj +++ b/webapp/dev/user.clj @@ -62,6 +62,7 @@ (require '[migratus.core :as migratus]) (migratus/create nil "activities_status" :sql) (migratus/create nil "roles" :edn) + (migratus/create nil "year_round_use" :sql) (require '[lipas.maintenance :as maintenance]) (require '[lipas.backend.core :as core]) @@ -72,4 +73,9 @@ (maintenance/merge-types (db) (search) robot 4520 4510) (maintenance/merge-types (db) (search) robot 4310 4320) + (require '[lipas.data.prop-types :as prop-types]) + (require '[lipas.data.prop-types-old :as prop-types-old]) + (require '[clojure.set :as set]) + (set/difference (set (keys prop-types/all)) (set (keys prop-types-old/all))) + ) diff --git a/webapp/src/cljc/lipas/data/prop_types_new.cljc b/webapp/src/cljc/lipas/data/prop_types_new.cljc index 253d2599c..e6e2fee5f 100644 --- a/webapp/src/cljc/lipas/data/prop_types_new.cljc +++ b/webapp/src/cljc/lipas/data/prop_types_new.cljc @@ -491,7 +491,7 @@ (assoc-in [:auxiliary-training-area? :description :fi] "Onko kohteessa oheisharjoitteluun soveltuva tila? Oheisharjoittelutila on liikuntapaikan käyttäjille tarkoitettu erillinen pienliikuntatila, jota voidaan käyttää esim. lämmittelyyn tai oheisharjoitteluun. Tilan koko, varustelu ja pintamateriaali ovat oheisharjoitteluun soveltuvia.") ;; Ominaisuuden nimi esim. "Lajitarkenne". Vastaava toiminnallisuus kuin veneilyn palvelupaikoissa - eli lisätiedoissa voidaan tarkentaa, minkä voimistelulajin harrastamiseen kohde on pääasiassa tarkoitettu. Vaihtoehdot: a. Lattialajit b. Telinelajit c. Lattia- ja telinelajit mahdollisia d. Pääasiassa cheerleading- tai sirkusharjoittelukäyttöön e. Ei tietoa (assoc-in [:sport-specification :description :fi] "Valitse voimistelulaji, johon tila on pääasiassa tarkoitettu.") - (assoc-in [:free-use :name :fi] "Kohde on vapaasti käytettävissä") + (assoc-in [:free-use? :name :fi] "Kohde on vapaasti käytettävissä") (assoc-in [:active-space-width-m :description :fi] "Liikuntakäytössä olevan tilan leveys (m)") (assoc-in [:active-space-length-m :description :fi] "Liikuntakäytössä olevan tilan pituus (m)") (assoc-in [:mirror-wall? :description :fi] "Liikuntatilassa vähintään yhdellä seinällä on kiinteät peilit") diff --git a/webapp/src/cljc/lipas/schema/core.cljc b/webapp/src/cljc/lipas/schema/core.cljc index fe3d28b33..ed11760a4 100644 --- a/webapp/src/cljc/lipas/schema/core.cljc +++ b/webapp/src/cljc/lipas/schema/core.cljc @@ -733,17 +733,17 @@ (s/def :lipas.sports-site.properties/ligthing-info string?) (s/def :lipas.sports-site.properties/highest-obstacle-m ::real) (s/def :lipas.sports-site.properties/fitness-stairs-length-m ::real) -(s/def :lipas.sports-site.properties/fitness-stairs-length-m ::real) (s/def :lipas.sports-site.properties/free-customer-use? boolean?) (s/def :lipas.sports-site.properties/space-divisible ::real) (s/def :lipas.sports-site.properties/auxiliary-training-area? boolean?) (s/def :lipas.sports-site.properties/sport-specification string?) -(s/def :lipas.sports-site.properties/width-of-active-space-m ::real) -(s/def :lipas.sports-site.properties/length-of-active-space-m ::real) +(s/def :lipas.sports-site.properties/active-space-width-m ::real) +(s/def :lipas.sports-site.properties/active-space-length-m ::real) (s/def :lipas.sports-site.properties/mirror-wall? boolean?) (s/def :lipas.sports-site.properties/parkour-hall-equipment-and-structures (s/coll-of - (into #{} (keys (get-in prop-types/all [:parkour-hall-equipment-and-structures :opts]))))) + (into #{} (keys (get-in prop-types/all [:parkour-hall-equipment-and-structures :opts]))) + :distinct true)) (s/def :lipas.sports-site.properties/ringette-boundary-markings? boolean?) (s/def :lipas.sports-site.properties/field-1-flexible-rink? boolean?) (s/def :lipas.sports-site.properties/field-2-flexible-rink? boolean?) @@ -756,7 +756,20 @@ (s/def :lipas.sports-site.properties/total-billiard-tables-count ::real) (s/def :lipas.sports-site.properties/boating-service-class (s/coll-of - (into #{} (keys (get-in prop-types/all [:boating-service-class :opts]))))) + (into #{} (keys (get-in prop-types/all [:boating-service-class :opts]))) + :distinct true)) +(s/def :lipas.sports-site.properties/travel-modes + (s/coll-of + (into #{} (keys (get-in prop-types/all [:travel-modes :opts]))) + :distinct true)) +(s/def :lipas.sports-site.properties/travel-mode-info string?) +(s/def :lipas.sports-site.properties/sledding-hill? boolean?) +(s/def :lipas.sports-site.properties/mobile-orienteering? boolean?) +(s/def :lipas.sports-site.properties/ski-orienteering? boolean?) +(s/def :lipas.sports-site.properties/bike-orienteering? boolean?) +(s/def :lipas.sports-site.properties/hs-point ::real) +(s/def :lipas.sports-site.properties/lighting-info string?) +(s/def :lipas.sports-site.properties/year-round-use? boolean?) (s/def :lipas.sports-site/properties (s/keys :opt-un [:lipas.sports-site.properties/height-m @@ -927,8 +940,8 @@ :lipas.sports-site.properties/space-divisible :lipas.sports-site.properties/auxiliary-training-area? :lipas.sports-site.properties/sport-specification - :lipas.sports-site.properties/width-of-active-space-m - :lipas.sports-site.properties/length-of-active-space-m + :lipas.sports-site.properties/active-space-width-m + :lipas.sports-site.properties/active-space-length-m :lipas.sports-site.properties/mirror-wall? :lipas.sports-site.properties/parkour-hall-equipment-and-structures :lipas.sports-site.properties/ringette-boundary-markings? @@ -941,7 +954,18 @@ :lipas.sports-site.properties/pyramid-tables-count :lipas.sports-site.properties/carom-tables-count :lipas.sports-site.properties/total-billiard-tables-count - :lipas.sports-site.properties/boating-service-class])) + :lipas.sports-site.properties/boating-service-class + :lipas.sports-site.properties/free-use? + :lipas.sports-site.properties/school-use? + :lipas.sports-site.properties/year-round-use? + :lipas.sports-site.properties/lighting-info + :lipas.sports-site.properties/hs-point + :lipas.sports-site.properties/bike-orienteering? + :lipas.sports-site.properties/ski-orienteering? + :lipas.sports-site.properties/mobile-orienteering? + :lipas.sports-site.properties/sledding-hill? + :lipas.sports-site.properties/travel-mode-info + :lipas.sports-site.properties/travel-modes])) (s/def :lipas.sports-site/properties-old (s/map-of keyword? (s/or :string? (str-in 1 100) From ccbe77d324324c3b953f84a27122d2b12540b7e5 Mon Sep 17 00:00:00 2001 From: Valtteri Harmainen Date: Sun, 3 Nov 2024 20:57:10 +0200 Subject: [PATCH 22/68] Fix --- webapp/src/cljc/lipas/data/prop_types.cljc | 1 - 1 file changed, 1 deletion(-) diff --git a/webapp/src/cljc/lipas/data/prop_types.cljc b/webapp/src/cljc/lipas/data/prop_types.cljc index fc543e503..35a80236e 100644 --- a/webapp/src/cljc/lipas/data/prop_types.cljc +++ b/webapp/src/cljc/lipas/data/prop_types.cljc @@ -416,7 +416,6 @@ {:fi "Onko jääkiipeily mahdollista kiipeilypaikalla", :se "Finns det möjlighet för isklättring vid klättringsplatsen", :en "Is ice climbing possible at the climbing site"}}, - :free-use {:name {:fi "Kohde on vapaasti käytettävissä"}}, :field-length-m {:name {:fi "Kentän pituus m", From 719c61fb5e79788c96cdc7945e75677e9405864e Mon Sep 17 00:00:00 2001 From: Valtteri Harmainen Date: Sun, 3 Nov 2024 20:58:49 +0200 Subject: [PATCH 23/68] Ensure legacy integration works with new types Legacy db has been updated with necessary changes in all envs --- .../integration/old_lipas/sports_site.clj | 39 ++++++++++++++++++- .../lipas/integration/old_lipas/transform.clj | 7 +++- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/webapp/src/clj/lipas/integration/old_lipas/sports_site.clj b/webapp/src/clj/lipas/integration/old_lipas/sports_site.clj index 3c5042177..529a9170d 100644 --- a/webapp/src/clj/lipas/integration/old_lipas/sports_site.clj +++ b/webapp/src/clj/lipas/integration/old_lipas/sports_site.clj @@ -198,7 +198,44 @@ :padelCourtsCount :padel-courts-count :rapidCanoeingCentre :rapid-canoeing-centre? :canoeingClub :canoeing-club? - :activityServiceCompany :activity-service-company?}) + :activityServiceCompany :activity-service-company? + :bikeOrienteering? :bike-orienteering?, + :field2FlexibleRink? :field-2-flexible-rink?, + :sportSpecification :sport-specification, + :travelModeInfo :travel-mode-info, + :spaceDivisible :space-divisible, + :auxiliaryTrainingArea? :auxiliary-training-area?, + :pyramidTablesCount :pyramid-tables-count, + :lightingInfo :lighting-info, + :customerServicePoint? :customer-service-point?, + :parkourHallEquipmentAndStructures + :parkour-hall-equipment-and-structures, + :waterPoint :water-point, + :activeSpaceWidthM :active-space-width-m, + :fitnessStairsLengthM :fitness-stairs-length-m, + :mirrorWall? :mirror-wall?, + :sleddingHill? :sledding-hill?, + :highestObstacleM :highest-obstacle-m, + :skiOrienteering? :ski-orienteering?, + :freeUse :free-use, + :totalBilliardTablesCount :total-billiard-tables-count, + :boatingServiceClass :boating-service-class, + :kaisaTablesCount :kaisa-tables-count, + :yearRoundUse? :year-round-use?, + :field1FlexibleRink? :field-1-flexible-rink?, + :mobileOrienteering? :mobile-orienteering?, + :field3FlexibleRink? :field-3-flexible-rink?, + :freeCustomerUse? :free-customer-use?, + :travelModes :travel-modes, + :heightOfBasketOrNetAdjustable? + :height-of-basket-or-net-adjustable?, + :caromTablesCount :carom-tables-count, + :changingRoomsM2 :changing-rooms-m2, + :poolTablesCount :pool-tables-count, + :ringetteBoundaryMarkings? :ringette-boundary-markings?, + :hsPoint :hs-point, + :snookerTablesCount :snooker-tables-count, + :activeSpaceLengthM :active-space-length-m}) (def prop-mappings-reverse (set/map-invert prop-mappings)) diff --git a/webapp/src/clj/lipas/integration/old_lipas/transform.clj b/webapp/src/clj/lipas/integration/old_lipas/transform.clj index 69fe3e54c..1d147d041 100644 --- a/webapp/src/clj/lipas/integration/old_lipas/transform.clj +++ b/webapp/src/clj/lipas/integration/old_lipas/transform.clj @@ -4,7 +4,8 @@ [clojure.spec.alpha :as spec] [lipas.data.types :as types] [lipas.integration.old-lipas.sports-site :as old] - [lipas.utils :as utils :refer [sreplace trim]])) + [lipas.utils :as utils :refer [sreplace trim]] + [clojure.string :as str])) (def helsinki-tz (java.time.ZoneId/of "Europe/Helsinki")) @@ -86,6 +87,10 @@ (comp old/surface-materials first)) (select-keys prop-keys) (assoc :info-fi (-> m :comment)) + (update :parkour-hall-equipment-and-structures + (fn [coll] (not-empty (str/join "," coll)))) + (update :travel-modes + (fn [coll] (not-empty (str/join "," coll)))) (set/rename-keys old/prop-mappings-reverse))) old/adapt-geoms utils/clean From e50784b663cfc1206e15d7f8d3a28fb722674ec8 Mon Sep 17 00:00:00 2001 From: Valtteri Harmainen Date: Mon, 4 Nov 2024 08:41:22 +0200 Subject: [PATCH 24/68] Fix --- webapp/src/cljc/lipas/data/types.cljc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/webapp/src/cljc/lipas/data/types.cljc b/webapp/src/cljc/lipas/data/types.cljc index a90e2e710..974e57f9e 100644 --- a/webapp/src/cljc/lipas/data/types.cljc +++ b/webapp/src/cljc/lipas/data/types.cljc @@ -1976,7 +1976,7 @@ {:surface-material {:priority 0}, :surface-material-info {:priority 0}, :track-width-m {:priority 0}, - :free-use {:priority 0}, + :free-use? {:priority 0}, :may-be-shown-in-harrastuspassi-fi? {:priority 0}, :toilet? {:priority 0}, :customer-service-point? {:priority 0}, @@ -2205,7 +2205,7 @@ :route-length-km {:priority 0}, :lit-route-length-km {:priority 0}, :route-width-m {:priority 0}, - :free-use {:priority 0}, + :free-use? {:priority 0}, :year-round-use? {:priority 0}}}, 5160 {:description @@ -3231,7 +3231,7 @@ {:surface-material {:priority 0}, :surface-material-info {:priority 0}, :outdoor-exercise-machines? {:priority 0}, - :free-use {:priority 0}, + :free-use? {:priority 0}, :route-width-m {:priority 0}, :may-be-shown-in-harrastuspassi-fi? {:priority 0}, :toilet? {:priority 0}, From c9497b898a2f88c92176823d73acd63759893e7c Mon Sep 17 00:00:00 2001 From: Valtteri Harmainen Date: Sun, 10 Nov 2024 12:43:12 +0200 Subject: [PATCH 25/68] user.clj --- webapp/dev/user.clj | 88 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 86 insertions(+), 2 deletions(-) diff --git a/webapp/dev/user.clj b/webapp/dev/user.clj index c4278864e..887bbe878 100644 --- a/webapp/dev/user.clj +++ b/webapp/dev/user.clj @@ -3,7 +3,8 @@ (:require [clojure.tools.namespace.repl] [integrant.repl :refer [reset reset-all halt go]] - [integrant.repl.state])) + [integrant.repl.state] + [lipas.data.prop-types :as prop-types])) (integrant.repl/set-prep! (fn [] (dissoc @(requiring-resolve 'lipas.backend.config/system-config) :lipas/nrepl))) @@ -73,9 +74,92 @@ (maintenance/merge-types (db) (search) robot 4520 4510) (maintenance/merge-types (db) (search) robot 4310 4320) + (require '[lipas.data.types :as types]) + (require '[lipas.data.types-old :as types-old]) (require '[lipas.data.prop-types :as prop-types]) (require '[lipas.data.prop-types-old :as prop-types-old]) (require '[clojure.set :as set]) - (set/difference (set (keys prop-types/all)) (set (keys prop-types-old/all))) + + (def new-types (set/difference + (set (keys types/all)) + (set (keys types-old/all)))) + + (require '[clojure.string :as str]) + + (for [type-code (conj new-types 113)] + (println + (format "INSERT INTO public.liikuntapaikkatyyppi( + id, tyyppikoodi, nimi_fi, nimi_se, kuvaus_fi, kuvaus_se, liikuntapaikkatyyppi_alaryhma, geometria, tason_nimi, nimi_en, kuvaus_en) + VALUES (%s, %s, '%s', '%s', '%s', '%s', %s, '%s', '%s', '%s', '%s');" + type-code + type-code + (get-in types/all [type-code :name :fi]) + (get-in types/all [type-code :name :se]) + (get-in types/all [type-code :description :fi]) + (get-in types/all [type-code :description :se]) + (get-in types/all [type-code :sub-category]) + (get-in types/all [type-code :geometry-type]) + (-> types/all + (get-in [type-code :name :fi]) + csk/->snake_case + (str/replace "ä" "a") + (str/replace "ö" "o") + (str/replace #"[^a-zA-Z]" "") + (->> (str "lipas_" type-code "_"))) + (get-in types/all [type-code :name :en]) + (get-in types/all [type-code :description :en])))) + + (def new-props (set/difference + (set (keys prop-types/all)) + (set (keys prop-types-old/all)))) + + new-props + + (require '[camel-snake-kebab.core :as csk]) + (def legacy-mapping (into {} (for [p new-props] + [(csk/->camelCaseKeyword p) p]))) + + (keys legacy-mapping) + + (def legacy-mapping-reverse (set/map-invert legacy-mapping)) + + (require '[lipas.data.prop-types :as prop-types]) + + (def data-types + "Legacy lipas supports only these. Others will be treated as strings" + {"boolean" "boolean" + "numeric" "numberic" + "string" "string"}) + + (doseq [[legacy-prop-k prop-k] legacy-mapping] + (println + (format "INSERT INTO public.ominaisuustyypit( + nimi_fi, tietotyyppi, kuvaus_fi, nimi_se, kuvaus_se, ui_nimi_fi, nimi_en, kuvaus_en, handle) + VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s');" + (csk/->snake_case (get-in prop-types/all [prop-k :name :fi])) + (get data-types (get-in prop-types/all [prop-k :data-type]) "string") + (get-in prop-types/all [prop-k :description :fi]) + (get-in prop-types/all [prop-k :name :se]) + (get-in prop-types/all [prop-k :description :se]) + (get-in prop-types/all [prop-k :name :fi]) + (get-in prop-types/all [prop-k :name :en]) + (get-in prop-types/all [prop-k :description :en]) + (name legacy-prop-k)))) + + (doseq [p new-props + [type-code m] types/all] + (when (contains? (set (keys (:props m))) p) + (println (str "-- Type " type-code)) + (println (str "-- prop " p)) + (println + (format + "INSERT INTO public.tyypinominaisuus( + liikuntapaikkatyyppi_id, ominaisuustyyppi_id, prioriteetti) + VALUES (%s, %s, %s);" + (format "(select id from liikuntapaikkatyyppi where tyyppikoodi = %s)" + type-code) + (format "(select id from ominaisuustyypit where handle = '%s')" + (name (legacy-mapping-reverse p))) + (get-in types/all [type-code :props p :priority]))))) ) From d3b63777cf6660f10d1076f1ee70a096249d922e Mon Sep 17 00:00:00 2001 From: Valtteri Harmainen Date: Tue, 12 Nov 2024 20:18:37 +0200 Subject: [PATCH 26/68] Assign new priorities for props --- webapp/src/cljc/lipas/data/types.cljc | 8637 +++++++++++++------------ 1 file changed, 4349 insertions(+), 4288 deletions(-) diff --git a/webapp/src/cljc/lipas/data/types.cljc b/webapp/src/cljc/lipas/data/types.cljc index 974e57f9e..f545246c1 100644 --- a/webapp/src/cljc/lipas/data/types.cljc +++ b/webapp/src/cljc/lipas/data/types.cljc @@ -329,4294 +329,4355 @@ (def all {1530 - {:description - {:fi - "Luisteluun, jääkiekkoon, kaukalopalloon, curlingiin tai muuhun jääurheiluun tarkoitettu kaukalo. Käytössä talvikaudella.", - :se - "Rink avsedd för skridskoåkning, ishockey, rinkbandy osv. Används under vintersäsongen.", - :en "Rink intended for ice-skating, ice hockey, rink bandy, etc."}, - :tags {:fi ["jääkiekkokaukalo"]}, - :name {:fi "Kaukalo", :se "Rink", :en "Rink"}, - :type-code 1530, - :main-category 1000, - :status "active", - :sub-category 1500, - :geometry-type "Point", - :props - {:surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :stand-capacity-person {:priority 0}, - :free-use? {:priority 0}, - :field-length-m {:priority 1}, - :match-clock? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :ice-rinks-count {:priority 0}, - :toilet? {:priority 0}, - :changing-rooms? {:priority 0}, - :area-m2 {:priority 1}, - :field-width-m {:priority 1}, - :lighting-info {:priority 0}, - :changing-rooms-m2 {:priority 0}, - :ligthing? {:priority 1}, - :school-use? {:priority 0}, - :light-roof? {:priority 0}}}, - 1520 - {:description - {:fi - "Luisteluun tarkoitettu luonnonmukainen kenttä. Jäädytetään käyttökuntoon talvikaudelle.", - :se "Plan avsedd för skridskoåkning. Används under vintersäsongen.", - :en "Field intended for ice-skating."}, - :tags {:fi []}, - :name - {:fi "Luistelukenttä", :se "Skridskobana", :en "Ice-skating field"}, - :type-code 1520, - :main-category 1000, - :status "active", - :sub-category 1500, - :geometry-type "Point", - :props - {:surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :stand-capacity-person {:priority 0}, - :free-use? {:priority 0}, - :field-length-m {:priority 1}, - :match-clock? {:priority 0}, - :fields-count {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :changing-rooms? {:priority 0}, - :area-m2 {:priority 1}, - :field-width-m {:priority 1}, - :lighting-info {:priority 0}, - :changing-rooms-m2 {:priority 0}, - :customer-service-point? {:priority 0}, - :ligthing? {:priority 1}, - :school-use? {:priority 0}, - :light-roof? {:priority 0}}}, - 2320 - {:description - {:fi - "Pysyvästi voimisteluun varustettu tila. Voimistelutilassa on erilaisia kiinteitä voimistelutelineitä ja -rakenteita (esim. volttimonttu, rekki tai trampoliini). Myös cheerleadingin ja sirkusharjoittelun olosuhteet luetaan voimistelutiloiksi. Tarkempi olosuhdetieto kerrotaan lisätiedoissa.", - :se "Permanent utrustning för att träna redskapsgymnastik.", - :en "Space permanently equipped for artistic gymnastics."}, - :tags {:fi ["monttu" "rekki" "nojapuut"]}, - :name - {:fi "Voimistelutila", - :se "Utrymme för redskapsgymnastik", - :en "Artistic gymnastics facility"}, - :type-code 2320, - :main-category 2000, - :status "active", - :sub-category 2300, - :geometry-type "Point", - :props - {:height-m {:priority 0}, - :surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :free-use? {:priority 0}, - :sport-specification {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :space-divisible {:priority 0}, - :gymnastic-routines-count {:priority 0}, - :area-m2 {:priority 1}, - :landing-places-count {:priority 0}, - :school-use? {:priority 0}}}, - 6130 - {:description - {:fi - "Pysyvästi esteratsastukseen varusteltu kenttä tai alue ulkona.", - :se "Bana med permanent utrustning för banhoppning", - :en "Field permanently equipped for show jumping. Outdoors."}, - :tags {:fi ["ratsastuskenttä"]}, - :name - {:fi "Esteratsastuskenttä/-alue", - :se "Bana för banhoppning", - :en "Show jumping field"}, - :type-code 6130, - :main-category 6000, - :status "active", - :sub-category 6100, - :geometry-type "Point", - :props - {:surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :free-use? {:priority 0}, - :field-length-m {:priority 1}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :area-m2 {:priority 1}, - :field-width-m {:priority 1}, - :lighting-info {:priority 0}, - :ligthing? {:priority 1}, - :school-use? {:priority 0}}}, - 1395 - {:description - {:fi - "Yksi tai useampi pöytätennispöytä ulkona. Pöytätennispöydän tulee olla sijoitettu niin, että pelaamiseen on riittävä tila pöydän ympärillä. Pöydän tulee olla pelikäyttöön soveltuva.", - :se - "Ett eller flera bordtennisbord utomhus. Bordet är lämpligt för spel och bör vara placerat så att det finns tillräckligt utrymme för spel.", - :en - "One or more outdoor table tennis tables in the same area. The table must be positioned so that there is enough space for playing. The table must be suitable for the sport."}, - :tags {:fi ["pöytätennis" "pingis" "ping pong"]}, - :name - {:fi "Pöytätennisalue", - :se "Område med bordtennisbord", - :en "Table tennis area"}, - :type-code 1395, - :main-category 1000, - :status "active", - :sub-category 1300, - :geometry-type "Point", - :props - {:free-use? {:priority 0}, - :table-tennis-count {:priority 1}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :ligthing? {:priority 1}, - :school-use? {:priority 0}, - :water-point {:priority 0}, - :lighting-info {:priority 0}}}, - 6210 - {:description - {:fi - "Koiran koulutukseen, agilityyn tai muuhun harjoittamiseen varattu ulkoalue.", - :se - "Område reserverat för hundträning, agility eller annan hundhobby.", - :en "Area reserved for dog training, agility or other dog sports."}, - :tags {:fi ["agility" "koirakenttä"]}, - :name - {:fi "Koiraurheilualue", - :se "Område för hundsport", - :en "Dog sports area"}, - :type-code 6210, - :main-category 6000, - :status "active", - :sub-category 6200, - :geometry-type "Point", - :props - {:surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :free-use? {:priority 0}, - :field-length-m {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :area-m2 {:priority 1}, - :field-width-m {:priority 0}, - :lighting-info {:priority 0}, - :ligthing? {:priority 1}, - :track-length-m {:priority 0}}}, - 1370 - {:description - {:fi - "Tennikseen tarkoitettu kenttä. Mahdollinen lyöntiseinä ja kentän pintamateriaali merkitään lisätietoihin.", - :se - "En eller flera tennisbanor på samma område. Antalet banor, ytmaterial mm i karakteristika. Även uppgift om slagväggen.", - :en - "One or more tennis courts in the same area. Number of courts, surface material, etc. specified in properties, including information about a potential hit wall."}, - :tags {:fi ["tenniskenttä"]}, - :name - {:fi "Tenniskenttä", - :se "Område med tennisbanor", - :en "Tennis court area"}, - :type-code 1370, - :main-category 1000, - :status "active", - :sub-category 1300, - :geometry-type "Point", - :props - {:surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :stand-capacity-person {:priority 0}, - :free-use? {:priority 0}, - :field-length-m {:priority 1}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :changing-rooms? {:priority 0}, - :area-m2 {:priority 1}, - :field-width-m {:priority 1}, - :lighting-info {:priority 0}, - :training-wall? {:priority 0}, - :water-point {:priority 0}, - :ligthing? {:priority 1}, - :school-use? {:priority 0}, - :light-roof? {:priority 0}}}, - 1360 - {:description - {:fi - "Pesäpalloon tarkoitettu kenttä. Jos kentän yhteydessä on katsomoita, lisätään kentän nimeen stadion-sana. Vähintään kansallisen tason pelipaikka. Pintamateriaali on esim. hiekka, hiekkatekonurmi tai muu synteettinen päällyste. Kentän koko on vähintään 50 x 100 m.", - :se - "En bobollsplan, kan ha flera läktare. Minimikrav: spelplats på nationell nivå. Sand, konstgräs med sand / annan syntetisk beläggning. >50 x 100 m.", - :en - "Finnish baseball field, may include stands. Can host at least national-level games. Sand, artificial turf / other synthetic surface, > 50 x 100 m. "}, - :tags {:fi ["pesäpallostadion"]}, - :name - {:fi "Pesäpallokenttä", :se "Bobollsplan", :en "Baseball field"}, - :type-code 1360, - :main-category 1000, - :status "active", - :sub-category 1300, - :geometry-type "Point", - :props - {:heating? {:priority 0}, - :surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :stand-capacity-person {:priority 0}, - :free-use? {:priority 0}, - :field-length-m {:priority 1}, - :match-clock? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :changing-rooms? {:priority 0}, - :area-m2 {:priority 1}, - :field-width-m {:priority 1}, - :lighting-info {:priority 0}, - :scoreboard? {:priority 0}, - :loudspeakers? {:priority 0}, - :customer-service-point? {:priority 0}, - :water-point {:priority 0}, - :ligthing? {:priority 1}, - :covered-stand-person-count {:priority 0}, - :school-use? {:priority 0}}}, - 110 - {:description - {:fi - "Erämaalailla perustetut alueet pohjoisimmassa Lapissa. Metsähallitus tietolähteenä.", - :se - "Grundade enligt ödemarkslagen, i nordligaste Lappland. Källa: Forststyrelsen.", - :en - "Areas located in northernmost Lapland, established based on the Wildeness Act (1991/62). Source of information Metsähallitus."}, - :tags {:fi []}, - :name - {:fi "Erämaa-alue", :se "Vildmarksområden", :en "Wilderness area"}, - :type-code 110, - :main-category 0, - :status "active", - :sub-category 1, - :geometry-type "Polygon", - :props - {:area-km2 {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, - 2360 - {:description - {:fi "Pysyvästi käytössä oleva ampumarata sisätiloissa.", - :se "Permanent skjutbana inomhus.", - :en "Permanent indoor shooting range."}, - :tags {:fi ["ilmakivääri" "ilma-ase" "ammunta"]}, - :name - {:fi "Sisäampumarata", - :se "Inomhusskjutbana", - :en "Indoor shooting range"}, - :type-code 2360, - :main-category 2000, - :status "active", - :sub-category 2300, - :geometry-type "Point", - :props - {:surface-material {:priority 0}, - :surface-material-info {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :air-gun-shooting? {:priority 0}, - :pistol-shooting? {:priority 0}, - :shooting-positions-count {:priority 1}, - :area-m2 {:priority 1}, - :rifle-shooting? {:priority 0}, - :free-rifle-shooting? {:priority 0}, - :school-use? {:priority 0}, - :track-length-m {:priority 1}}}, - 5310 - {:description - {:fi - "Useiden eri moottoriurheilun lajien suorituspaikkoja, huoltotilat olemassa.", - :se - "Platser för flera olika motorsportgrenar, serviceutrymmen finns.", - :en "Venues for various motor sports; service premises available."}, - :tags {:fi []}, - :name - {:fi "Moottoriurheilukeskus", - :se "Centrum för motorsport", - :en "Motor sports centre"}, - :type-code 5310, - :main-category 5000, - :status "active", - :sub-category 5300, - :geometry-type "Point", - :props - {:surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :automated-timing? {:priority 0}, - :stand-capacity-person {:priority 0}, - :free-use? {:priority 0}, - :finish-line-camera? {:priority 0}, - :track-width-m {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :area-m2 {:priority 0}, - :lighting-info {:priority 0}, - :year-round-use? {:priority 0}, - :scoreboard? {:priority 0}, - :loudspeakers? {:priority 0}, - :ligthing? {:priority 0}, - :covered-stand-person-count {:priority 0}, - :track-length-m {:priority 1}}}, - 1560 - {:description - {:fi - "Alamäkiluistelua varten vuosittain rakennettava rata. Käytössä talvikaudella.", - :se "Permanent bana byggd för utförsåkning.", - :en "Permanent track built for downhill skating. "}, - :tags {:fi ["luistelu" "alamäkiluistelu"]}, - :name - {:fi "Alamäkiluistelurata", - :se "Skridskobana för utförsåkning", - :en "Downhill skating track"}, - :type-code 1560, - :main-category 1000, - :status "active", - :sub-category 1500, - :geometry-type "Point", - :props - {:surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :lifts-count {:priority 0}, - :free-use? {:priority 0}, - :track-width-m {:priority 0}, - :altitude-difference {:priority 1}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :lighting-info {:priority 0}, - :ligthing? {:priority 1}, - :school-use? {:priority 0}, - :track-length-m {:priority 1}}}, - 205 - {:description - {:fi "Rantautumiseen osoitettu paikka, ei järjestettyjä palveluita.", - :se "Plats som anvisats för ilandstigning, inga ordnade tjänster.", - :en "Place intended for landing by boat, no services provided."}, - :tags {:fi ["laituri" "taukopaikka"]}, - :name - {:fi "Rantautumispaikka", - :se "Ilandstigningsplats", - :en "Boat dock"}, - :type-code 205, - :main-category 0, - :status "deprecated", - :sub-category 2, - :geometry-type "Point", - :props - {:toilet? {:priority 0}, - :boat-launching-spot? {:priority 0}, - :may-be-shown-in-excursion-map-fi? {:priority 0}, - :pier? {:priority 0}, - :school-use? {:priority 0}, - :free-use? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, - 2150 - {:description - {:fi - "Muun rakennuksen yhteydessä oleva avoin liikuntatila, joka sopii monipuolisesti erilaisten liikuntamuotojen harrastamiseen. Salin liikuntapinta-ala vaihtelee tyypillisesti alle 300 neliöstä noin 750 neliöön. Esim. koulurakennuksessa sijaitseva liikuntasali.", - :se - "En idrottssal som är ansluten till en annan byggnad. Storlek och höjd anges i karakteristika.", - :en - "A gymnastics hall connected to another building. Size and height specified in properties."}, - :tags {:fi ["jumppasali" "voimistelusali"]}, - :name {:fi "Liikuntasali", :se "Idrottssal", :en "Gymnastics hall"}, - :type-code 2150, - :main-category 2000, - :status "active", - :sub-category 2100, - :geometry-type "Point", - :props - {:height-m {:priority 1}, - :surface-material {:priority 1}, - :basketball-fields-count {:priority 0}, - :surface-material-info {:priority 0}, - :free-use? {:priority 0}, - :tennis-courts-count {:priority 0}, - :field-length-m {:priority 1}, - :match-clock? {:priority 0}, - :badminton-courts-count {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :space-divisible {:priority 0}, - :gymnastics-space? {:priority 0}, - :area-m2 {:priority 1}, - :field-width-m {:priority 1}, - :futsal-fields-count {:priority 0}, - :football-fields-count {:priority 0}, - :floorball-fields-count {:priority 0}, - :handball-fields-count {:priority 0}, - :volleyball-fields-count {:priority 0}, - :spinning-hall? {:priority 0}, - :school-use? {:priority 0}}}, - 2210 - {:description - {:fi - "Liikuntahalli on itsenäinen rakennus, jossa voi olla useita liikuntatiloja tai osiin jaettavissa oleva pääsali.", - :se - "Idrottshall med utrymmen för flera idrottsgrenar eller med ett i mindre sektioner indelbart huvudidrottsutrymme. Storleken varierar mellan ca 750 och 4999 m2. Inkluderar inomhusaktivitetsparker med faciliteter för flera fysiska aktiviteter.", - :en - "Building containing facilities for various sports or the main sports area can be split into smaller sections. Hall size varies between app. 750 - 4999 square meters. Includes indoor activity parks with facilities for multiple physical activities."}, - :tags {:fi ["urheilutalo" "urheiluhalli"]}, - :name {:fi "Liikuntahalli", :se "Idrottshall", :en "Sports hall "}, - :type-code 2210, - :main-category 2000, - :status "active", - :sub-category 2200, - :geometry-type "Point", - :props - {:height-m {:priority 1}, - :surface-material {:priority 1}, - :basketball-fields-count {:priority 0}, - :surface-material-info {:priority 0}, - :stand-capacity-person {:priority 0}, - :free-use? {:priority 0}, - :sprint-lanes-count {:priority 0}, - :javelin-throw-places-count {:priority 0}, - :tennis-courts-count {:priority 0}, - :field-length-m {:priority 1}, - :circular-lanes-count {:priority 0}, - :match-clock? {:priority 0}, - :inner-lane-length-m {:priority 0}, - :discus-throw-places {:priority 0}, - :badminton-courts-count {:priority 0}, - :hammer-throw-places-count {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :padel-courts-count {:priority 0}, - :polevault-places-count {:priority 0}, - :group-exercise-rooms-count {:priority 0}, - :space-divisible {:priority 0}, - :toilet? {:priority 0}, - :gymnastics-space? {:priority 0}, - :running-track-surface-material {:priority 0}, - :area-m2 {:priority 1}, - :field-width-m {:priority 1}, - :scoreboard? {:priority 0}, - :futsal-fields-count {:priority 0}, - :shotput-count {:priority 0}, - :longjump-places-count {:priority 0}, - :football-fields-count {:priority 0}, - :floorball-fields-count {:priority 0}, - :auxiliary-training-area? {:priority 0}, - :squash-courts-count {:priority 0}, - :customer-service-point? {:priority 0}, - :accessibility-info {:priority 0}, - :handball-fields-count {:priority 0}, - :volleyball-fields-count {:priority 0}, - :climbing-wall? {:priority 0}, - :school-use? {:priority 0}, - :highjump-places-count {:priority 0}}}, - 101 - {:description - {:fi - "Sijaitsevat taajamissa, max 1 km asutuksesta. Toimivat kävely-, leikki-, oleskelu-, lenkkeily- ja pyöräilypaikkoina. Kaavamerkintä V tai VL. Esimerkkejä lähi- tai ulkoilupuistoista: leikkipuistot, liikennepuistot, perhepuistot, oleskelupuistot, keskuspuistot ja kirkkopuistot.", - :se - "I tätorter, i omedelbar närhet till bebyggelse. Avsedd för daglig användning. Plats för lek, vistelse och promenader. Planbeteckning VL. Till exempel en lekpark.", - :en - "In population centres, in or near residential areas. Intended for daily use. Used for play, recreation and walks. Plan symbol VL. E.g. a playground."}, - :tags {:fi ["puisto" "lähiliikuntapaikka"]}, - :name - {:fi "Lähi-/ulkoilupuisto", :se "Närpark", :en "Neighbourhood park"}, - :type-code 101, - :main-category 0, - :status "active", - :sub-category 1, - :geometry-type "Polygon", - :props - {:playground? {:priority 0}, - :area-km2 {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :water-point {:priority 0}, - :toilet? {:priority 0}}}, - 102 - {:description - {:fi - "Päivittäin käytettäviä alueita, max 1 km asunnoista. Toimivat kävely-, leikki-, oleskelu-, lenkkeily- ja pyöräilypaikkoina. Kevyt liikenne voi mennä ulkoilupuiston läpi. Voi sisältää puistoa, metsää, peltoa, niittyä, vesialuetta. Kaavamerkintä V tai VL.", - :se - "Områden avsedda för daglig använding, max på 1 kilometers avstånd från bebyggelse. Fungerar som ett område för promenader, lekar, vistelse, joggning och cykling. Lätt trafikled kan fara igenom friluftsparken. Området kan bestå av park, skog, åker, äng och vattenled. Planbeteckning V eller VL.", - :en - "Used daily, max. 1 km from residential areas. Intended for walks, play, recreation, jogging and cycling. There may be bicycle and pedestrian traffic across the park. May consist of park, forest, fields, meadows, bodies of water. Symbol V or VL."}, - :tags {:fi ["puisto"]}, - :name {:fi "Ulkoilupuisto", :se "Friluftspark", :en "Leisure park"}, - :type-code 102, - :main-category 0, - :status "deprecated", - :sub-category 1, - :geometry-type "Polygon", - :props - {:playground? {:priority 0}, - :area-km2 {:priority 0}, - :may-be-shown-in-excursion-map-fi? {:priority 0}, - :school-use? {:priority 0}, - :free-use? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, - 7000 - {:description - {:fi - "Liikuntapaikan tai -paikkojen yhteydessä oleva, liikuntapaikan ylläpitoa tai käyttöä palveleva rakennus. Voi sisältää varastoja, pukuhuoneita, suihkutiloja yms.", - :se "Servicebyggnader i anslutning till idrottsanläggningar.", - :en "Maintenance buildings in connection with sports facilities."}, - :tags {:fi ["konesuoja" "huoltotila"]}, - :name - {:fi "Huoltorakennukset", - :se "Servicebyggnader", - :en "Maintenance/service buildings"}, - :type-code 7000, - :main-category 7000, - :status "active", - :sub-category 7000, - :geometry-type "Point", - :props - {:free-use? {:priority 0}, - :ski-service? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :shower? {:priority 0}, - :changing-rooms? {:priority 0}, - :area-m2 {:priority 0}, - :equipment-rental? {:priority 0}, - :sauna? {:priority 0}, - :school-use? {:priority 0}}}, - 1110 - {:description - {:fi - "Liikuntapuisto on useita liikuntapaikkoja käsittävä liikunta-alue. Liikuntapuistossa voi olla esim. erilaisia kenttiä, uimaranta, kuntorata, monitoimihalli, leikkipuisto jne. koottuna samalle alueelle. Lipakseen tallennetaan sekä tieto liikuntapuistosta että yksittäiset liikuntapaikat, joita puisto sisältää. Liikuntapaikat lasketaan omiksi paikoikseen.", - :se - "En idrottspark är ett idrottsområde med flera idrottsplatser. Där kan finnas olika planer, badstrand, konditionsbana, allaktivitetshall, lekpark osv samlade på samma område. I Lipas lagras uppgifter om såväl idrottsparken som enstaka faciliteter som finns i parken. Varje motionsplats räknas som en plats.", - :en - "A sports park is an area including several sports facilities, e.g., different fields, beach, a jogging track, a multi-purpose hall, a playground. 'Lipas' contains information both on the sports park and the individual sports facilities found there. The sports facilities are listed as individual items in the classification."}, - :tags {:fi ["puisto" "lähiliikunta" "lähiliikuntapaikka"]}, - :name {:fi "Liikuntapuisto", :se "Idrottspark", :en "Sports park"}, - :type-code 1110, - :main-category 1000, - :status "active", - :sub-category 1100, - :geometry-type "Polygon", - :props - {:free-use? {:priority 0}, - :fields-count {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :area-m2 {:priority 1}, - :lighting-info {:priority 0}, - :ligthing? {:priority 1}, - :accessibility-info {:priority 0}, - :playground? {:priority 0}, - :school-use? {:priority 0}}}, - 3250 - {:description - {:fi - "Vesiurheilukeskuksessa on vesistössä sijaitsevia liikuntapalveluita tai palvelukokonaisuus, joka voi muodostua erilaisista veden päällä tai vedessä olevista suorituspaikoista tai -radoista."}, - :tags {:fi []}, - :name {:fi "Vesiurheilukeskus"}, - :type-code 3250, - :main-category 3000, - :status "active", - :sub-category 3200, - :geometry-type "Point", - :props - {:free-use? {:priority 0}, - :pier? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :shower? {:priority 0}, - :changing-rooms? {:priority 0}, - :pool-water-area-m2 {:priority 0}, - :sauna? {:priority 0}, - :customer-service-point? {:priority 0}}}, - 6220 - {:description - {:fi - "Erityisesti koiraharrastusta, agilityä, koulutusta tms. varten varustettu halli.", - :se - "Hall som utrustats särskilt för hundhobby, agility, träning osv.", - :en - "Hall specifically equipped for dog sports, agility, training, etc."}, - :tags {:fi ["agility" "koirahalli"]}, - :name - {:fi "Koiraurheiluhalli", - :se "Hundsporthall", - :en "Dog sports hall"}, - :type-code 6220, - :main-category 6000, - :status "active", - :sub-category 6200, - :geometry-type "Point", - :props - {:heating? {:priority 0}, - :surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :free-use? {:priority 0}, - :field-length-m {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :area-m2 {:priority 1}, - :field-width-m {:priority 0}, - :lighting-info {:priority 0}, - :ligthing? {:priority 0}}}, - 4530 - {:description - {:fi - "Pyöräillen tapahtuvaan suunnistamiseen, alueesta on pyöräsuunnistukseen soveltuva kartta.", - :se "Karta över område som lämpar sig för cykelorientering.", - :en "A map for mountain bike orienteering available."}, - :tags {:fi []}, - :name - {:fi "Pyöräsuunnistusalue", - :se "Cykelorienteringsområde", - :en " Mountain bike orienteering area"}, - :type-code 4530, - :main-category 4000, - :status "deprecated", - :sub-category 4500, - :geometry-type "Polygon", - :props - {:area-km2 {:priority 0}, - :school-use? {:priority 0}, - :free-use? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, - 4720 - {:description - {:fi - "Merkitty luonnon kallio, jota voi käyttää kiipeilyyn. Jääkiipeily lisätietoihin. Myös boulderointikalliot.", - :se - "Märkt berg i naturen. Isklättring i tilläggsinformation. Även berg för bouldering.", - :en - "Marked natural cliff. Ice climbing specified in additional information. Also includes bouldering cliffs."}, - :tags {:fi []}, - :name {:fi "Kiipeilykallio", :se "Klätterberg", :en "Climbing rock"}, - :type-code 4720, - :main-category 4000, - :status "active", - :sub-category 4700, - :geometry-type "Point", - :props - {:surface-material {:priority 0}, - :surface-material-info {:priority 0}, - :free-use? {:priority 0}, - :may-be-shown-in-excursion-map-fi? {:priority 0}, - :climbing-routes-count {:priority 0}, - :ice-climbing? {:priority 0}, - :climbing-wall-height-m {:priority 1}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :area-m2 {:priority 1}, - :lighting-info {:priority 0}, - :climbing-wall-width-m {:priority 1}, - :ligthing? {:priority 0}}}, - 1330 - {:description - {:fi - "Rantalentopallokenttä, pehmeä alusta. Kohde voi sijaita muuallakin kuin rannalla.", - :se - "Beachvolleybollplan, mjuk grund. Kan också ha annat läge än stranden.", - :en - "Beach volleyball court, soft basement. May also be located far from a beach."}, - :tags {:fi ["rantalentopallo" "rantalentopallokenttä"]}, - :name - {:fi "Beachvolley-/rantalentopallokenttä", - :se "Beachvolleyplan", - :en "Beach volleyball court"}, - :type-code 1330, - :main-category 1000, - :status "active", - :sub-category 1300, - :geometry-type "Point", - :props - {:surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :height-of-basket-or-net-adjustable? {:priority 0}, - :free-use? {:priority 0}, - :field-length-m {:priority 1}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :area-m2 {:priority 1}, - :field-width-m {:priority 1}, - :lighting-info {:priority 0}, - :water-point {:priority 0}, - :ligthing? {:priority 1}, - :school-use? {:priority 0}}}, - 206 - {:description - {:fi - "Rakennettu tulentekopaikka tai keittokatos. Kohde voi olla esimerkiksi maasta eristetty katoksellinen tulisija tai tulisija avotulelle. Tulentekopaikan tarkempi kuvaus ja tieto mahdollisista rajoituksista lisätietoihin.", - :se "En byggd eldningsplats eller ett kokskjul. Objektet kan till exempel vara en eldstad med tak som är isolerad från marken eller en eldstad för öppen eld. En mer detaljerad beskrivning av eldningsplatsen och information om eventuella begränsningar finns i ytterligare information.", - :en "A constructed fireplace or cooking shelter. The site can be, for example, a covered fireplace isolated from the ground or a fireplace for open fires. A more detailed description of the fireplace and information about any possible restrictions can be found in the additional information."}, - :tags - {:fi - ["nuotiopaikka" - "keittokatos" - "grillauspaikka" - "ruoka" - "taukopaikka"]}, - :name - {:fi "Ruoanlaitto- / tulentekopaikka", - :se "Matlagningsplats", - :en "Cooking facilities"}, - :type-code 206, - :main-category 0, - :status "active", - :sub-category 2, - :geometry-type "Point", - :props - {:may-be-shown-in-excursion-map-fi? {:priority 0}, - :toilet? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :free-use? {:priority 0}}}, - 4830 - {:description - {:fi - "Ulkona tai sisällä sijaitseva jousiammuntarata. Radan käyttö edellyttää erillistä lupaa, seuran jäsenyyttä tai harjoitusvuoroa. Radan varustus ja soveltuvat lajit kuvataan lisätiedoissa.", - :se "Ute eller inne. Utrustning och grenar i karakteristika.", - :en - "Outdoors or indoors. Equipment and the various sports detailed in properties."}, - :tags {:fi ["jousiampumarata"]}, - :name - {:fi "Jousiammuntarata", :se "Bågskyttebana", :en "Archery range"}, - :type-code 4830, - :main-category 4000, - :status "active", - :sub-category 4800, - :geometry-type "Point", - :props - {:free-use? {:priority 0}, - :track-width-m {:priority 0}, - :free-customer-use? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :shooting-positions-count {:priority 1}, - :area-m2 {:priority 0}, - :lighting-info {:priority 0}, - :ligthing? {:priority 1}, - :track-length-m {:priority 1}}}, - 1180 - {:description - {:fi "Frisbeegolfin pelaamiseen rakennettu rata.", - :se "En bana byggt för frisbeegolf.", - :en "Track built for disc golf. "}, - :tags {:fi []}, - :name - {:fi "Frisbeegolfrata", - :se "Frisbeegolfbana", - :en "Disc golf course"}, - :type-code 1180, - :main-category 1000, - :status "active", - :sub-category 1100, - :geometry-type "Point", - :props - {:surface-material {:priority 0}, - :surface-material-info {:priority 0}, - :holes-count {:priority 1}, - :free-use? {:priority 0}, - :may-be-shown-in-excursion-map-fi? {:priority 0}, - :altitude-difference {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :lighting-info {:priority 0}, - :ligthing? {:priority 0}, - :accessibility-info {:priority 0}, - :school-use? {:priority 0}, - :track-type {:priority 0}, - :range? {:priority 0}, - :track-length-m {:priority 0}}}, - 4422 - {:description - {:fi - "Moottorikelkkailuun tarkoitettu reitti, jolla ei ole tehty virallista reittitoimitusta. Reitillä on kuitenkin ylläpitäjä ja maanomistajien lupa.", - :se "Ingen ruttexpedition.", - :en "No official approval."}, - :tags {:fi []}, - :name - {:fi "Moottorikelkkaura", - :se "Snöskoterspår", - :en "Unofficial snowmobile route"}, - :type-code 4422, - :main-category 4000, - :status "active", - :sub-category 4400, - :geometry-type "LineString", - :props - {:may-be-shown-in-excursion-map-fi? {:priority 0}, - :route-width-m {:priority 0}, - :route-length-km {:priority 1}, - :rest-places-count {:priority 0}, - :free-use? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, - 4430 - {:description - {:fi - "Ratsastukseen ja/tai kärryillä ajoon tarkoitettu reitti. Sallitut käyttötavat kerrotaan reitin tarkemmissa tiedoissa.", - :se - "Led avsedd för ridning och/eller häst med kärra. Användningsanvisningar i karakteristika.", - :en - "Route intended for horseback riding and/or carriage riding. Different uses specified in additional information."}, - :tags {:fi ["ratsastusreitti"]}, - :name {:fi "Hevosreitti", :se "Hästled", :en "Horse track"}, - :type-code 4430, - :main-category 4000, - :status "active", - :sub-category 4400, - :geometry-type "LineString", - :props - {:surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :free-use? {:priority 0}, - :route-width-m {:priority 1}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :rest-places-count {:priority 0}, - :lit-route-length-km {:priority 1}, - :school-use? {:priority 0}, - :route-length-km {:priority 1}}}, - 204 - {:description - {:fi - "Luonnon tarkkailuun tarkoitettu rakennelma, lintutorni tai vastaava.", - :se - "Anordning avsedd för observationer i naturen, t ex fågeltorn.", - :en - "Structure built for nature observation. E.g. bird observation tower."}, - :tags {:fi ["lintutorni" "näkötorni" "torni"]}, - :name - {:fi "Luontotorni", :se "Naturtorn", :en "Nature observation tower"}, - :type-code 204, - :main-category 0, - :status "active", - :sub-category 2, - :geometry-type "Point", - :props - {:toilet? {:priority 0}, - :may-be-shown-in-excursion-map-fi? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :free-use? {:priority 0}}}, - 106 - {:description - {:fi - "Monikäyttöalueiksi voidaan nimittää jokaisenoikeuksin ulkoiluun käytettäviä maa- ja metsätalousalueita. Monikäyttöalueita ovat erityisesti rakentamattomat rannat ja taajamien läheiset maa- ja metsätalousalueet. Kaavamerkintä MU. Virkistysmetsien metsätaloudessa on huomioitu mm. maisemalliset arvot, ja ne on perustettu Metsähallituksen päätöksellä. Virkistysmetsien osalta Lipas-aineisto perustuu Metsähallituksen tietoihin.", - :se - "Områden för mångsidig användning kan kallas jord- och skogsbruksområden som används för rekreation med allemansrätten. Områden för mångsidig användning är särskilt obebyggda stränder och jord- och skogsbruksområden nära tätorter. Planbeteckning MU. Inom skogsbruket i rekreationsskogar har man beaktat bl.a. landskapsvärden, och de har inrättats genom beslut av Forststyrelsen. När det gäller rekreationsskogar baseras Lipas-materialet på uppgifter från Forststyrelsen.", - :en - "Multi-use areas can be designated as agricultural and forestry areas used for outdoor activities under everyman's rights. Multi-use areas are particularly undeveloped shores and agricultural and forestry areas near urban areas. Plan designation MU. In the forestry of recreational forests, landscape values, among other things, have been considered, and they have been established by a decision of Metsähallitus. For recreational forests, the Lipas data is based on information from Metsähallitus."}, - :tags {:fi ["ulkoilualue" "virkistysalue"]}, - :name - {:fi "Monikäyttöalue tai virkistysmetsä, jossa on virkistyspalveluita", - :se "Mångbruksområde eller rekreationsskog med rekreationstjänster", - :en "Multi-use area or recreational forest with recreational services"}, - :type-code 106, - :main-category 0, - :status "active", - :sub-category 1, - :geometry-type "Polygon", - :props - {:area-km2 {:priority 0}, - :may-be-shown-in-excursion-map-fi? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, - 2620 - {:description - {:fi - "Biljardisali on biljardin pelaamiseen tarkoitettu tila. Biljardipöytien määrä ja tyyppi kuvataan lisätiedoissa."}, - :tags {:fi []}, - :name {:fi "Biljardisali"}, - :type-code 2620, - :main-category 2000, - :status "active", - :sub-category 2600, - :geometry-type "Point", - :props - {:total-billiard-tables-count {:priority 0}, - :carom-tables-count {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :snooker-tables-count {:priority 0}, - :pool-tables-count {:priority 0}, - :customer-service-point? {:priority 0}, - :pyramid-tables-count {:priority 0}, - :kaisa-tables-count {:priority 0}, - :school-use? {:priority 0}}}, - 4610 - {:description - {:fi - "Ampumahiihdon harjoitteluun tarkoitettu alue, jossa on ainakin latu ja ampumapaikka/-paikkoja. ", - :se - "Annat träningsområde för skidskytte. Spår och skjutplats finns.", - :en - "Other training area for biathlon. Ski track and shooting range."}, - :tags {:fi ["ampumapaikka"]}, - :name - {:fi "Ampumahiihdon harjoittelualue", - :se "Träningsområde för skidskytte", - :en "Training area for biathlon"}, - :type-code 4610, - :main-category 4000, - :status "active", - :sub-category 4600, - :geometry-type "Point", - :props - {:stand-capacity-person {:priority 0}, - :free-use? {:priority 0}, - :ski-service? {:priority 0}, - :finish-line-camera? {:priority 0}, - :ski-track-traditional? {:priority 0}, - :route-width-m {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :rest-places-count {:priority 0}, - :changing-rooms? {:priority 0}, - :shooting-positions-count {:priority 1}, - :lit-route-length-km {:priority 0}, - :year-round-use? {:priority 0}, - :scoreboard? {:priority 0}, - :changing-rooms-m2 {:priority 0}, - :loudspeakers? {:priority 0}, - :ski-track-freestyle? {:priority 0}, - :route-length-km {:priority 0}}}, - 2610 - {:description - {:fi - "Keilailuun varustettu halli. Ratojen määrä ja palveluvarustus kirjataan lisätietoihin.", - :se "Antalet banor och serviceutrustning i karakteristika.", - :en "Number of alleys and service facilities in properties."}, - :tags {:fi []}, - :name {:fi "Keilahalli", :se "Bowlinghall", :en "Bowling alley"}, - :type-code 2610, - :main-category 2000, - :status "active", - :sub-category 2600, - :geometry-type "Point", - :props - {:free-use? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :bowling-lanes-count {:priority 1}, - :toilet? {:priority 0}, - :area-m2 {:priority 0}, - :cosmic-bowling? {:priority 0}, - :scoreboard? {:priority 0}, - :loudspeakers? {:priority 0}, - :school-use? {:priority 0}}}, - 2110 - {:description - {:fi - "Erilasia liikuntapalveluita ja -tiloja tarjoava kuntokeskus. Kohteessa voi olla esimerkiksi kuntosali- ja ryhmäliikuntatiloja.", - :se - "Olika motionstjänster och -utrymmen, t ex gym och gruppidrottsutrymmen.", - :en - "Different sports services and premises, e.g., gym, group exercise premises. "}, - :tags {:fi ["kuntosali" "kuntoilu"]}, - :name - {:fi "Kuntokeskus", - :se "Konditionsidrottscentrum", - :en "Fitness centre"}, - :type-code 2110, - :main-category 2000, - :status "active", - :sub-category 2100, - :geometry-type "Point", - :props - {:surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :free-customer-use? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :group-exercise-rooms-count {:priority 0}, - :area-m2 {:priority 1}, - :weight-lifting-spots-count {:priority 0}, - :customer-service-point? {:priority 0}, - :spinning-hall? {:priority 0}, - :school-use? {:priority 0}, - :exercise-machines-count {:priority 0}}}, - 3120 - {:description - {:fi - "Yksittäinen tai useampi pieni uima-allas muun kuin uimahallin tai kylpylän yhteydessä. Uima-allastilat voivat olla pääasiassa esim. kuntoutus- tai terapiakäytössä. Altaiden määrä ja vesipinta-ala kerrotaan ominaisuustiedoissa.", - :se "Enstaka simbassäng , ofta i anslutning till en annan byggnad.", - :en - "Individual swimming pool, often in connection with other buildings."}, - :tags {:fi []}, - :name {:fi "Uima-allastila", :se "Simbassäng", :en "Swimming pool"}, - :type-code 3120, - :main-category 3000, - :status "active", - :sub-category 3100, - :geometry-type "Point", - :props - {:pool-tracks-count {:priority 0}, - :free-use? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :pool-width-m {:priority 0}, - :pool-min-depth-m {:priority 0}, - :swimming-pool-count {:priority 0}, - :pool-water-area-m2 {:priority 1}, - :pool-length-m {:priority 1}, - :pool-max-depth-m {:priority 0}, - :accessibility-info {:priority 0}, - :pool-temperature-c {:priority 0}, - :school-use? {:priority 0}}}, - 104 - {:description - {:fi - "Sijaitsevat kauempana taajamasta, automatkan päässä. Monipuolinen polku- ja reittiverkosto. Käyttö painottuu viikonloppuihin ja loma-aikoihin. Palvelevat usein useaa kuntaa. Kaavamerkintä VR.", - :se - "Ett område på bil avstånd från tätorten, Området har en stor variation av stig- och ruttnätverk. Användningen av området fokuserar sig mest till helgerna och semester tiderna. Området betjänar oftast mer än en kommun. Planbeteckning VR.", - :en - "Located further away from population centres, accessible by car. Complex network of paths and routes. Use concentrated during weekends and holidays. Often serves several municipalities. Symbol VR."}, - :tags {:fi ["virkistysalue"]}, - :name {:fi "Retkeilyalue", :se "Utflyktsområde", :en "Hiking area"}, - :type-code 104, - :main-category 0, - :status "deprecated", - :sub-category 1, - :geometry-type "Polygon", - :props - {:may-be-shown-in-excursion-map-fi? {:priority 0}, - :area-km2 {:priority 0}, - :school-use? {:priority 0}, - :free-use? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, - 2330 - {:description - {:fi "Pysyvästi pöytätennikseen varustettu tila.", - :se "Permanent utrustning för att träna bordtennis.", - :en "Space permanently equipped for table tennis."}, - :tags {:fi ["pingis" "pingispöytä"]}, - :name - {:fi "Pöytätennistila", - :se "Utrymme för bordtennis", - :en "Table tennis venue"}, - :type-code 2330, - :main-category 2000, - :status "active", - :sub-category 2300, - :geometry-type "Point", - :props - {:height-m {:priority 0}, - :surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :free-use? {:priority 0}, - :active-space-width-m {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :area-m2 {:priority 1}, - :active-space-length-m {:priority 0}, - :table-tennis-count {:priority 1}, - :school-use? {:priority 0}}}, - 2280 - {:description - {:fi - "Tenniksen pelaamiseen varusteltu halli. Kenttien lukumäärä ja pintamateriaali kerrotaan kohteen lisätiedoissa.", - :se "Antalet banor i karakteristika.", - :en "Number of courts specified in properties."}, - :tags {:fi []}, - :name {:fi "Tennishalli", :se "Tennishall", :en "Tennis hall"}, - :type-code 2280, - :main-category 2000, - :status "active", - :sub-category 2200, - :geometry-type "Point", - :props - {:height-m {:priority 1}, - :surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :stand-capacity-person {:priority 0}, - :free-use? {:priority 0}, - :tennis-courts-count {:priority 1}, - :field-length-m {:priority 0}, - :badminton-courts-count {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :padel-courts-count {:priority 0}, - :toilet? {:priority 0}, - :area-m2 {:priority 1}, - :field-width-m {:priority 0}, - :scoreboard? {:priority 0}, - :floorball-fields-count {:priority 0}, - :squash-courts-count {:priority 0}, - :customer-service-point? {:priority 0}, - :volleyball-fields-count {:priority 0}, - :school-use? {:priority 0}}}, - 6140 - {:description - {:fi "Raviurheilun harjoitus- tai kilparata.", - :se "Övnings- eller tävlingsbana för travsport.", - :en "Training or competition track for horse racing."}, - :tags {:fi []}, - :name {:fi "Ravirata", :se "Travbana", :en "Horse racing track"}, - :type-code 6140, - :main-category 6000, - :status "active", - :sub-category 6100, - :geometry-type "Point", - :props - {:surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :automated-timing? {:priority 0}, - :stand-capacity-person {:priority 0}, - :free-use? {:priority 0}, - :finish-line-camera? {:priority 0}, - :track-width-m {:priority 1}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :lighting-info {:priority 0}, - :scoreboard? {:priority 0}, - :loudspeakers? {:priority 0}, - :ligthing? {:priority 1}, - :covered-stand-person-count {:priority 0}, - :track-length-m {:priority 1}}}, - 2140 - {:description - {:fi - "Sali, jossa voi harrastaa kamppailulajeja kuten painia, nyrkkeilyä tai budolajeja. Tilan koko ja varustus kerrotaan kohteen lisätiedoissa.", - :se - "Sal där man kan utöva självförsvarsgrenar, t ex brottning, boxning. Storleken anges i karakteristika.", - :en - "Hall for self-defence sports, e.g., wrestling, boxing. Size specified in properties. "}, - :tags {:fi ["paini" "judo" "tatami"]}, - :name - {:fi "Kamppailulajien sali", - :se "Sal för kampsport", - :en "Martial arts hall"}, - :type-code 2140, - :main-category 2000, - :status "active", - :sub-category 2100, - :geometry-type "Point", - :props - {:surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :group-exercise-rooms-count {:priority 0}, - :space-divisible {:priority 0}, - :tatamis-count {:priority 0}, - :area-m2 {:priority 1}, - :wrestling-mats-count {:priority 0}, - :boxing-rings-count {:priority 0}, - :weight-lifting-spots-count {:priority 0}, - :customer-service-point? {:priority 0}, - :school-use? {:priority 0}, - :exercise-machines-count {:priority 0}}}, - 4220 - {:description - {:fi - "Hiihtoon tarkoitettu katettu tila (esim. tunneli, putki, halli).", - :se - "Utrymme avsett för skidåkning under tak (tunnel, rör, hall el dyl).", - :en - "Covered space (tunnel, tube, hall, etc.) intended for skiing."}, - :tags {:fi []}, - :name {:fi "Hiihtotunneli", :se "Skidtunnel", :en "Ski tunnel"}, - :type-code 4220, - :main-category 4000, - :status "active", - :sub-category 4200, - :geometry-type "Point", - :props - {:surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :free-use? {:priority 0}, - :ski-service? {:priority 0}, - :altitude-difference {:priority 1}, - :route-width-m {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :area-m2 {:priority 0}, - :equipment-rental? {:priority 0}, - :accessibility-info {:priority 0}, - :route-length-km {:priority 1}}}, - 2230 - {:description - {:fi - "Ensisijaisesti jalkapalloiluun tarkoitettu halli. Halli voi olla ympärivuotisessa käytössä tai erikseen talviajalle pystytettävä kevythalli. Kentän pintamateriaalina on yleensä tekonurmi.", - :se - "Hall avsedd för fotboll. Ytmaterial, antalet planer och storlek i karakteristika.", - :en - "Hall intended for football. Surface material, number and size of courts specified in properties."}, - :tags {:fi []}, - :name - {:fi "Jalkapallohalli", :se "Fotbollshall", :en "Football hall"}, - :type-code 2230, - :main-category 2000, - :status "active", - :sub-category 2200, - :geometry-type "Point", - :props - {:height-m {:priority 1}, - :heating? {:priority 0}, - :surface-material {:priority 1}, - :basketball-fields-count {:priority 0}, - :surface-material-info {:priority 0}, - :stand-capacity-person {:priority 0}, - :free-use? {:priority 0}, - :tennis-courts-count {:priority 0}, - :field-length-m {:priority 1}, - :match-clock? {:priority 0}, - :sprint-track-length-m {:priority 0}, - :badminton-courts-count {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :area-m2 {:priority 1}, - :field-width-m {:priority 1}, - :scoreboard? {:priority 0}, - :football-fields-count {:priority 0}, - :auxiliary-training-area? {:priority 0}, - :loudspeakers? {:priority 0}, - :customer-service-point? {:priority 0}, - :volleyball-fields-count {:priority 0}, - :school-use? {:priority 0}}}, - 1350 - {:description - {:fi - "Suuri jalkapallokenttä, katsomoita. Vähintään kansallisen tason pelipaikka.", - :se - "Stor fotbollsplan, flera läktare. Minimikrav: spelplats på nationell nivå.", - :en - "Large football field, stands. Can host at least national-level games."}, - :tags {:fi ["jalkapallokenttä"]}, - :name - {:fi "Jalkapallostadion", - :se "Fotbollsstadion", - :en "Football stadium"}, - :type-code 1350, - :main-category 1000, - :status "active", - :sub-category 1300, - :geometry-type "Point", - :props - {:heating? {:priority 0}, - :surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :stand-capacity-person {:priority 0}, - :free-use? {:priority 0}, - :field-length-m {:priority 1}, - :match-clock? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :area-m2 {:priority 1}, - :field-width-m {:priority 1}, - :lighting-info {:priority 0}, - :year-round-use? {:priority 0}, - :scoreboard? {:priority 0}, - :loudspeakers? {:priority 0}, - :customer-service-point? {:priority 0}, - :water-point {:priority 0}, - :ligthing? {:priority 1}, - :covered-stand-person-count {:priority 0}, - :school-use? {:priority 0}, - :light-roof? {:priority 0}}}, - 4840 - {:description - {:fi - "Maastoon rakennettu jousiammuntarata. Radan käyttö edellyttää erillistä lupaa, seuran jäsenyyttä tai harjoitusvuoroa. ", - :se "Bågskyttebana byggd i terrängen.", - :en "Archery course built in rough terrain."}, - :tags {:fi ["jousiampumarata"]}, - :name - {:fi "Jousiammuntamaastorata", - :se "Terrängbana för bågskytte", - :en "Field archery course"}, - :type-code 4840, - :main-category 4000, - :status "active", - :sub-category 4800, - :geometry-type "Point", - :props - {:free-use? {:priority 0}, - :free-customer-use? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :shooting-positions-count {:priority 1}, - :lighting-info {:priority 0}, - :ligthing? {:priority 1}, - :track-length-m {:priority 1}}}, - 113 - {:description - {:fi - "Vapaa-ajankalastukseen sopiva alue. Kohteessa voi olla palvelurakenteita.", - :se - "Område eller en plats i ett naturligt vattendrag som ställts i ordning för fritidsfiske.", - :en - "Natural aquatic destination equipped and maintained for recreational fishing."}, - :tags {:fi ["kalastusalue" "kalastuspaikka"]}, - :name - {:fi "Kalastuskohde (alue)", - :se "Område eller plats för fiske", - :en "Fishing area/spot "}, - :type-code 113, - :main-category 0, - :status "active", - :sub-category 1, - :geometry-type "Polygon", - :props - {:free-use? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :pier? {:priority 0}, - :customer-service-point? {:priority 0}, - :equipment-rental? {:priority 0}}}, - 1510 - {:description - {:fi - "Koneellisesti tai keinotekoisesti jäähdytetty ulkokenttä. Kentän koko ja varustustiedot löytyvät lisätiedoista. Käytössä talvikaudella.", - :se - "En utomhusbana som är mekaniskt eller artificiellt kyld. Information om banans storlek och utrustning finns i ytterligare information. Används under vintersäsongen.", - :en - "An outdoor rink that is mechanically or artificially cooled. Details about the size and equipment of the rink can be found in the additional information. Used during the winter season."}, - :tags {:fi ["luistelukenttä" "luistelu"]}, - :name - {:fi "Tekojääkenttä/tekojäärata", - :se "Konstis", - :en "Mechanically frozen open-air ice rink"}, - :type-code 1510, - :main-category 1000, - :status "active", - :sub-category 1500, - :geometry-type "Point", - :props - {:surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :stand-capacity-person {:priority 0}, - :free-use? {:priority 0}, - :field-length-m {:priority 1}, - :match-clock? {:priority 0}, - :fields-count {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :ice-rinks-count {:priority 0}, - :toilet? {:priority 0}, - :changing-rooms? {:priority 0}, - :area-m2 {:priority 1}, - :field-width-m {:priority 1}, - :lighting-info {:priority 0}, - :changing-rooms-m2 {:priority 0}, - :customer-service-point? {:priority 0}, - :ligthing? {:priority 1}, - :school-use? {:priority 0}, - :light-roof? {:priority 0}}}, - 5350 - {:description - {:fi - "Pääasiallisesti kiihdytysautoiluun tai kiihdytysmoottoripyöräilyyn käytetty rata.", - :se "Huvudsakligen för accelerationskörning.", - :en "Mainly for drag racing."}, - :tags {:fi []}, - :name - {:fi "Kiihdytysrata", :se "Accelerationsbana", :en "Dragstrip"}, - :type-code 5350, - :main-category 5000, - :status "active", - :sub-category 5300, - :geometry-type "Point", - :props - {:surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :automated-timing? {:priority 0}, - :stand-capacity-person {:priority 0}, - :free-use? {:priority 0}, - :track-width-m {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :area-m2 {:priority 0}, - :lighting-info {:priority 0}, - :year-round-use? {:priority 0}, - :scoreboard? {:priority 0}, - :loudspeakers? {:priority 0}, - :ligthing? {:priority 0}, - :covered-stand-person-count {:priority 0}, - :track-length-m {:priority 1}}}, - 2225 - {:description - {:fi - "Sisäleikkipuistot ovat yleensä pienille lapsille tarkoitettuja liikunnallisia leikkipaikkoja. Sisäaktiviteettipuistot ovat tyypillisesti lapsille ja nuorille tarkoitettuja liikuntakeskuksia, jotka sisältävät erilaisia liikunnallisia kohteita."}, - :tags {:fi []}, - :name {:fi "Sisäleikki-/sisäaktiviteettipuisto"}, - :type-code 2225, - :main-category 2000, - :status "active", - :sub-category 2200, - :geometry-type "Point", - :props - {:customer-service-point? {:priority 0}, - :height-m {:priority 0}, - :area-m2 {:priority 0}}}, - 4440 - {:description - {:fi - "Hiihtolatu, jossa on aina tai tiettyinä aikoina koirahiihto sallittua. Perinteinen tyyli tai vapaa tyyli.", - :se - "Ett skidspår där det alltid eller vissa tider är tillåtet att åka med hundspann. Klassisk stil eller fristil.", - :en - "Ski track on which dog skijoring is allowed either always or at given times. Traditional or free style."}, - :tags {:fi ["koiralatu"]}, - :name - {:fi "Koirahiihtolatu", - :se "Spår för hundspann", - :en "Dog skijoring track"}, - :type-code 4440, - :main-category 4000, - :status "active", - :sub-category 4400, - :geometry-type "LineString", - :props - {:surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :free-use? {:priority 0}, - :ski-track-traditional? {:priority 0}, - :route-width-m {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :rest-places-count {:priority 0}, - :lit-route-length-km {:priority 1}, - :ski-track-freestyle? {:priority 0}, - :school-use? {:priority 0}, - :route-length-km {:priority 1}}}, - 2520 - {:description - {:fi - "Kilpajäähalli on jääurheilun kilpailu- ja ottelutapahtumiin soveltuva jäähalli. Katsomon koko, kenttien lukumäärä ja muut tarkemmat tiedot kuvataan lisätiedoissa.", - :se - "Läktare finns, storleken på läktaren anges i karakteristika, likaså antalet planer.", - :en - "Includes bleachers, whose size is specified in properties. Number of fields, heating, changing rooms, etc., specified in properties."}, - :tags {:fi ["jäähalli"]}, - :additional-type - {:small {:fi "Pieni kilpahalli > 500 hlö", :en "Small competition hall > 500 people", :se "Liten tävlingshall > 500 personer"}, - :competition {:fi "Kilpahalli < 3000 hlö", :en "Competition hall < 3000 people", :se "Tävlingshall < 3000 personer"}, - :large {:fi "Suurhalli > 3000 hlö", :en "Large hall > 3000 people", :se "Större hall > 3000 personer"}} -, - :name - {:fi "Kilpajäähalli", - :se "Tävlingsishall", - :en "Competition ice arena"}, - :type-code 2520, - :keywords {:fi ["Jäähalli"], :en [], :se []}, - :main-category 2000, - :status "active", - :sub-category 2500, - :geometry-type "Point", - :props - {:surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :automated-timing? {:priority 0}, - :stand-capacity-person {:priority 0}, - :free-use? {:priority 0}, - :finish-line-camera? {:priority 0}, - :match-clock? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :ice-rinks-count {:priority 1}, - :field-2-flexible-rink? {:priority 0}, - :toilet? {:priority 0}, - :area-m2 {:priority 1}, - :curling-lanes-count {:priority 0}, - :scoreboard? {:priority 0}, - :auxiliary-training-area? {:priority 0}, - :ringette-boundary-markings? {:priority 0}, - :field-1-flexible-rink? {:priority 0}, - :loudspeakers? {:priority 0}, - :school-use? {:priority 0}, - :field-3-flexible-rink? {:priority 0}}}, - 4710 - {:description - {:fi - "Rakennettu kiipeilyseinä ulkona, köysikiipeilyrata tai vastaava kiipeilyä varten rakennettu paikka. Myös rakennetut boulderointipaikat. Paikan tarkempi kuvaus ominaisuustietoihin.", - :se - "Byggd klättervägg utomhus, klätterbana eller annan plats byggd för klättring. Även platser för bouldering. Precisering i karakteristika.", - :en - "Built outdoor climbing wall, rope climbing path or other place built for climbing. Also bouldering venues. Clarification in 'properties'."}, - :tags {:fi ["kiipeilyseinä" "köysikiipeily"]}, - :name - {:fi "Ulkokiipeilypaikka", - :se "Utomhusklätterplats", - :en "Open-air climbing venue"}, - :type-code 4710, - :main-category 4000, - :status "active", - :sub-category 4700, - :geometry-type "Point", - :props - {:surface-material {:priority 0}, - :surface-material-info {:priority 0}, - :free-use? {:priority 0}, - :climbing-routes-count {:priority 0}, - :ice-climbing? {:priority 0}, - :climbing-wall-height-m {:priority 1}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :area-m2 {:priority 1}, - :lighting-info {:priority 0}, - :climbing-wall-width-m {:priority 1}, - :ligthing? {:priority 0}, - :school-use? {:priority 0}}}, - 304 - {:description - {:fi - "Tavallisen arkiliikunnan taukopaikka, päiväkäyttöön. Lisätietoihin merkitään kohteessa olevat palvelut, esim. kahvio, vuokrauspiste tai opastuspiste.", - :se "Rastplats för bruk under dagen, vardagsmotion.", - :en "Rest area for regular daily sports, for daytime use."}, - :tags {:fi ["tupa" "taukopaikka" "ulkoilumaja" "hiihtomaja"]}, - :name - {:fi "Ulkoilumaja/hiihtomaja", - :se "Friluftsstuga/skidstuga", - :en "Outdoor/ski lodge "}, - :type-code 304, - :main-category 0, - :status "active", - :sub-category 2, - :geometry-type "Point", - :props - {:toilet? {:priority 0}, - :may-be-shown-in-excursion-map-fi? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :customer-service-point? {:priority 0}, - :equipment-rental? {:priority 0}, - :free-use? {:priority 0}}}, - 4412 - {:description - {:fi - "Pyöräilyreitti, joka kulkee enimmäkseen päällystetyillä teillä tai sorateillä. Reitti voi olla merkitty maastoon tai se on digitaalisesti opastettu.", - :se "Cykelled, ej för mountainbikar.", - :en "Biking route, not intended for cross-country biking."}, - :tags {:fi []}, - :name {:fi "Pyöräilyreitti", :se "Cykelled", :en "Biking route"}, - :type-code 4412, - :main-category 4000, - :status "active", - :sub-category 4400, - :geometry-type "LineString", - :props - {:surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :free-use? {:priority 0}, - :may-be-shown-in-excursion-map-fi? {:priority 0}, - :route-width-m {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :rest-places-count {:priority 0}, - :lit-route-length-km {:priority 1}, - :route-length-km {:priority 1}}}, - 4820 - {:description - {:fi - "Ampumarata jossa myös palveluita. SM-kisojen järjestäminen mahdollista.", - :se "Skjutbana med tjänster. Möjligt att arrangera FM-tävlingar.", - :en - "Shooting range with services. National competitions possible."}, - :tags {:fi ["ampumapaikka" "ammunta"]}, - :name - {:fi "Ampumaurheilukeskus", - :se "Sportskyttecentrum", - :en "Shooting sports centre"}, - :type-code 4820, - :main-category 4000, - :status "active", - :sub-category 4800, - :geometry-type "Point", - :props - {:stand-capacity-person {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :air-gun-shooting? {:priority 0}, - :toilet? {:priority 0}, - :pistol-shooting? {:priority 0}, - :shooting-positions-count {:priority 1}, - :area-m2 {:priority 0}, - :lighting-info {:priority 0}, - :rifle-shooting? {:priority 0}, - :year-round-use? {:priority 0}, - :scoreboard? {:priority 0}, - :loudspeakers? {:priority 0}, - :shotgun-shooting? {:priority 0}, - :free-rifle-shooting? {:priority 0}, - :ligthing? {:priority 1}, - :accessibility-info {:priority 0}, - :track-length-m {:priority 1}}}, - 1170 - {:description - {:fi "Ratapyöräilyä varten rakennettu paikka, ulkona (velodromi).", - :se "Utomhus, velodrom.", - :en "For track racing outdoors (velodrome)."}, - :tags {:fi ["velodromi"]}, - :name - {:fi "Pyöräilyrata/velodromi", - :se "Velodrom", - :en "Velodrome"}, - :type-code 1170, - :main-category 1000, - :status "active", - :sub-category 1100, - :geometry-type "Point", - :props - {:surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :free-use? {:priority 0}, - :track-width-m {:priority 1}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :area-m2 {:priority 0}, - :lighting-info {:priority 0}, - :ligthing? {:priority 1}, - :school-use? {:priority 0}, - :track-length-m {:priority 1}}}, - 6150 - {:description - {:fi "Islanninhevosten askellajiratsastukseen varattu rata ulkona.", - :se - "En bana utomhus avsedd för gångartstävlingar med islandshästar.", - :en - "An outdoor track designated for gaited riding competitions with Icelandic horses."}, - :tags - {:fi - ["islanninhevosrata" - "islanninhevosratsastus" - "ovaalibaana" - "askellajiratsastus" - "askellajirata"], - :se - ["islandshästbana" - "islandshästridning" - "ovalbana" - "gångartstävling" - "gångartsbana"], - :en - ["Icelandic horse track" - "Icelandic horse riding" - "oval track" - "gaited riding" - "gaited track"]}, - :name {:fi "Ovaalirata", :se "Ovalbana", :en "Oval Track"}, - :type-code 6150, - :main-category 6000, - :status "active", - :sub-category 6100, - :geometry-type "Point", - :props - {:surface-material {:priority 0}, - :surface-material-info {:priority 0}, - :track-width-m {:priority 0}, - :free-use? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :customer-service-point? {:priority 0}, - :ligthing? {:priority 0}, - :track-length-m {:priority 0}}}, - 4404 - {:description - {:fi - "Erityisesti luontoharrastusta varten rakennettu ulkoilureitti. Reitin varrella opasteita tai infotauluja alueen luonnosta.", - :se - "I synnerhet för naturintresse, info- och orienteringstavlor längs leden.", - :en - "Intended particularly for nature activities; signposts or info boards along the route."}, - :tags {:fi ["retkeily"]}, - :name {:fi "Luontopolku", :se "Naturstig", :en "Nature trail"}, - :type-code 4404, - :main-category 4000, - :status "active", - :sub-category 4400, - :geometry-type "LineString", - :props - {:surface-material {:priority 0}, - :surface-material-info {:priority 0}, - :free-use? {:priority 0}, - :may-be-shown-in-excursion-map-fi? {:priority 0}, - :route-width-m {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :rest-places-count {:priority 0}, - :lit-route-length-km {:priority 0}, - :accessibility-info {:priority 0}, - :school-use? {:priority 0}, - :route-length-km {:priority 1}}}, - 108 - {:description - {:fi - "Metsähallituksen päätöksellä perustettu virkistysmetsä. Metsätaloudessa huomioidaan mm. maisemalliset arvot. Metsähallitus tietolähde.", - :se - "Grundad enligt Forststyrelsens beslut. I skogsbruket tas hänsyn till bl a landskapsvärden. Källa: Forststyrelsen.", - :en - "Recreational forest designated by Metsähallitus. E.g. scenic value is considered in forestry. Source of information Metsähallitus."}, - :tags {:fi []}, - :name - {:fi "Virkistysmetsä", - :se "Friluftsskog", - :en "Recreational forest"}, - :type-code 108, - :main-category 0, - :status "deprecated", - :sub-category 1, - :geometry-type "Polygon", - :props - {:area-km2 {:priority 0}, - :school-use? {:priority 0}, - :free-use? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, - 4401 - {:description - {:fi - "Kuntoiluun tarkoitettu hoidettu liikuntareitti asutuksen läheisyydessä. Usein ainakin osittain valaistu.", - :se "Led avsedd för konditionssport i närheten av bebyggelse.", - :en "Route intended for jogging in or near a residential area."}, - :tags {:fi ["pururata"]}, - :name {:fi "Kuntorata", :se "Konditionsbana", :en "Jogging track"}, - :type-code 4401, - :main-category 4000, - :status "active", - :sub-category 4400, - :geometry-type "LineString", - :props - {:surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :free-use? {:priority 0}, - :may-be-shown-in-excursion-map-fi? {:priority 0}, - :outdoor-exercise-machines? {:priority 0}, - :route-width-m {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :rest-places-count {:priority 0}, - :shooting-positions-count {:priority 0}, - :lit-route-length-km {:priority 1}, - :accessibility-info {:priority 0}, - :school-use? {:priority 0}, - :route-length-km {:priority 1}}}, - 2350 - {:description - {:fi - "Pysyvästi tanssi-, ilmaisu- tai ryhmäliikuntaan varustettu itsenäinen tila, joka ei ole osa esim. kuntokeskusta. Myös boutique-, fitness- ja mikrostudiot ovat tanssi- tai ryhmäliikuntatiloja.", - :se "Permanent utrustning för dans och kreativ motion.", - :en - "Space permanently equipped for dance or expressive movement exercise."}, - :tags {:fi ["peilisali" "baletti" "tanssisali"]}, - :name - {:fi "Tanssi-/ryhmäliikuntatila", - :se "Utrymme för dans", - :en "Dance studio"}, - :type-code 2350, - :main-category 2000, - :status "active", - :sub-category 2300, - :geometry-type "Point", - :props - {:height-m {:priority 0}, - :surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :free-use? {:priority 0}, - :active-space-width-m {:priority 0}, - :mirror-wall? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :group-exercise-rooms-count {:priority 0}, - :area-m2 {:priority 1}, - :active-space-length-m {:priority 0}, - :school-use? {:priority 0}}}, - 2340 - {:description - {:fi "Pysyvästi miekkailuun varustettu tila.", - :se "Permanent utrustning för fäktning.", - :en "Space permanently equipped for fencing."}, - :tags {:fi []}, - :name - {:fi "Miekkailutila", - :se "Utrymme för fäktning", - :en "Fencing venue"}, - :type-code 2340, - :main-category 2000, - :status "active", - :sub-category 2300, - :geometry-type "Point", - :props - {:height-m {:priority 0}, - :surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :free-use? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :area-m2 {:priority 1}, - :fencing-bases-count {:priority 1}, - :school-use? {:priority 0}}}, - 2120 - {:description - {:fi - "Liikuntatila, jossa on useita kuntosalilaitteita pysyvästi sijoitettuna.", - :se "Gymredskap osv. Storleken anges i karakteristika.", - :en "Gym equipment, etc. Size specified in properties."}, - :tags {:fi ["kuntoilu" "voimailu"]}, - :name {:fi "Kuntosali", :se "Gym", :en "Gym"}, - :type-code 2120, - :main-category 2000, - :status "active", - :sub-category 2100, - :geometry-type "Point", - :props - {:surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :free-customer-use? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :group-exercise-rooms-count {:priority 0}, - :area-m2 {:priority 1}, - :weight-lifting-spots-count {:priority 0}, - :customer-service-point? {:priority 0}, - :spinning-hall? {:priority 0}, - :school-use? {:priority 0}, - :exercise-machines-count {:priority 0}}}, - 109 - {:description - {:fi - "Ulkoilulailla perustetut, retkeilyä ja luonnon virkistyskäyttöä varten. Metsähallitus tietolähteenä.", - :se - "Grundat enligt lagen om friluftsliv för att användas för friluftsliv och rekreation i naturen. Källa: Forststyrelsen.", - :en - "Established based on the Outdoor Recreation Act for hiking and recreational use of nature. Source of information Metsähallitus."}, - :tags {:fi []}, - :name - {:fi "Valtion retkeilyalue", - :se "Statens friluftsområde", - :en "National hiking area"}, - :type-code 109, - :main-category 0, - :status "active", - :sub-category 1, - :geometry-type "Polygon", - :props - {:area-km2 {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, - 1650 - {:description - {:fi - "Ensisijaisesti golfin pelaamiseen tarkoitettu alue kesäkaudella. Reikien määrä merkitään lisätietoihin.", - :se "Officiell golfbana. Antalet hål anges i karakteristika.", - :en - "Official golf course. Number of holes included in properties."}, - :tags {:fi ["greeni" "puttialue" "range"]}, - :name {:fi "Golfkenttä (alue)", :se "Golfbana", :en "Golf course"}, - :type-code 1650, - :main-category 1000, - :status "active", - :sub-category 1600, - :geometry-type "Polygon", - :props - {:holes-count {:priority 1}, - :free-use? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :lighting-info {:priority 0}, - :customer-service-point? {:priority 0}, - :green? {:priority 0}, - :ligthing? {:priority 1}, - :school-use? {:priority 0}, - :range? {:priority 0}}}, - 4441 - {:description - {:fi "Koiravaljakoille ylläpidetty reitti.", - :se "En rutt underhållen för hundspann.", - :en "A route maintained for dog sledding."}, - :tags {:fi ["valjakkoajo" "valjakkoreitti"], :se [], :en []}, - :name - {:fi "Koiravaljakkoreitti", - :se "Hundspannsrutt", - :en "Dog Sledding Route"}, - :type-code 4441, - :main-category 4000, - :status "active", - :sub-category 4400, - :geometry-type "LineString", - :props - {:surface-material {:priority 0}, - :surface-material-info {:priority 0}, - :route-length-km {:priority 0}, - :lit-route-length-km {:priority 0}, - :route-width-m {:priority 0}, - :free-use? {:priority 0}, - :year-round-use? {:priority 0}}}, - 5160 - {:description - {:fi - "Soudun ja melonnan sisäharjoittelutila on erityisesti näihin lajeihin pysyvästi tarkoitettu liikuntapaikka.", - :se "Separat, ej normal bassäng.", - :en "Separate training facility, not a regular swimming pool."}, - :tags {:fi ["kajakki" "kanootti" "melonta"]}, - :name - {:fi "Soudun ja melonnan sisäharjoittelutila", - :se "Inomhusträningsutrymme för rodd och paddling", - :en "Indoor training facility for rowing and canoeing"}, - :type-code 5160, - :main-category 5000, - :status "active", - :sub-category 5100, - :geometry-type "Point", - :props - {:area-m2 {:priority 0}, - :free-use? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, - 1550 - {:description - {:fi - "Luisteluun tarkoitettu luonnonjäälle tai maalle rakennettava huollettu luistelureitti. Rakennetaan talvisin samalle alueelle. ", - :se - "Byggs varje vinter på samma område t ex i en idrottspark eller på havsis.", - :en - "Built yearly in the same area, e.g., in a sports park or on frozen lake/sea."}, - :tags {:fi ["luistelu" "retkiluistelu" "retkiluistelurata"]}, - :name - {:fi "Luistelureitti", :se "Skridskoled", :en "Ice-skating route"}, - :type-code 1550, - :main-category 1000, - :status "active", - :sub-category 1500, - :geometry-type "Point", - :props - {:surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :free-use? {:priority 0}, - :may-be-shown-in-excursion-map-fi? {:priority 0}, - :track-width-m {:priority 1}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :lighting-info {:priority 0}, - :equipment-rental? {:priority 0}, - :customer-service-point? {:priority 0}, - :ligthing? {:priority 1}, - :school-use? {:priority 0}, - :track-length-m {:priority 1}}}, - 3230 - {:description - {:fi - "Pieni yleinen uimaranta tai uimapaikka, jossa pelastusväline ja ilmoitustaulu. Veden laadun seuranta ja alueen hoito järjestetty.", - :se - "Liten allmän badstrand eller badplats. Räddningsutrustning och en anslagstavla finns. Kvaliteten på vattnet följs upp och området underhålls.", - :en - "Small public beach or swimming site. Rescue equipment and a notice board are available. The quality of the water is monitored and the area is maintained."}, - :tags {:fi ["uimaranta"]}, - :name {:fi "Uimapaikka", :se "Badplats", :en "Swimming site"}, - :type-code 3230, - :main-category 3000, - :status "active", - :sub-category 3200, - :geometry-type "Point", - :props - {:free-use? {:priority 0}, - :pier? {:priority 0}, - :may-be-shown-in-excursion-map-fi? {:priority 0}, - :beach-length-m {:priority 1}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :shower? {:priority 0}, - :changing-rooms? {:priority 0}, - :sauna? {:priority 0}, - :other-platforms? {:priority 0}, - :school-use? {:priority 0}}}, - 5130 - {:description - {:fi "Pysyvä moottorivenekilpailujen rata-alue.", - :se "Permanent banområde för hastighetstävlingar.", - :en "Permanent track area for speed competitions."}, - :tags {:fi []}, - :name - {:fi "Moottoriveneurheilualue", - :se "Område för motorbåtsport", - :en "Motor boat sports area"}, - :type-code 5130, - :main-category 5000, - :status "active", - :sub-category 5100, - :geometry-type "Point", - :props - {:pier? {:priority 0}, - :area-km2 {:priority 0}, - :boat-places-count {:priority 0}, - :free-use? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, - 5110 - {:description - {:fi - "Soutustadion sisältää pysyvästi soutuun käytettäviä rakenteita. Soutustadionissa on katsomo ja valmius ratamerkintöihin.", - :se - "Byggt för rodd, permanent. Läktare och förberett för banmärkning.", - :en - "Permanent construction for rowing. Bleachers, track markings possible."}, - :tags {:fi []}, - :name {:fi "Soutustadion", :se "Roddstadion", :en "Rowing stadium"}, - :type-code 5110, - :main-category 5000, - :status "active", - :sub-category 5100, - :geometry-type "Point", - :props - {:automated-timing? {:priority 0}, - :stand-capacity-person {:priority 0}, - :free-use? {:priority 0}, - :pier? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :area-m2 {:priority 0}, - :scoreboard? {:priority 0}, - :track-length-m {:priority 1}}}, - 3240 - {:description - {:fi - "Talviuintipaikka voi sijaita avannossa, avovedessä tai maauimalassa talvikaudella. Talviuintipaikka merkitään omaksi liikuntapaikakseen.", - :se - "Vinterbadplats kan vara belägen i en vak, öppet vatten eller utomhuspool. Vinterbadplats är markerad som egen idrottsanläggning", - :en - "Winter swimming area may be located in an ice hole, open water or open air pool. Winter swimming area is marked as its own sports facility."}, - :tags {:fi ["avanto" "avantouinti" "talviuinti"]}, - :name - {:fi "Talviuintipaikka", - :se "Vinterbadplats", - :en "Winter swimming area"}, - :type-code 3240, - :main-category 3000, - :status "active", - :sub-category 3200, - :geometry-type "Point", - :props - {:free-use? {:priority 0}, - :pier? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :shower? {:priority 0}, - :changing-rooms? {:priority 0}, - :ice-reduction? {:priority 0}, - :sauna? {:priority 0}, - :school-use? {:priority 0}}}, - 4510 - {:description - {:fi - "Suunnistukseen käytetty alue. Lisätietoihin merkitään, jos aluetta käytetään mobo-, pyörä- tai hiihtosuunnistukseen. Suunnistusalueesta on saatavilla kartta ja maankäyttöön on maanomistajan suostumus.", - :se - "Anmält till orienteringsförbundet. Karta över området tillgänglig.", - :en - "The Finnish Orienteering Federation has been informed. A map of the area available."}, - :tags {:fi []}, - :name - {:fi "Suunnistusalue", - :se "Orienteringsområde", - :en "Orienteering area"}, - :type-code 4510, - :main-category 4000, - :status "active", - :sub-category 4500, - :geometry-type "Polygon", - :props - {:area-km2 {:priority 0}, - :school-use? {:priority 0}, - :free-use? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :mobile-orienteering? {:priority 0}, - :bike-orienteering? {:priority 0}, - :ski-orienteering? {:priority 0}}}, - 4240 - {:description - {:fi "Katettu laskettelurinne.", - :se "Slalombacke med tak. Höjdskillnad och längd i karakteristika.", - :en - "Covered ski slope. Height and length specified in attributes."}, - :tags {:fi []}, - :name - {:fi "Lasketteluhalli", - :se "Slalomhall", - :en "Downhill skiing hall"}, - :type-code 4240, - :main-category 4000, - :status "active", - :sub-category 4200, - :geometry-type "Point", - :props - {:surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :free-use? {:priority 0}, - :ski-service? {:priority 0}, - :altitude-difference {:priority 1}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :area-m2 {:priority 0}, - :equipment-rental? {:priority 0}, - :route-length-km {:priority 1}}}, - 2270 - {:description - {:fi - "Ensisijaisesti squashin pelaamiseen tarkoitettu halli. Yksittäisen kentän mitat 9,75 m x 6,4 m. Vapaa korkeus ja pintamateriaali ilmoitetaan lisätiedoissa.", - :se "En eller flera squashplaner. Antalet planer i karakteristika.", - :en - "One or more squash courts. Number of courts specified in properties."}, - :tags {:fi ["squash" "squash-kenttä" "squashkenttä" "squashhalli"]}, - :name {:fi "Squash-halli", :se "Squashhall", :en "Squash hall"}, - :type-code 2270, - :main-category 2000, - :status "active", - :sub-category 2200, - :geometry-type "Point", - :props - {:height-m {:priority 1}, - :surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :stand-capacity-person {:priority 0}, - :free-use? {:priority 0}, - :tennis-courts-count {:priority 0}, - :field-length-m {:priority 0}, - :badminton-courts-count {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :padel-courts-count {:priority 0}, - :toilet? {:priority 0}, - :area-m2 {:priority 1}, - :field-width-m {:priority 0}, - :scoreboard? {:priority 0}, - :floorball-fields-count {:priority 0}, - :squash-courts-count {:priority 1}, - :customer-service-point? {:priority 0}, - :volleyball-fields-count {:priority 0}, - :school-use? {:priority 0}}}, - 4210 - {:description - {:fi - "Pysyvästi lajiin varustettu tila, esim. curlingrata tai curlinghalli.", - :se "Curlingbana med tak och permanent utrustning för grenen.", - :en "Covered track permanently equipped for curling."}, - :tags {:fi ["curlinghalli" "curling-halli" "curling-rata"]}, - :name - {:fi "Curlingrata/-halli", :se "Curlingbana", :en "Curling sheet"}, - :type-code 4210, - :main-category 4000, - :status "active", - :sub-category 4200, - :geometry-type "Point", - :props - {:surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :stand-capacity-person {:priority 0}, - :free-use? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :changing-rooms? {:priority 0}, - :area-m2 {:priority 1}, - :curling-lanes-count {:priority 0}, - :changing-rooms-m2 {:priority 0}}}, - 301 - {:description - {:fi - "Päiväsaikainen levähdyspaikka retkeilijöille. Esimerkiksi kodalla tarkoitetaan kotamallista sääsuojaa tai levähdyspaikkaa ja laavu on kaltevakattoinen sääsuoja, joka sisältää tulipaikan. Lisätietoihin merkitään tieto tulentekopaikasta.", - :se "Viloplats för vandrare under dagtid.", - :en "Daytime rest stop for hikers."}, - :tags {:fi ["taukopaikka"]}, - :name - {:fi "Laavu, kota tai kammi", - :se "Vindskydd eller kåta", - :en "Lean-to, goahti (Lapp tent shelter) or 'kammi' earth lodge"}, - :type-code 301, - :main-category 0, - :status "active", - :sub-category 2, - :geometry-type "Point", - :props - {:may-be-shown-in-excursion-map-fi? {:priority 0}, - :toilet? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :water-point {:priority 0}, - :free-use? {:priority 0}}}, - 111 - {:description - {:fi - "Kansallispuistot ovat luonnonsuojelualueita, joiden perustamisesta ja tarkoituksesta on säädetty lailla. Kansallispuistoissa on merkittyjä reittejä, luontopolkuja ja tulentekopaikkoja. Kansallispuistoissa voi myös yöpyä, sillä niissä on telttailualueita tai yöpymiseen tarkoitettuja rakennuksia. LIPAS-aineisto perustuu Metsähallituksen tietoihin.", - :se - "Naturskyddsområden med lagstadgad status och uppgift. Areal minst 1000 ha. Källa: Forststyrelsen.", - :en - "Nature conservation areas whose establishment and purpose are based on legislation. Min. area 1,000 ha. Source of information Metsähallitus."}, - :tags {:fi []}, - :name - {:fi "Kansallispuisto", :se "Nationalpark", :en "National park"}, - :type-code 111, - :main-category 0, - :status "active", - :sub-category 1, - :geometry-type "Polygon", - :props - {:area-km2 {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, - 4630 - {:description - {:fi - "Hiihtokilpailujen järjestämiseen soveltuva kisakeskus, jossa on esimerkiksi lähtö- ja maalialue, huoltotilat ja riittävä latuverkosto.", - :se "Start- och målområden, serviceutrymmen, spårsystem.", - :en "Start and finish area, service premises. Tracks."}, - :tags {:fi ["hiihtostadion"]}, - :name - {:fi "Kilpahiihtokeskus", - :se "Maastohiihtokeskus", - :en "Ski competition centre"}, - :type-code 4630, - :main-category 4000, - :status "active", - :sub-category 4600, - :geometry-type "Point", - :props - {:stand-capacity-person {:priority 0}, - :free-use? {:priority 0}, - :ski-service? {:priority 0}, - :finish-line-camera? {:priority 0}, - :ski-track-traditional? {:priority 0}, - :route-width-m {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :shower? {:priority 0}, - :rest-places-count {:priority 0}, - :changing-rooms? {:priority 0}, - :lit-route-length-km {:priority 0}, - :scoreboard? {:priority 0}, - :sauna? {:priority 0}, - :loudspeakers? {:priority 0}, - :accessibility-info {:priority 0}, - :ski-track-freestyle? {:priority 0}, - :route-length-km {:priority 0}}}, - 4810 - {:description - {:fi "Ulkoampumarata yhdelle tai useammalle lajille.", - :se "Utomhusskjutbana för en eller flera grenar.", - :en "Outdoor shooting range for one or more sports. "}, - :tags {:fi ["ampumapaikka" "ammunta"]}, - :name - {:fi "Ampumarata", :se "Skjutbana", :en "Open-air shooting range"}, - :type-code 4810, - :main-category 4000, - :status "active", - :sub-category 4800, - :geometry-type "Point", - :props - {:stand-capacity-person {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :air-gun-shooting? {:priority 0}, - :toilet? {:priority 0}, - :pistol-shooting? {:priority 0}, - :shooting-positions-count {:priority 1}, - :area-m2 {:priority 0}, - :lighting-info {:priority 0}, - :rifle-shooting? {:priority 0}, - :year-round-use? {:priority 0}, - :scoreboard? {:priority 0}, - :loudspeakers? {:priority 0}, - :shotgun-shooting? {:priority 0}, - :free-rifle-shooting? {:priority 0}, - :ligthing? {:priority 1}, - :accessibility-info {:priority 0}, - :track-length-m {:priority 1}}}, - 1540 - {:description - {:fi - "Pikaluisteluun varusteltu luistelurata. Radan koko ja pituus lisätään ominaisuustietoihin. Käytössä talvikaudella.", - :se "Bana för hastighetsåkning. Används under vintersäsongen.", - :en "Track size and length specified in properties."}, - :tags {:fi ["luistelurata"]}, - :name - {:fi "Pikaluistelurata", - :se "Bana för hastighetsåkning på skridsko", - :en "Speed-skating track"}, - :type-code 1540, - :main-category 1000, - :status "active", - :sub-category 1500, - :geometry-type "Point", - :props - {:surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :stand-capacity-person {:priority 0}, - :free-use? {:priority 0}, - :track-width-m {:priority 1}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :area-m2 {:priority 0}, - :lighting-info {:priority 0}, - :changing-rooms-m2 {:priority 0}, - :customer-service-point? {:priority 0}, - :ligthing? {:priority 1}, - :school-use? {:priority 0}, - :track-length-m {:priority 1}}}, - 5320 - {:description - {:fi - "Pääasiassa moottoripyöräilyä varten rakennettu, luonnonmukainen ei-asfalttipintainen alue (esim. enduroreitit ja trial-harjoittelualueet maastoliikennealueilla).", - :se "Huvudsakligen för motorcykelsport.", - :en "Mainly for motorcycling."}, - :tags {:fi ["motocross"]}, - :name - {:fi "Moottoripyöräilyalue", - :se "Område för motorcykelsport", - :en "Motorcycling area"}, - :type-code 5320, - :main-category 5000, - :status "active", - :sub-category 5300, - :geometry-type "Point", - :props - {:surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :automated-timing? {:priority 0}, - :stand-capacity-person {:priority 0}, - :free-use? {:priority 0}, - :track-width-m {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :area-m2 {:priority 0}, - :lighting-info {:priority 0}, - :year-round-use? {:priority 0}, - :scoreboard? {:priority 0}, - :loudspeakers? {:priority 0}, - :ligthing? {:priority 0}, - :covered-stand-person-count {:priority 0}, - :track-length-m {:priority 1}}}, - 3210 - {:description - {:fi - "Maauimala tai vesipuisto on ulkona sijaitseva, vedenpuhdistusjärjestelmällä varustettu uintiin tarkoitettu ja hoidettu vesistö tai uima-altaita/allas. Lisäksi kohteessa voi olla vesiliukumäkiä.", - :se "Vattenreningssystem.", - :en "Water treatment system."}, - :tags {:fi ["uima-allas" "ulkoallas" "ulkouima-allas"]}, - :name - {:fi "Maauimala/vesipuisto", :se "Utebassäng", :en "Open-air pool "}, - :type-code 3210, - :main-category 3000, - :status "active", - :sub-category 3200, - :geometry-type "Point", - :props - {:pool-tracks-count {:priority 0}, - :stand-capacity-person {:priority 0}, - :free-use? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :pool-width-m {:priority 0}, - :pool-min-depth-m {:priority 0}, - :toilet? {:priority 0}, - :swimming-pool-count {:priority 1}, - :pool-water-area-m2 {:priority 1}, - :pool-length-m {:priority 0}, - :pool-max-depth-m {:priority 0}, - :loudspeakers? {:priority 0}, - :pool-temperature-c {:priority 0}, - :school-use? {:priority 0}}}, - 4640 - {:description - {:fi - "Hiihdon opetteluun ja harjoitteluun tarkoitettu paikka erityisesti lapsille. Erilaisia harjoittelupaikkoja, kuten latuja, mäkiä ym.", - :se "Träningsplats för skidåkning, teknikhaster mm.", - :en - "Ski training venue, an area of parallel short ski tracks for ski instruction, etc."}, - :tags {:fi []}, - :name - {:fi "Hiihtomaa", :se "Skidland", :en "Cross-country ski park"}, - :type-code 4640, - :main-category 4000, - :status "active", - :sub-category 4600, - :geometry-type "Point", - :props - {:free-use? {:priority 0}, - :ski-service? {:priority 0}, - :ski-track-traditional? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :rest-places-count {:priority 0}, - :lit-route-length-km {:priority 0}, - :scoreboard? {:priority 0}, - :equipment-rental? {:priority 0}, - :loudspeakers? {:priority 0}, - :accessibility-info {:priority 0}, - :ski-track-freestyle? {:priority 0}, - :school-use? {:priority 0}, - :route-length-km {:priority 0}}}, - 1150 - {:description - {:fi - "Rullaluistelua, skeittausta, potkulautailua varten varustettu paikka. Ominaisuustiedoissa tarkemmat tiedot kohteesta.", - :se - "Plats utrustad för rullskridskoåkning, skejtning och sparkcykelåkning.", - :en - "An area equipped for roller-blading, skateboarding, kick scooting."}, - :tags - {:fi ["ramppi" "skeittipaikka" "skeittipuisto" "skeittiparkki"]}, - :name - {:fi "Skeitti-/rullaluistelupaikka", - :se "Plats för skejtning/rullskridskoåkning", - :en "Skateboarding/roller-blading rink "}, - :type-code 1150, - :main-category 1000, - :status "active", - :sub-category 1100, - :geometry-type "Point", - :props - {:area-m2 {:priority 1}, - :surface-material-info {:priority 0}, - :surface-material {:priority 1}, - :ligthing? {:priority 1}, - :school-use? {:priority 0}, - :free-use? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :lighting-info {:priority 0}}}, - 2310 - {:description - {:fi - "Yksittäinen yleisurheilun olosuhde sisätiloissa esim. liikunta- tai monitoimihallin yhteydessä. Suorituspaikat kuvataan lisätiedoissa.", - :se - "Fristående, ej i anslutning till en friidrottshall. I karakteristika anges övningsplatserna.", - :en - "Stand-alone, not in an athletics hall. Venues specified under properties."}, - :tags {:fi ["yleisurheilu" "juoksurata"]}, - :name - {:fi "Yksittäinen yleisurheilun suorituspaikka", - :se "Enstaka övningsplats för friidrott", - :en "Stand-alone athletics venue"}, - :type-code 2310, - :main-category 2000, - :status "active", - :sub-category 2300, - :geometry-type "Point", - :props - {:height-m {:priority 0}, - :surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :free-use? {:priority 0}, - :javelin-throw-places-count {:priority 0}, - :sprint-track-length-m {:priority 0}, - :inner-lane-length-m {:priority 0}, - :discus-throw-places {:priority 0}, - :hammer-throw-places-count {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :polevault-places-count {:priority 0}, - :area-m2 {:priority 0}, - :shotput-count {:priority 0}, - :longjump-places-count {:priority 0}, - :school-use? {:priority 0}, - :highjump-places-count {:priority 0}}}, - 5210 - {:description - {:fi - "Harraste- tai urheiluilmailuun tarkoitettu alue, esim. lentopaikka.", - :se "Flygsportarena, t ex en flygplats.", - :en "Area for air sports, e.g. an airfield."}, - :tags - {:fi - ["lentäminen" - "lento" - "lentokone" - "ilmailu" - "ilmailualue" - "lentokenttä"]}, - :name - {:fi "Urheiluilmailualue", - :se "Område för flygsport", - :en "Sport aviation area"}, - :type-code 5210, - :main-category 5000, - :status "active", - :sub-category 5200, - :geometry-type "Point", - :props - {:track-length-m {:priority 0}, - :area-m2 {:priority 0}, - :surface-material-info {:priority 0}, - :surface-material {:priority 0}, - :track-width-m {:priority 0}, - :free-use? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, - 2380 - {:description - {:fi "Parkouria varten varustettu sisätila.", - :se "Inomhusutrymme utrustat för parkour.", - :en "Indoor space equipped for parkour. "}, - :tags {:fi ["parkour"]}, - :name {:fi "Parkour-sali", :se "Parkoursal", :en "Parkour hall"}, - :type-code 2380, - :main-category 2000, - :status "active", - :sub-category 2300, - :geometry-type "Point", - :props - {:surface-material {:priority 0}, - :surface-material-info {:priority 0}, - :free-use? {:priority 0}, - :parkour-hall-equipment-and-structures {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :area-m2 {:priority 1}, - :highest-obstacle-m {:priority 0}, - :auxiliary-training-area? {:priority 0}, - :school-use? {:priority 0}}}, - 103 - {:description - {:fi - "Voivat sijaita taajaman reunoilla, vyöhykkeittäin taajaman sisällä tai taajaman ulkopuolella. Kohteissa voi olla myös taajamasta lähteviä tai taajamaan palaavia reittejä tai polku- ja reittiverkosto. Kohteet sisältävät vaihtelevaa maastoa ja luonnonmukaisia tai puistomaisia alueita. Kohteet voivat myös sijaita vesialuiden lähellä kuten rannoilla tai saarissa. Kohteiden pääasiallinen käyttö on retkeilyä ja luonnossa virkistäytymistä, mutta niitä voidaan käyttää monipuolisesti erilaisen liikunnan kuten hiihdon, lenkkeilyn tai uinnin harrastamiseen. Kaavamerkintä esim. VR. HUOM! Uusien liikunta- ja ulkoilupaikkojen lisäksi Ulkoilu-/virkistysalueluokka sisältää ennen vuotta 2024 Ulkoilualueet ja Retkeilyalueet tyyppiluokkiin lisätyt olosuhteet", - :se - "Området befinner sig i utkanten av tätorter eller i zoner inom tätorten. På 1-10 kilometers avstånd från bebyggelse. Friluftsområdet används för t.ex. promenader, skidning, joggning, simning. Serverar oftast friluftsaktiviteter för en kommun. Området erbjuder en stor variation av motions möjligheter. Området kan bestå av skog, kärr, åkrar, naturenliga områden och parkliknande delar. Planbeteckning VR.", - :en - "On the edge of population centres or zoned within population centres. 1-10 km from residential areas. Used for e.g. walks, skiing, jogging, swimming. Serves usually recreational needs within one municipality, offers versatile sports facilities. May include forest, swamp, fields, natural areas and park areas. Symbol VR."}, - :tags {:fi ["puisto" "virkistysalue"]}, - :name - {:fi "Ulkoilu-/virkistysalue", - :se "Friluftsområde", - :en "Outdoor area"}, - :type-code 103, - :main-category 0, - :status "active", - :sub-category 1, - :geometry-type "Polygon", - :props - {:may-be-shown-in-excursion-map-fi? {:priority 0}, - :area-km2 {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :water-point {:priority 0}}}, - 201 - {:description - {:fi - "Vapaa-ajankalastukseen sopiva kohde. Kohteessa voi olla palvelurakenteita.", - :se - "Område eller en plats i ett naturligt vattendrag som ställts i ordning för fritidsfiske.", - :en - "Natural aquatic destination equipped and maintained for recreational fishing."}, - :tags {:fi ["kalastusalue" "kalastuspaikka"]}, - :name - {:fi "Kalastuskohde (piste)", - :se "Område eller plats för fiske", - :en "Fishing area/spot "}, - :type-code 201, - :main-category 0, - :status "active", - :sub-category 2, - :geometry-type "Point", - :props - {:toilet? {:priority 0}, - :free-use? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :pier? {:priority 0}, - :customer-service-point? {:priority 0}, - :equipment-rental? {:priority 0}}}, - 1220 - {:description - {:fi - "Hyvin varusteltu yleisurheilukenttä. Yleissurheilukentällä on ratoja ja yleisurheilun suorituspaikkoja. Myös kisakäyttö on mahdollista. Lyhytrataiset (juoksurata alle 400 m) yleisurheilukentät tallennettaan yleisurheilun harjoitusalueeksi. Yleisurheilukentällä sijaitseva jalkapallon tai muun lajin keskeinen suorituspaikka merkitään omaksi liikuntapaikakseen (esim. jalkapallostadion tai pallokenttä). ", - :se - "En plan, banor och träningsplatser för friidrott. Centrum, banor, ytbeläggningar samt träningsplatser med beskrivningar.", - :en - "Field, track and athletic venues/facilities. Centre, tracks, surfaces, venues specified in properties. "}, - :tags - {:fi - ["keihäs" - "keihäänheitto" - "moukari" - "pituushyppy" - "juoksurata" - "kolmiloikka" - "seiväs" - "kuula" - "urheilukenttä"]}, - :name - {:fi "Yleisurheilukenttä", - :se "Friidrottsplan", - :en "Athletics field"}, - :type-code 1220, - :main-category 1000, - :status "active", - :sub-category 1200, - :geometry-type "Point", - :props - {:heating? {:priority 0}, - :surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :automated-timing? {:priority 0}, - :stand-capacity-person {:priority 0}, - :free-use? {:priority 0}, - :sprint-lanes-count {:priority 0}, - :javelin-throw-places-count {:priority 0}, - :finish-line-camera? {:priority 0}, - :field-length-m {:priority 1}, - :circular-lanes-count {:priority 0}, - :match-clock? {:priority 0}, - :sprint-track-length-m {:priority 0}, - :inner-lane-length-m {:priority 0}, - :discus-throw-places {:priority 0}, - :hammer-throw-places-count {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :polevault-places-count {:priority 0}, - :toilet? {:priority 0}, - :running-track-surface-material {:priority 1}, - :area-m2 {:priority 1}, - :field-width-m {:priority 1}, - :lighting-info {:priority 0}, - :scoreboard? {:priority 0}, - :shotput-count {:priority 0}, - :longjump-places-count {:priority 0}, - :loudspeakers? {:priority 0}, - :customer-service-point? {:priority 0}, - :ligthing? {:priority 1}, - :covered-stand-person-count {:priority 0}, - :school-use? {:priority 0}, - :highjump-places-count {:priority 0}, - :training-spot-surface-material {:priority 0}}}, - 4411 - {:description - {:fi - "Maastopyöräilyyn tarkoitettu reitti, joka kulkee vaihtelevassa maastossa ja on merkitty maastoon. Reitti voi hyödyntää muita olemassa olevia ulkoilureittipohjia.", - :se "Led avsedd framför allt för mountainbikar, märkt.", - :en "Marked route intended especially for cross-country biking."}, - :tags {:fi []}, - :name - {:fi "Maastopyöräilyreitti", - :se "Mountainbikeled", - :en "Cross-country biking route"}, - :type-code 4411, - :main-category 4000, - :status "active", - :sub-category 4400, - :geometry-type "LineString", - :props - {:surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :free-use? {:priority 0}, - :may-be-shown-in-excursion-map-fi? {:priority 0}, - :route-width-m {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :rest-places-count {:priority 0}, - :lit-route-length-km {:priority 1}, - :school-use? {:priority 0}, - :route-length-km {:priority 1}}}, - 1140 - {:description - {:fi "Parkouria varten varustettu alue.", - :se "Område utrustat för parkour.", - :en "An area equipped for parkour."}, - :tags {:fi []}, - :name {:fi "Parkour-alue", :se "Parkourområde", :en "Parkour area"}, - :type-code 1140, - :main-category 1000, - :status "active", - :sub-category 1100, - :geometry-type "Point", - :props - {:surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :free-use? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :area-m2 {:priority 1}, - :lighting-info {:priority 0}, - :highest-obstacle-m {:priority 0}, - :ligthing? {:priority 1}, - :climbing-wall? {:priority 0}, - :school-use? {:priority 0}}}, - 4520 - {:description - {:fi - "Hiihtosuunnistukseen soveltuva alue, alueesta hiihtosuunnistuskartta saatavilla.", - :se "Skidorienteringskarta över området, ej för sommarorientering.", - :en - "A ski orienteering map of the area available; no summer orienteering."}, - :tags {:fi []}, - :name - {:fi "Hiihtosuunnistusalue", - :se "Skidorienteringsområde", - :en "Ski orienteering area"}, - :type-code 4520, - :main-category 4000, - :status "deprecated", - :sub-category 4500, - :geometry-type "Polygon", - :props - {:area-km2 {:priority 0}, - :school-use? {:priority 0}, - :free-use? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, - 107 - {:description - {:fi - "Matkailupalvelujen alueet ovat matkailua palveleville toiminnoille varattuja alueita, jotka sisältävät myös sisäiset liikenneväylät ja -alueet, alueen toimintoja varten tarpeelliset palvelut ja virkistysalueet sekä yhdyskuntateknisen huollon alueet. Kohteet voivat toimia myös retkeilyauto- ja pyörämatkailijoiden tauko- ja yöpymispaikkoina. Kaavamerkintä RM.", - :se - "Områden med turisttjänster har reserverats för turist- och semestercentra, semesterbyar, semesterhotell och motsvarande aktörer. De har egna trafikleder och -områden samt områden för egna serviceenheter och egen infrastruktur för aktiviteter. Planbeteckning RM.", - :en - "Area reserved for tourism and holiday centres, holiday villages, hotels, etc., also including internal traffic routes and areas; services and recreational areas needed for operations, as well as technical maintenance areas. Symbol RM."}, - :tags {:fi ["ulkoilualue" "virkistysalue" "leirintäalue"]}, - :name - {:fi "Matkailupalveluiden alue", - :se "Område med turisttjänster", - :en "Tourist services area"}, - :type-code 107, - :main-category 0, - :status "active", - :sub-category 1, - :geometry-type "Polygon", - :props - {:area-km2 {:priority 0}, - :free-use? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}}}, - 6110 - {:description - {:fi "Ratsastukseen varustettu kenttä.", - :se "Bana avsedd för ridning. Storlek i karakteristika.", - :en - "Field reserved for horseback riding. Size specified in properties."}, - :tags {:fi []}, - :name {:fi "Ratsastuskenttä", :se "Ridbana", :en "Equestrian field"}, - :type-code 6110, - :main-category 6000, - :status "active", - :sub-category 6100, - :geometry-type "Point", - :props - {:surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :free-use? {:priority 0}, - :field-length-m {:priority 1}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :show-jumping? {:priority 0}, - :area-m2 {:priority 1}, - :field-width-m {:priority 1}, - :lighting-info {:priority 0}, - :ligthing? {:priority 1}, - :school-use? {:priority 0}}}, - 1120 - {:description - {:fi - "Lähiliikuntapaikka on tarkoitettu päivittäiseen ulkoiluun ja liikuntaan. Se sijaitsee asutuksen läheisyydessä, on pienimuotoinen ja alueelle on vapaa pääsy. Yleensä tarjolla on erilaisia suorituspaikkoja. Suorituspaikat tulee tallentaa omiksi liikuntapaikoikseen (esim. pallokenttä, ulkokuntosali tai parkour-alue). Lähiliikuntapaikka voi olla myös koulun tai päiväkodin piha, jos liikuntapaikan käyttö on mahdollista kouluajan ulkopuolella.", - :se - "Ett näridrottsområde är avsett för daglig utomhusaktivitet och motion. Det ligger nära bostadsområden, är småskaligt och har fri tillgång. Vanligtvis erbjuds olika aktivitetsplatser. Aktivitetsplatserna bör registreras som egna idrottsplatser (t.ex. bollplan, utomhusgym eller parkourområde). Ett näridrottsområde kan också vara en skolgård eller en daghemsgård om idrottsplatsen kan användas utanför skoltid.", - :en - "A local sports facility is intended for daily outdoor activities and exercise. It is located near residential areas, is small-scale, and has free access. Usually, various activity sites are available. Activity sites should be recorded as individual sports facilities (e.g., ball field, outdoor gym, or parkour area). A local sports facility can also be a school or daycare yard if the sports facility can be used outside school hours."}, - :tags - {:fi - ["ässäkenttä" "monitoimikenttä" "monitoimikaukalo" "lähipuisto"]}, - :name - {:fi "Lähiliikuntapaikka", - :se "Näridrottsplats", - :en "Neighbourhood sports area"}, - :type-code 1120, - :main-category 1000, - :status "active", - :sub-category 1100, - :geometry-type "Point", - :props - {:surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :fields-count {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :ice-rinks-count {:priority 0}, - :area-m2 {:priority 1}, - :lighting-info {:priority 0}, - :ligthing? {:priority 1}, - :accessibility-info {:priority 0}, - :playground? {:priority 0}, - :school-use? {:priority 0}, - :exercise-machines-count {:priority 0}}}, - 1390 - {:description - {:fi - "Padelin pelaamiseen tarkoitettu kenttä ulkona. Pintamateriaali hiekkatekonurmi. Lajivaatimusten mukaiset seinät. Voi olla myös katettu.", - :se - "En utomhusbana avsedd för padelspel. Underlagsmaterialet är sandkonstgräs. Väggar enligt sportens krav. Kan även vara täckt.", - :en - "An outdoor court intended for playing padel. The surface material is sand artificial grass. Walls meet the sport's requirements. It can also be covered."}, - :tags {:fi ["padel" "padel-kenttä"]}, - :name - {:fi "Padelkenttä", - :se "Område med padelbanor", - :en "Padel court area"}, - :type-code 1390, - :main-category 1000, - :status "active", - :sub-category 1300, - :geometry-type "Point", - :props - {:surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :free-use? {:priority 0}, - :field-length-m {:priority 1}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :area-m2 {:priority 1}, - :field-width-m {:priority 1}, - :lighting-info {:priority 0}, - :water-point {:priority 0}, - :ligthing? {:priority 1}, - :school-use? {:priority 0}, - :light-roof? {:priority 0}}}, - 5340 - {:description - {:fi "Pääasiallisesti kartingajoon tai supermotoon käytetty rata.", - :se "Huvudsakligen för karting.", - :en "Mainly for karting."}, - :tags {:fi []}, - :name {:fi "Karting-rata", :se "Kartingbana", :en "Kart circuit"}, - :type-code 5340, - :main-category 5000, - :status "active", - :sub-category 5300, - :geometry-type "Point", - :props - {:surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :automated-timing? {:priority 0}, - :free-use? {:priority 0}, - :track-width-m {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :area-m2 {:priority 0}, - :lighting-info {:priority 0}, - :year-round-use? {:priority 0}, - :ligthing? {:priority 0}, - :track-length-m {:priority 1}}}, - 302 - {:description - {:fi - "Autiotupa, varaustupa, taukotupa, päivätupa. Yöpymis- ja levähdyspaikka retkeilijöille. Autiotupa avoin, varaustupa lukittu ja maksullinen. Päivätupa päiväkäyttöön.", - :se - "Övernattningsstuga, reserveringsstuga, raststuga, dagstuga. Övernattnings- och rastplats för vandrare. Övernattningsstugan öppen, reserveringsstugan låst och avgiftsbelagd. Dagstuga för bruk under dagen.", - :en - "Open hut, reservable hut, rest hut, day hut. Overnight resting place for hikers. An open hut is freely available; a reservable hut locked and subject to a charge. A day hut is for daytime use."}, - :tags {:fi ["taukopaikka"]}, - :name {:fi "Tupa", :se "Stuga", :en "Hut"}, - :type-code 302, - :main-category 0, - :status "active", - :sub-category 2, - :geometry-type "Point", - :props - {:may-be-shown-in-excursion-map-fi? {:priority 0}, - :toilet? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :water-point {:priority 0}, - :free-use? {:priority 0}}}, - 4405 - {:description - {:fi - "Maastossa oleva retkeilyreitti, yleensä kauempana asutuksesta. Reitin varrella retkeilyn palveluita, esim. laavuja.", - :se - "Utflyktsled i terrängen, oftast längre borta från bebyggelse. Längs rutten friluftstjänster, t ex vindskydd.", - :en - "Natural hiking route, usually further away from residential areas. Provides hiking facilities, e.g. lean-to structures."}, - :tags {:fi ["retkeily" "vaellus" "vaelluspolku"]}, - :name {:fi "Retkeilyreitti", :se "Utflyktsled", :en "Hiking route"}, - :type-code 4405, - :main-category 4000, - :status "active", - :sub-category 4400, - :geometry-type "LineString", - :props - {:surface-material {:priority 0}, - :surface-material-info {:priority 0}, - :free-use? {:priority 0}, - :may-be-shown-in-excursion-map-fi? {:priority 0}, - :route-width-m {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :rest-places-count {:priority 0}, - :lit-route-length-km {:priority 1}, - :accessibility-info {:priority 0}, - :route-length-km {:priority 1}}}, - 6120 - {:description - {:fi "Kylmä tai lämmin katettu tila ratsastukseen.", - :se "Kallt eller varmt takförsett utrymme för ridning.", - :en "Cold or warm, covered space for horseback riding."}, - :tags {:fi ["ratsastushalli" "maneesi"]}, - :name {:fi "Ratsastusmaneesi", :se "Ridmanege", :en "Riding manège"}, - :type-code 6120, - :main-category 6000, - :status "active", - :sub-category 6100, - :geometry-type "Point", - :props - {:heating? {:priority 0}, - :surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :stand-capacity-person {:priority 0}, - :free-use? {:priority 0}, - :field-length-m {:priority 1}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :show-jumping? {:priority 0}, - :area-m2 {:priority 1}, - :field-width-m {:priority 1}, - :lighting-info {:priority 0}, - :school-use? {:priority 0}}}, - 4407 - {:description - {:fi - "Asfaltoitu rullahiihtoon lumettomana aikana tarkoitettu reitti. Reitti kulkee maastossa, ja sen käyttöä muilla kulkutavoilla on rajoitettu.", - :se - "En asfalterad bana avsedd för rullskidåkning under snöfria perioder. Banan går genom terrängen och användningen av andra färdsätt är begränsad.", - :en - "An asphalt track intended for roller skiing during snow-free periods. The track runs through terrain, and the use of other modes of travel is restricted."}, - :tags - {:fi ["rullahiihto"], :se ["rullskidåkning"], :en ["roller skiing"]}, - :name - {:fi "Rullahiihtorata", :se "Rullskidbana", :en "Roller Ski Track"}, - :type-code 4407, - :main-category 4000, - :status "active", - :sub-category 4400, - :geometry-type "LineString", - :props - {:surface-material {:priority 0}, - :surface-material-info {:priority 0}, - :outdoor-exercise-machines? {:priority 0}, - :free-use? {:priority 0}, - :route-width-m {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :rest-places-count {:priority 0}, - :lit-route-length-km {:priority 0}, - :route-length-km {:priority 0}}}, - 1310 - {:description - {:fi - "Koripalloon varustettu kenttä, kiinteät tai siirrettävät koritelineet. Minikenttä ja yhden korin kenttä lisätiedoissa.", - :se - "Plan utrustad för basket med fasta eller flyttbara ställningar. Miniplan och enkorgsplan i tilläggsupgifter.", - :en - "A field equipped for basketball, with fixed or movable apparatus. 'Mini-court' and 'one-basket court' included in additional information. "}, - :tags {:fi []}, - :name - {:fi "Koripallokenttä", :se "Basketplan", :en "Basketball court"}, - :type-code 1310, - :main-category 1000, - :status "active", - :sub-category 1300, - :geometry-type "Point", - :props - {:surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :height-of-basket-or-net-adjustable? {:priority 0}, - :free-use? {:priority 0}, - :field-length-m {:priority 1}, - :match-clock? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :area-m2 {:priority 1}, - :field-width-m {:priority 1}, - :lighting-info {:priority 0}, - :scoreboard? {:priority 0}, - :water-point {:priority 0}, - :ligthing? {:priority 1}, - :basketball-field-type {:priority 0}, - :school-use? {:priority 0}}}, - 202 - {:description - {:fi "Telttailualue tai muu leiriytymiseen osoitettu paikka.", - :se "Tältplats eller annat område ordnat för tältning.", - :en "Camping site for tents or other encampment. "}, - :tags - {:fi ["yöpyminen" "taukopaikka" "telttapaikka" "leirintäalue"]}, - :name - {:fi "Telttailu ja leiriytyminen", - :se "Tältning och läger", - :en "Camping"}, - :type-code 202, - :main-category 0, - :status "active", - :sub-category 2, - :geometry-type "Point", - :props - {:toilet? {:priority 0}, - :may-be-shown-in-excursion-map-fi? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :water-point {:priority 0}, - :free-use? {:priority 0}}}, - 1190 - {:description - {:fi - "Yleinen mäenlaskuun esimerkiksi pulkalla tai liukurilla tarkoitettu mäki. Kohde on ylläpidetty ja hoidettu, ja se voi muodostua luonnon mäestä tai rakennetuista kumpareista.", - :se - "En allmän backe avsedd för åkning med till exempel pulka eller stjärtlapp. Backen är underhållen och skött och kan bestå av en naturlig backe eller konstruerade högar.", - :en - "A common hill intended for sledding with, for example, a sled or a slider. The hill is maintained and taken care of, and it can consist of a natural hill or constructed mounds."}, - :tags {:fi ["pulkkailu" "pulkka" "mäenlasku"]}, - :name {:fi "Pulkkamäki", :se "Pulkabacke", :en "Sledding hill"}, - :type-code 1190, - :main-category 1000, - :status "active", - :sub-category 1100, - :geometry-type "Point", - :props - {:ligthing? {:priority 0}, - :school-use? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :lighting-info {:priority 0}}}, - 1620 - {:description - {:fi - "Ensisijaisesti golfin pelaamiseen tarkoitettu alue kesäkaudella. Reikien määrä merkitään lisätietoihin.", - :se "Officiell golfbana. Antalet hål anges i karakteristika.", - :en - "Official golf course. Number of holes included in properties."}, - :tags {:fi ["greeni" "puttialue" "range"]}, - :name {:fi "Golfkenttä (piste)", :se "Golfbana", :en "Golf course"}, - :type-code 1620, - :main-category 1000, - :status "active", - :sub-category 1600, - :geometry-type "Point", - :props - {:holes-count {:priority 1}, - :free-use? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :lighting-info {:priority 0}, - :customer-service-point? {:priority 0}, - :green? {:priority 0}, - :ligthing? {:priority 1}, - :school-use? {:priority 0}, - :range? {:priority 0}}}, - 2250 - {:description - {:fi - "Ensisijaisesti skeittausta varten varustettu halli. Hallia voidaan käyttää bmx-pyöräilyn tai muiden soveltuvien lajien harrastamiseen.", - :se - "Hall utrustad för skejtning, rullskridskoåkning, bmx-åkning osv.", - :en "An area for skateboarding, roller-blading, BMX biking, etc."}, - :tags {:fi ["ramppi"]}, - :name - {:fi "Skeittihalli", :se "Skateboardhall", :en "Indoor skatepark"}, - :type-code 2250, - :main-category 2000, - :status "active", - :sub-category 2200, - :geometry-type "Point", - :props - {:height-m {:priority 0}, - :surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :free-use? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :area-m2 {:priority 1}, - :scoreboard? {:priority 0}, - :customer-service-point? {:priority 0}, - :school-use? {:priority 0}}}, - 2530 - {:description - {:fi "Pikaluisteluun tarkoitettu halli.", - :se - "Hall avsedd för hastighetsåkning på skridsko. Storlek > 333 1/3 m.", - :en "Hall intended for speed-skating. Size > 333.3 m."}, - :tags {:fi ["jäähalli"]}, - :name - {:fi "Pikaluisteluhalli", - :se "Skridskohall", - :en "Speed-skating hall"}, - :type-code 2530, - :main-category 2000, - :status "active", - :sub-category 2500, - :geometry-type "Point", - :props - {:field-2-area-m2 {:priority 0}, - :surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :field-3-length-m {:priority 0}, - :field-2-length-m {:priority 0}, - :automated-timing? {:priority 0}, - :stand-capacity-person {:priority 0}, - :free-use? {:priority 0}, - :field-1-length-m {:priority 0}, - :finish-line-camera? {:priority 0}, - :match-clock? {:priority 0}, - :field-1-width-m {:priority 0}, - :field-3-width-m {:priority 0}, - :field-2-width-m {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :ice-rinks-count {:priority 1}, - :field-1-area-m2 {:priority 0}, - :toilet? {:priority 0}, - :area-m2 {:priority 1}, - :scoreboard? {:priority 0}, - :auxiliary-training-area? {:priority 0}, - :loudspeakers? {:priority 0}, - :field-3-area-m2 {:priority 0}, - :school-use? {:priority 0}}}, - 112 - {:description - {:fi - "Muut luonnonsuojelualueet kuin kansallispuistot. Tietoja kerätään vain sellaisilta luonnonsuojelualueilta ja luonnonpuistoilta, joiden virkistyskäyttö on mahdollista. Esim. kunta- tai yksityisomisteisille maille perustetut suojelualueet. Kaavamerkintä S, SL.", - :se - "Andra naturskyddsområden än nationalparker och naturparker. Endast de naturskyddsområden där friluftsanvändning är möjlig. T ex skyddsområden som grundats på kommunal eller privat mark. Planbeteckning S, SL.", - :en - "Nature conservation areas other than national parks and natural parks. Only nature conservation areas with opportunities for recreation. E.g. protection areas established on municipal and private land. Symbol S, SL."}, - :tags {:fi ["virkistysalue"]}, - :name - {:fi "Muu luonnonsuojelualue, jolla on virkistyspalveluita", - :se "Annat naturskyddsområde med rekreationstjänster", - :en "Other nature conservation area with recreational services"}, - :type-code 112, - :main-category 0, - :status "active", - :sub-category 1, - :geometry-type "Polygon", - :props - {:may-be-shown-in-excursion-map-fi? {:priority 0}, - :area-km2 {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, - 2130 - {:description - {:fi - "Painonnostoon tai toiminnalliseen voimaharjoitteluun varustettu kuntoilutila tai voimailusali. Esimerkiksi crossfit- ja painonnostosalit.", - :se - "Utrustad för tyngdlyftning och boxning. Storleken anges i karakteristika.", - :en - "Equipped for weightlifting and boxing. Size specified in properties."}, - :tags {:fi ["kuntosali" "kuntoilu" "painonnosto" "voimanosto"]}, - :name - {:fi "Voimailusali", - :se "Styrketräningssal", - :en "Weight training hall "}, - :type-code 2130, - :main-category 2000, - :status "active", - :sub-category 2100, - :geometry-type "Point", - :props - {:surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :free-customer-use? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :group-exercise-rooms-count {:priority 0}, - :tatamis-count {:priority 0}, - :area-m2 {:priority 1}, - :wrestling-mats-count {:priority 0}, - :boxing-rings-count {:priority 0}, - :weight-lifting-spots-count {:priority 0}, - :customer-service-point? {:priority 0}, - :school-use? {:priority 0}, - :exercise-machines-count {:priority 0}}}, - 4406 - {:description - {:fi - "Talvisin tai ympärivuotisesti käytössä oleva maastoreitti, joka soveltuu usealle kulkutavalle (esim. jalan, lumikengille, läskipyörälle). Lisätietoihin merkitään, jos reitti on ympärivuotisessa käytössä ja mahdolliset kulkutavat.", - :se - "En terrängled som används på vintern eller året runt och som är lämplig för flera färdsätt (t.ex. till fots, med snöskor, fatbike). Ytterligare information anger om leden är i bruk året runt och möjliga färdsätt.", - :en - "A terrain trail used in winter or year-round, suitable for multiple modes of travel (e.g., on foot, with snowshoes, fat bike). Additional information indicates if the trail is in year-round use and possible modes of travel."}, - :tags - {:fi ["yhteiskäyttöreitti" "talvipolku"], - :se ["gemensam led" "vinterstig"], - :en ["shared trail" "winter path"]}, - :name - {:fi "Monikäyttöreitti", - :se "Multianvändningsled", - :en "Multi-use Trail"}, - :type-code 4406, - :main-category 4000, - :status "active", - :sub-category 4400, - :geometry-type "LineString", - :props - {:surface-material {:priority 0}, - :surface-material-info {:priority 0}, - :travel-mode-info {:priority 0}, - :route-width-m {:priority 0}, - :toilet? {:priority 0}, - :rest-places-count {:priority 0}, - :lit-route-length-km {:priority 0}, - :travel-modes {:priority 0}, - :year-round-use? {:priority 0}, - :route-length-km {:priority 0}}}, - 3220 - {:description - {:fi - "Yleinen uimaranta, EU-uimaranta. Pelastusväline ja ilmoitustaulu, jäteastia ja käymälä. Veden laadun seuranta ja alueen hoito järjestetty.", - :se - "Allmän badstrand, EU badstrand. Räddningsutrustning, en anslagstavla samt ett sopkärl och en toalett finns. Kvaliteten på vattnet följs upp och området underhålls.", - :en - "Public beach, EU bathing beach. Rescue equipment, a notice board, a waste bin, and a toilet are available. The quality of the water is monitored and the area is maintained."}, - :tags {:fi ["uimapaikka"]}, - :name {:fi "Uimaranta", :se "Badstrand", :en "Public beach"}, - :type-code 3220, - :main-category 3000, - :status "active", - :sub-category 3200, - :geometry-type "Point", - :props - {:free-use? {:priority 0}, - :pier? {:priority 0}, - :may-be-shown-in-excursion-map-fi? {:priority 0}, - :beach-length-m {:priority 1}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :shower? {:priority 0}, - :changing-rooms? {:priority 0}, - :sauna? {:priority 0}, - :other-platforms? {:priority 0}, - :school-use? {:priority 0}}}, - 5330 - {:description - {:fi - "Suuri rata-autoiluun tai moottoripyöräilyyn tarkoitettu asfaltoitu moottoriurheilupaikka.", - :se "Stor motorsportplats avsedd för bankörning.", - :en "Large motor sports venue for formula racing."}, - :tags {:fi ["autourheilu"]}, - :name - {:fi "Moottorirata", :se "Motorbana", :en "Formula race track"}, - :type-code 5330, - :main-category 5000, - :status "active", - :sub-category 5300, - :geometry-type "Point", - :props - {:surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :automated-timing? {:priority 0}, - :stand-capacity-person {:priority 0}, - :free-use? {:priority 0}, - :finish-line-camera? {:priority 0}, - :track-width-m {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :lighting-info {:priority 0}, - :year-round-use? {:priority 0}, - :scoreboard? {:priority 0}, - :loudspeakers? {:priority 0}, - :ligthing? {:priority 0}, - :track-length-m {:priority 1}}}, - 4230 - {:description - {:fi "Lumilautailua varten rakennettu halli.", - :se - "Tunnel avsedd för snowboardåkning. Olika användningsmöjligheter i tilläggsinformation.", - :en - "Tunnel intended for snowboarding. Different uses specified in additional information."}, - :tags {:fi ["laskettelu"]}, - :name - {:fi "Lumilautatunneli", - :se "Snowboardtunnel", - :en "Snowboarding tunnel"}, - :type-code 4230, - :main-category 4000, - :status "active", - :sub-category 4200, - :geometry-type "Point", - :props - {:height-m {:priority 0}, - :surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :free-use? {:priority 0}, - :ski-service? {:priority 0}, - :altitude-difference {:priority 1}, - :route-width-m {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :area-m2 {:priority 0}, - :equipment-rental? {:priority 0}, - :route-length-km {:priority 1}}}, - 4320 - {:description - {:fi - "Mäkihyppyyn soveltuva mäki, vauhtimäessä on jää-, keramiikka- tai muovilatu. Mäen koko, materiaalit ja mahdollinen kesäkäyttö kuvataan lisätiedoissa.", - :se - "Is-, keramik- eller plastspår. K-punkt samt sommar- och vinteranvändning i karakteristika. Minimikrav: en liten backe med k-punkt på 75 m eller mera.", - :en - "Ice, ceramic or plastic track. Summer and winter use specified in attributes, along with K point, etc. Minimum normal hill, K point minimum 75 m."}, - :tags {:fi ["mäkihyppy" "hyppyri"]}, - :name {:fi "Hyppyrimäki", :se "Hoppbacke", :en "Ski jumping hill"}, - :type-code 4320, - :main-category 4000, - :status "active", - :sub-category 4300, - :geometry-type "Point", - :props - {:skijump-hill-type {:priority 1}, - :lifts-count {:priority 0}, - :plastic-outrun? {:priority 0}, - :free-use? {:priority 0}, - :ski-service? {:priority 0}, - :skijump-hill-material {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :hs-point {:priority 0}, - :k-point {:priority 1}, - :toilet? {:priority 0}, - :changing-rooms? {:priority 0}, - :year-round-use? {:priority 0}, - :changing-rooms-m2 {:priority 0}, - :jumps-count {:priority 0}, - :inruns-material {:priority 0}}}, - 3130 - {:description - {:fi - "Monipuolinen uimala kuntoutus-, virkistys- tai hyvinvointipalveluilla. Vesipinta-ala ja allasmäärät/tyypit ominaisuuksiin.", - :se - "Mångsidig badinrättning med rehabiliterings- och rekreationstjänster. Vattenareal samt antal och typ av bassänger i karakteristika.", - :en - "Versatile spa with rehabilitation or wellness services. Water volume and number/types of pools specified in properties."}, - :tags {:fi []}, - :name {:fi "Kylpylä", :se "Badinrättning", :en "Spa"}, - :type-code 3130, - :main-category 3000, - :status "active", - :sub-category 3100, - :geometry-type "Point", - :props - {:free-use? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :area-m2 {:priority 1}, - :swimming-pool-count {:priority 1}, - :pool-water-area-m2 {:priority 1}, - :accessibility-info {:priority 0}, - :school-use? {:priority 0}}}, - 3110 - {:description - {:fi - "Halli, jossa on yksi tai useampia uima-altaita. Altaiden määrä ja vesipinta-ala kysytään ominaisuustiedoissa.", - :se - "Hall med en eller flera simbassänger. Antalet bassänger och vattenareal anges i karakteristika.", - :en - "Hall with one or several swimming pools. Number of pools and water surface area is requested in properties."}, - :tags {:fi []}, - :name - {:fi "Uimahalli", :se "Simhall", :en "Public indoor swimming pool"}, - :type-code 3110, - :main-category 3000, - :status "active", - :sub-category 3100, - :geometry-type "Point", - :props - {:automated-timing? {:priority 0}, - :stand-capacity-person {:priority 0}, - :free-use? {:priority 0}, - :finish-line-camera? {:priority 0}, - :match-clock? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :area-m2 {:priority 1}, - :swimming-pool-count {:priority 1}, - :pool-water-area-m2 {:priority 1}, - :scoreboard? {:priority 0}, - :loudspeakers? {:priority 0}, - :accessibility-info {:priority 0}, - :school-use? {:priority 0}}}, - 203 - {:description - {:fi - "Kohteessa on veneilyyn liittyviä palveluita kuten säilytysmahdollisuus, vesillelaskupaikka tai veneen kiinnitysmahdollisuus. Kohteelle määritetään venesatamaluokka, jonka palveluvarustus kuvataan lisätiedoissa. Jos kyse on melontalaiturista, se kirjataan kyseisen laituriluokan alle. Kohde tulee merkitä tärkeimmän laiturin läheisyyteen, jos sellainen kohteessa on.", - :se "Tjänster för båtfarare. Precisering i karakteristika.", - :en "Facilities related to boating. Specififed in 'attributes'."}, - :tags {:fi ["satama" "laituri"]}, - :name - {:fi "Veneilyn palvelupaikka", - :se "Serviceplats för båtfarare", - :en "Boating services"}, - :type-code 203, - :main-category 0, - :status "active", - :sub-category 2, - :geometry-type "Point", - :props - {:free-use? {:priority 0}, - :pier? {:priority 0}, - :may-be-shown-in-excursion-map-fi? {:priority 0}, - :boat-launching-spot? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :boating-service-class {:priority 1}, - :customer-service-point? {:priority 0}, - :water-point {:priority 0}, - :accessibility-info {:priority 0}}}, - 4620 - {:description - {:fi - "Vähintään kansallisen tason kilpailujen järjestämiseen soveltuva ampumahiihtokeskus. Ampumahiihtokeskuksessa useita ampumapaikkoja ja latuverkosto.", - :se "Tillräckligt stort för åtminstone nationella tävlingar.", - :en "For minimum national level competitions."}, - :tags {:fi ["ampumapaikka"]}, - :name - {:fi "Ampumahiihtokeskus", - :se "Skidskyttecentrum", - :en "Biathlon centre"}, - :type-code 4620, - :main-category 4000, - :status "active", - :sub-category 4600, - :geometry-type "Point", - :props - {:stand-capacity-person {:priority 0}, - :free-use? {:priority 0}, - :ski-service? {:priority 0}, - :finish-line-camera? {:priority 0}, - :ski-track-traditional? {:priority 0}, - :route-width-m {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :shower? {:priority 0}, - :rest-places-count {:priority 0}, - :changing-rooms? {:priority 0}, - :shooting-positions-count {:priority 1}, - :lit-route-length-km {:priority 0}, - :year-round-use? {:priority 0}, - :scoreboard? {:priority 0}, - :sauna? {:priority 0}, - :loudspeakers? {:priority 0}, - :accessibility-info {:priority 0}, - :ski-track-freestyle? {:priority 0}, - :route-length-km {:priority 0}}}, - 5360 - {:description - {:fi - "Pääasiallisesti jokamiesajoa, rallicrossia tai moottoripyöräilyä varten.", - :se "Huvudsakligen för allemanskörning och/eller rallycross.", - :en "Mainly for everyman racing and/or rallycross."}, - :tags {:fi []}, - :name - {:fi "Jokamies- ja rallicross-rata", - :se "Allemans- och rallycrossbana", - :en "Everyman racing and rallycross track "}, - :type-code 5360, - :main-category 5000, - :status "active", - :sub-category 5300, - :geometry-type "Point", - :props - {:surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :automated-timing? {:priority 0}, - :stand-capacity-person {:priority 0}, - :free-use? {:priority 0}, - :finish-line-camera? {:priority 0}, - :track-width-m {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :area-m2 {:priority 0}, - :lighting-info {:priority 0}, - :year-round-use? {:priority 0}, - :scoreboard? {:priority 0}, - :loudspeakers? {:priority 0}, - :ligthing? {:priority 0}, - :covered-stand-person-count {:priority 0}, - :track-length-m {:priority 1}}}, - 2290 - {:description - {:fi "Petanque-peliin tarkoitettu halli.", - :se - "Hall avsedd för petanque. Storlek, antalet planer och utrustning i karakteristika.", - :en "Hall intended for petanque."}, - :tags {:fi ["petankki"]}, - :name - {:fi "Petanque-halli", :se "Petanquehall", :en "Petanque hall"}, - :type-code 2290, - :main-category 2000, - :status "active", - :sub-category 2200, - :geometry-type "Point", - :props - {:height-m {:priority 0}, - :surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :free-use? {:priority 0}, - :fields-count {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :area-m2 {:priority 1}, - :scoreboard? {:priority 0}, - :customer-service-point? {:priority 0}, - :school-use? {:priority 0}}}, - 2260 - {:description - {:fi - "Ensisijaisesti sulkapallon pelaamiseen tarkoitettu halli. Vapaa korkeus ilmoitetaan lisätiedoissa.", - :se "Hall i första hand avsedd för badminton.", - :en "Hall intended primarily for badminton."}, - :tags {:fi []}, - :name - {:fi "Sulkapallohalli", :se "Badmintonhall", :en "Badminton hall"}, - :type-code 2260, - :main-category 2000, - :status "active", - :sub-category 2200, - :geometry-type "Point", - :props - {:height-m {:priority 1}, - :surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :stand-capacity-person {:priority 0}, - :free-use? {:priority 0}, - :tennis-courts-count {:priority 0}, - :field-length-m {:priority 0}, - :badminton-courts-count {:priority 1}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :padel-courts-count {:priority 0}, - :toilet? {:priority 0}, - :area-m2 {:priority 1}, - :field-width-m {:priority 0}, - :scoreboard? {:priority 0}, - :floorball-fields-count {:priority 0}, - :squash-courts-count {:priority 0}, - :customer-service-point? {:priority 0}, - :volleyball-fields-count {:priority 0}, - :school-use? {:priority 0}}}, - 1160 - {:description - {:fi - "Pyöräilyä ja temppuilua varten varattu alue, esim. bmx-, pump track- tai dirt-pyöräilyalue.", - :se "Ett område avsett för cykling och trick, till exempel BMX-, pump track- eller dirtcyklingsområde.", - :en "An area designated for cycling and stunts, such as a BMX, pump track, or dirt biking area."}, - :tags {:fi ["pumptrack" "bmx" "pump" "track"]}, - :name - {:fi "Pyöräilyalue", :se "Cykelåkningsområde", :en "Cycling area"}, - :type-code 1160, - :main-category 1000, - :status "active", - :sub-category 1100, - :geometry-type "Point", - :props - {:surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :stand-capacity-person {:priority 0}, - :free-use? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :area-m2 {:priority 1}, - :lighting-info {:priority 0}, - :customer-service-point? {:priority 0}, - :ligthing? {:priority 1}, - :accessibility-info {:priority 0}, - :covered-stand-person-count {:priority 0}, - :school-use? {:priority 0}}}, - 1210 - {:description - {:fi - "Yleisurheilun harjoitusalueeksi merkitään kohde, jossa on yleisurheilun harjoitteluun soveltuvia suorituspaikkoja, esim. kenttä, ratoja tai eri lajien suorituspaikkoja, mutta ei virallisen yleisurheilukentän kaikkia suorituspaikkoja. Lyhytrataiset (juoksurata alle 400 m) yleisurheilukentät tallennetaan yleisurheilun harjoitusalueeksi.", - :se - "Ett område för friidrottsträning markeras där det finns anläggningar som är lämpliga för friidrottsträning, till exempel en plan, banor eller platser för olika grenar, men inte alla anläggningar för en officiell friidrottsarena. Kortbaniga friidrottsarenor (löparbana under 400 m) registreras som friidrottsträningsområden.", - :en - "An athletics training area is designated for locations with facilities suitable for athletics training, such as a field, tracks, or various event areas, but not all facilities of an official athletics stadium. Short track athletics fields (running track under 400 m) are recorded as athletics training areas."}, - :tags - {:fi - ["keihäs" - "keihäänheitto" - "moukari" - "pituushyppy" - "juoksurata" - "kolmiloikka" - "seiväs" - "kuula" - "urheilukenttä" - "yleisurheilukenttä"]}, - :name - {:fi "Yleisurheilun harjoitusalue", - :se "Träningsområde för friidrott", - :en "Athletics training area"}, - :type-code 1210, - :main-category 1000, - :status "active", - :sub-category 1200, - :geometry-type "Point", - :props - {:heating? {:priority 0}, - :surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :free-use? {:priority 0}, - :sprint-lanes-count {:priority 0}, - :javelin-throw-places-count {:priority 0}, - :field-length-m {:priority 0}, - :circular-lanes-count {:priority 0}, - :sprint-track-length-m {:priority 0}, - :inner-lane-length-m {:priority 0}, - :discus-throw-places {:priority 0}, - :hammer-throw-places-count {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :polevault-places-count {:priority 0}, - :toilet? {:priority 0}, - :running-track-surface-material {:priority 0}, - :area-m2 {:priority 1}, - :field-width-m {:priority 0}, - :lighting-info {:priority 0}, - :shotput-count {:priority 0}, - :longjump-places-count {:priority 0}, - :ligthing? {:priority 1}, - :school-use? {:priority 0}, - :highjump-places-count {:priority 0}, - :training-spot-surface-material {:priority 0}}}, - 5140 - {:description - {:fi - "Rakennettu pysyvästi vesihiihdolle. Vesihiihtoalueella on laituri.", - :se "Byggt för vattenskidåkning, permanent. Minimikrav: brygga.", - :en - "Permanent construction for water skiing. Minimum equipment pier."}, - :tags {:fi []}, - :name - {:fi "Vesihiihtoalue", - :se "Område för vattenskidåkning", - :en "Water ski area"}, - :type-code 5140, - :main-category 5000, - :status "active", - :sub-category 5100, - :geometry-type "Point", - :props - {:pier? {:priority 0}, - :area-km2 {:priority 0}, - :free-use? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, - 4310 - {:description - {:fi - "Mäkihypyn harjoitteluun rakennettu mäki. K-piste ominaisuustietoihin, materiaalit, kesä- ja talvikäyttö ominaisuuksiin. ", - :se - "K-punkt, material samt sommar- och vinteranvändning i karakteristika.", - :en - "K point in properties; materials, summer and winter use specified in attributes. "}, - :tags {:fi ["mäkihyppy" "hyppyri" "hyppyrimäki"]}, - :name - {:fi "Harjoitushyppyrimäki", - :se "Träningshoppbacke", - :en "Ski jumping hill for training"}, - :type-code 4310, - :main-category 4000, - :status "deprecated", - :sub-category 4300, - :geometry-type "Point", - :props - {:skijump-hill-type {:priority 1}, - :lifts-count {:priority 0}, - :plastic-outrun? {:priority 0}, - :free-use? {:priority 0}, - :ski-service? {:priority 0}, - :skijump-hill-material {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :k-point {:priority 1}, - :toilet? {:priority 0}, - :year-round-use? {:priority 0}, - :p-point {:priority 0}, - :inruns-material {:priority 0}, - :school-use? {:priority 0}}}, - 207 - {:description - {:fi - "Opastuspiste on ulkoilureitin, virkistysalueen tai muun liikuntapaikan yhteydessä oleva lisätieto. Paikassa voi olla esimerkiksi opastustaulu ja kartta tai laajempi palvelupiste. Opastuspiste-merkintää voidaan käyttää myös ilmoittamaan reitin lähtöpisteen.", - :se - "En informationspunkt är en extra information vid en friluftsled, ett rekreationsområde eller en annan idrottsplats. På platsen kan det till exempel finnas en informationstavla och karta eller en mer omfattande servicestation. Informationspunkt-markeringen kan också användas för att ange startpunkten för en rutt.", - :en - "An information point is additional information associated with an outdoor trail, recreational area, or other sports facility. The location may include, for example, an information board and map or a more extensive service point. The information point marking can also be used to indicate the starting point of a route."}, - :tags {:fi ["info" "opastaulu" "infopiste"]}, - :name {:fi "Opastuspiste", :se "Informationspunkt", :en "Info"}, - :type-code 207, - :main-category 0, - :status "deprecated", - :sub-category 2, - :geometry-type "Point", - :props - {:parking-place? {:priority 0}, - :may-be-shown-in-excursion-map-fi? {:priority 0}, - :toilet? {:priority 0}, - :school-use? {:priority 0}, - :free-use? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, - 1130 - {:description - {:fi - "Ulkokuntoilupaikka on esimerkiksi kuntoilulaitteita, voimailulaitteita tai kuntoportaat sisältävä liikuntapaikka. Kohde voi olla osa liikuntapuistoa, liikuntareitin varrella oleva kuntoilupaikka tai ns. ulkokuntosali.", - :se - "En utomhusträningsplats är en idrottsplats som innehåller till exempel träningsutrustning, styrketräningsutrustning eller träningsstegar. Platsen kan vara en del av en idrottspark, en träningsplats längs en motionsslinga eller en så kallad utomhusgym.", - :en - "An outdoor fitness area is a sports facility that includes, for example, exercise equipment, strength training equipment, or fitness stairs. The location can be part of a sports park, a fitness spot along a trail, or a so-called outdoor gym"}, - :tags - {:fi - ["kuntoilulaite" - "ulkokuntoilupiste" - "kuntoilupiste" - "kuntoilupaikka" - "kuntoportaat"]}, - :name - {:fi "Ulkokuntoilupaikka", - :se "Konditionspark för utomhusaktiviteter", - :en "Street workout park"}, - :type-code 1130, - :main-category 1000, - :status "active", - :sub-category 1100, - :geometry-type "Point", - :props - {:surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :free-use? {:priority 0}, - :fitness-stairs-length-m {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :area-m2 {:priority 1}, - :lighting-info {:priority 0}, - :ligthing? {:priority 1}, - :playground? {:priority 0}, - :school-use? {:priority 0}, - :exercise-machines-count {:priority 1}}}, - 5120 - {:description - {:fi "Pysyvästi purjehdusta varten varustettu alue.", - :se "Byggt för segling, permanent.", - :en "Permanent construction for sailing."}, - :tags {:fi []}, - :name - {:fi "Purjehdusalue", :se "Seglingsområde", :en "Sailing area"}, - :type-code 5120, - :main-category 5000, - :status "active", - :sub-category 5100, - :geometry-type "Point", - :props - {:area-km2 {:priority 0}, - :pier? {:priority 0}, - :boat-places-count {:priority 0}, - :free-use? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, - 4110 - {:description - {:fi - "Laskettelun suorituspaikka on lasketteluun tai lumilautailuun tarkoitettu liikuntapaikka, esim. laskettelukeskus. Laskettelun suorituspaikassa voi olla laskettelurinteitä, parkkeja tai muita rinnerakenteita ja hiihtohissejä.", - :se - "Slalombacke, rodelbana, pipe, puckelpist, freestyle ramp, trickbana.", - :en "Ski slopes, half pipes and other slope structures."}, - :tags {:fi ["rinne" "laskettelu" "laskettelurinne"]}, - :name - {:fi "Laskettelun suorituspaikka", - :se "Slalombackar och alpina skidcentra", - :en "Ski slopes and downhill ski resorts"}, - :type-code 4110, - :main-category 4000, - :status "active", - :sub-category 4100, - :geometry-type "Point", - :props - {:lifts-count {:priority 1}, - :freestyle-slope? {:priority 0}, - :free-use? {:priority 0}, - :ski-service? {:priority 0}, - :sledding-hill? {:priority 0}, - :longest-slope-m {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :snowpark-or-street? {:priority 0}, - :max-vertical-difference {:priority 1}, - :toilet? {:priority 0}, - :halfpipe-count {:priority 0}, - :equipment-rental? {:priority 0}, - :slopes-count {:priority 1}, - :shortest-slope-m {:priority 0}, - :jumps-count {:priority 0}, - :customer-service-point? {:priority 0}, - :lit-slopes-count {:priority 1}, - :accessibility-info {:priority 0}}}, - 4452 - {:description - {:fi - "Merkitty vesireitti, ei kuitenkaan veneväylä. Vesireitti on reittiehdotus-tyyppinen suositeltu vesiretkeilyyn soveltuva reitti. Esim. kirkkovenesoutureitti.", - :se - "Märkt vattenled, endast ruttförslag t ex för kyrkbåtsrodd, inte som farled för småbåtar.", - :en - "Marked water route, not a navigation channel. Route suggestions included. E.g., route for \"church rowing boats\"."}, - :tags {:fi ["kanootti" "kajakki" "melonta"]}, - :name - {:fi "Vesiretkeilyreitti", - :se "Utflyktsled i vattendrag", - :en "Water route"}, - :type-code 4452, - :main-category 4000, - :status "active", - :sub-category 4400, - :geometry-type "LineString", - :props - {:may-be-shown-in-excursion-map-fi? {:priority 0}, - :route-length-km {:priority 1}, - :rest-places-count {:priority 0}, - :school-use? {:priority 0}, - :free-use? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :jumps-count {:priority 0}}}, - 5370 - {:description - {:fi "Pääasiallisesti jääspeedwayta varten.", - :se "Huvudsakligen för isracing.", - :en "Speedway mainly for ice racing."}, - :tags {:fi ["speedway"]}, - :name - {:fi "Speedway-/jääspeedwayrata", - :se "Isracingbana", - :en "Ice speedway track"}, - :type-code 5370, - :main-category 5000, - :status "active", - :sub-category 5300, - :geometry-type "Point", - :props - {:surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :automated-timing? {:priority 0}, - :stand-capacity-person {:priority 0}, - :free-use? {:priority 0}, - :finish-line-camera? {:priority 0}, - :track-width-m {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :lighting-info {:priority 0}, - :year-round-use? {:priority 0}, - :scoreboard? {:priority 0}, - :loudspeakers? {:priority 0}, - :ligthing? {:priority 0}, - :track-length-m {:priority 1}}}, - 2240 - {:description - {:fi - "Ensisijaisesti salibandyyn tarkoitettu halli. Kenttien määrä ja pintamateriaali kirjataan lisätietoihin.", - :se - "Hall i första hand avsedd för innebandy. Antalet planer samt ytmaterial i karakteristika.", - :en - "Hall primarily intended for floorball. Number of courts and surface material specified in properties."}, - :tags {:fi ["sähly"]}, - :name - {:fi "Salibandyhalli", :se "Innebandyhall", :en "Floorball hall"}, - :type-code 2240, - :main-category 2000, - :status "active", - :sub-category 2200, - :geometry-type "Point", - :props - {:height-m {:priority 0, :derived? true}, - :surface-material {:priority 1, :derived? true}, - :surface-material-info {:priority 0, :derived? true}, - :stand-capacity-person {:priority 0, :derived? true}, - :free-use? {:priority 0}, - :field-length-m {:priority 1, :derived? true}, - :badminton-courts-count {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :area-m2 {:priority 1, :derived? true}, - :field-width-m {:priority 1, :derived? true}, - :scoreboard? {:priority 0}, - :floorball-fields-count {:priority 1, :derived? true}, - :auxiliary-training-area? {:priority 0}, - :customer-service-point? {:priority 0}, - :school-use? {:priority 0}}}, - 2510 - {:description - {:fi - "Harjoitusjäähalli on pääasiassa jääurheilun harjoitteluun ja jääliikuntaan käytettävä jäähalli.", - :se - "Antalet planer och omklädningshytter, uppvärmning osv anges i karakteristika.", - :en - "Number of fields, heating, changing rooms, etc., specified in properties."}, - :tags {:fi ["jäähalli"]}, - :name - {:fi "Harjoitusjäähalli", - :se "Övningsishall", - :en "Training ice arena"}, - :type-code 2510, - :keywords {:fi ["Jäähalli"], :en [], :se []}, - :main-category 2000, - :status "active", - :sub-category 2500, - :geometry-type "Point", - :props - {:surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :automated-timing? {:priority 0}, - :stand-capacity-person {:priority 0}, - :free-use? {:priority 0}, - :finish-line-camera? {:priority 0}, - :match-clock? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :ice-rinks-count {:priority 1}, - :field-2-flexible-rink? {:priority 0}, - :toilet? {:priority 0}, - :area-m2 {:priority 1}, - :curling-lanes-count {:priority 0}, - :scoreboard? {:priority 0}, - :auxiliary-training-area? {:priority 0}, - :ringette-boundary-markings? {:priority 0}, - :field-1-flexible-rink? {:priority 0}, - :loudspeakers? {:priority 0}, - :school-use? {:priority 0}, - :field-3-flexible-rink? {:priority 0}}}, - 1640 - {:description - {:fi "Ratagolfliiton hyväksymät ratagolf-/minigolfradat.", - :se "Bangolf / minigolf, enligt Finlands Bangolfförbundets regler.", - :en - "A course built for miniature golf, accepted by the Ratagolf Union."}, - :tags {:fi ["minigolf"]}, - :name {:fi "Ratagolf", :se "Bangolf", :en "Minigolf course"}, - :type-code 1640, - :main-category 1000, - :status "active", - :sub-category 1600, - :geometry-type "Point", - :props - {:holes-count {:priority 1}, - :free-use? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :lighting-info {:priority 0}, - :customer-service-point? {:priority 0}, - :green? {:priority 0}, - :ligthing? {:priority 1}, - :school-use? {:priority 0}, - :range? {:priority 0}}}, - 1380 - {:description - {:fi "Rullakiekon pelaamiseen varustettu kenttä.", - :se "Plan utrustad för inlinehockey.", - :en "Field equipped for roller hockey."}, - :tags {:fi ["rullakiekko"]}, - :name - {:fi "Rullakiekkokenttä", - :se "Inlinehockeyplan", - :en "Roller hockey field"}, - :type-code 1380, - :main-category 1000, - :status "active", - :sub-category 1300, - :geometry-type "Point", - :props - {:surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :free-use? {:priority 0}, - :field-length-m {:priority 1}, - :match-clock? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :area-m2 {:priority 1}, - :field-width-m {:priority 1}, - :lighting-info {:priority 0}, - :water-point {:priority 0}, - :ligthing? {:priority 1}, - :school-use? {:priority 0}}}, - 4451 - {:description - {:fi - "Erityisesti melontaan tarkoitettu vesistöreitti. Reitistä on laadittu reittikuvaus ja maastossa löytyy opasteita (esim. rantautumispaikoista). Reittiehdotus-tyyppinen, ei navigointiin.", - :se - "Särskilt för paddling, märkt med ruttförslag, ej för navigering.", - :en - "Marked route particularly for canoeing. Route suggestions are not intended for navigation."}, - :tags {:fi ["kanootti" "kajakki"]}, - :name {:fi "Melontareitti", :se "Paddlingsled", :en "Canoe route"}, - :type-code 4451, - :main-category 4000, - :status "active", - :sub-category 4400, - :geometry-type "LineString", - :props - {:route-length-km {:priority 1}, - :rest-places-count {:priority 0}, - :may-be-shown-in-excursion-map-fi? {:priority 0}, - :free-use? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, - 4403 - {:description - {:fi - "Jalkaisin tapahtuvaan ulkoiluun tarkoitettu reitti. Suhteellisen leveä ja helppokulkuinen reitti, yleensä valaistu ja pinnoitettu.", - :se - "Promenadled. Relativt bred och lättilgänglig, eventuellt belyst och asfalterad.", - :en - "Route intended for outdoor pedestrian activities. Relatively broad and passable. Potentially lit and surfaced."}, - :tags {:fi ["ulkoilu" "kävely" "ulkoilureitti" "kävelyreitti"]}, - :name - {:fi "Kävelyreitti/ulkoilureitti", - :se "Promenadled/friluftsled", - :en "Walking route/outdoor route"}, - :type-code 4403, - :main-category 4000, - :status "active", - :sub-category 4400, - :geometry-type "LineString", - :props - {:surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :free-use? {:priority 0}, - :may-be-shown-in-excursion-map-fi? {:priority 0}, - :outdoor-exercise-machines? {:priority 0}, - :route-width-m {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :rest-places-count {:priority 0}, - :lit-route-length-km {:priority 1}, - :accessibility-info {:priority 0}, - :route-length-km {:priority 1}}}, - 5150 - {:description - {:fi - "Melontaan tarkoitettu palvelupaikka, jossa voi olla esim. vuokrauspalveluita. Melontakeskuksesta voi lähteä melontareitti tai sen yhteydessä voi olla melontaratoja.", - :se "En paddlingsanläggning med uthyrningstjänster. Från paddlingscentret kan det finnas paddelleder eller paddelbanor i närheten.", - :en "A canoeing facility with rental services. From the canoeing center, there may be canoeing routes or paddling tracks nearby."}, - :tags {:fi ["melonta" "kajakki" "kanootti" "melontakeskus"]}, - :name - {:fi "Melontakeskus", - :se "Centrum för paddling", - :en "Canoeing centre"}, - :type-code 5150, - :main-category 5000, - :status "active", - :sub-category 5100, - :geometry-type "Point", - :props - {:free-use? {:priority 0}, - :pier? {:priority 0}, - :canoeing-club? {:priority 0}, - :altitude-difference {:priority 0}, - :rapid-canoeing-centre? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :equipment-rental? {:priority 0}, - :activity-service-company? {:priority 0}}}, - 1630 - {:description - {:fi - "Golfia varten varustettu sisäharjoittelutila. Voi olla useita erilaisia suorituspaikkoja.", - :se "Övningsutrymme byggt för golf. Storlek i karakteristika.", - :en "Training space built for golf. Size specified in properties."}, - :tags {:fi ["greeni" "puttialue"]}, - :name - {:fi "Golfin harjoitushalli", - :se "Övningshall för golf", - :en "Golf training hall"}, - :type-code 1630, - :main-category 2000, - :status "active", - :sub-category 2200, - :geometry-type "Point", - :props - {:height-m {:priority 1}, - :holes-count {:priority 0}, - :free-use? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :area-m2 {:priority 1}, - :customer-service-point? {:priority 0}, - :green? {:priority 0}, - :school-use? {:priority 0}, - :range? {:priority 0}}}, - 2295 - {:description - {:fi - "Yksi tai useampi padelkenttä sisällä. Pintamateriaali tekonurmi (hiekkatekonurmi). Lajivaatimusten mukaiset seinät. Vapaa korkeus ilmoitetaan lisätiedoissa.", - :se - "En eller flera padelbanor inomhus. Ytmaterial konstgräs (med sand), 20 x 10 m. Väggar måste uppfylla spelets krav. Höjd anges i karakteristika.", - :en - "One or more indoor padel courts. The court has an artificial grass surface and its measurements are 20 x 10 metres. The walls must meet the requirements for the sport. Height given in 'properties'."}, - :tags {:fi ["padel" "padel-halli"]}, - :name {:fi "Padelhalli", :se "Padelhall", :en "Padel hall"}, - :type-code 2295, - :main-category 2000, - :status "active", - :sub-category 2200, - :geometry-type "Point", - :props - {:height-m {:priority 1}, - :surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :stand-capacity-person {:priority 0}, - :free-use? {:priority 0}, - :field-length-m {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :padel-courts-count {:priority 1}, - :toilet? {:priority 0}, - :area-m2 {:priority 1}, - :field-width-m {:priority 0}, - :scoreboard? {:priority 0}, - :school-use? {:priority 0}}}, - 2370 - {:description - {:fi "Kiipeilyyn varustettu sisätila. Myös boulderointipaikat.", - :se - "Inomhusutrymme utrustat för klättring, även platser för bouldering.", - :en "Indoor space equipped for climbing. Also bouldering venues."}, - :tags {:fi ["kiipeilyseinä"]}, - :name - {:fi "Sisäkiipeilyseinä", - :se "Klättervägg inomhus", - :en "Indoor climbing wall"}, - :type-code 2370, - :main-category 2000, - :status "active", - :sub-category 2300, - :geometry-type "Point", - :props - {:surface-material {:priority 0}, - :surface-material-info {:priority 0}, - :climbing-routes-count {:priority 0}, - :climbing-wall-height-m {:priority 1}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :area-m2 {:priority 1}, - :climbing-wall-width-m {:priority 1}, - :school-use? {:priority 0}}}, - 1340 - {:description - {:fi - "Palloiluun tarkoitettu kenttä, jonka pintamateriaali on esim. hiekka, nurmi tai hiekkatekonurmi. Kentällä on mahdollista pelata yhtä tai useampaa palloilulajia. Kentän koko merkitään lisätietoihin. Kevyt poistettava kate on mahdollinen.", - :se - "Plan avsedd för bollspel. Sand, konstgräs med sand el dyl, storleken varierar. En eller flera bollspelsgrenar möjliga.", - :en - "A field intended for ball games. Sand, grass, artificial turf, etc., size varies. One or more types of ball games possible."}, - :tags {:fi []}, - :name {:fi "Pallokenttä", :se "Bollplan", :en "Ball field"}, - :type-code 1340, - :main-category 1000, - :status "active", - :sub-category 1300, - :geometry-type "Point", - :props - {:heating? {:priority 0}, - :surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :stand-capacity-person {:priority 0}, - :free-use? {:priority 0}, - :field-length-m {:priority 1}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :changing-rooms? {:priority 0}, - :area-m2 {:priority 1}, - :field-width-m {:priority 1}, - :lighting-info {:priority 0}, - :year-round-use? {:priority 0}, - :customer-service-point? {:priority 0}, - :water-point {:priority 0}, - :ligthing? {:priority 1}, - :school-use? {:priority 0}, - :light-roof? {:priority 0}}}, - 1610 - {:description - {:fi - "Golfin harjoittelua varten varustettu alue. Harjoitusalue voi sisältää useampia suorituspaikkoja, kuten rangen ja puttausviheriön. Harjoitusalue sijaitsee ulkona.", - :se - "Ett område utrustat för golfträning. Träningsområdet kan innehålla flera träningsplatser, såsom en range och en puttningsgreen. Träningsområdet ligger utomhus.", - :en "An area equipped for golf practice. The practice area may include multiple facilities, such as a driving range and a putting green. The practice area is located outdoors."}, - :tags {:fi ["greeni" "puttialue" "range"]}, - :name - {:fi "Golfin harjoitusalue", - :se "Träningsområde för golf", - :en "Golf training area"}, - :type-code 1610, - :main-category 1000, - :status "active", - :sub-category 1600, - :geometry-type "Point", - :props - {:holes-count {:priority 1}, - :free-use? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :lighting-info {:priority 0}, - :customer-service-point? {:priority 0}, - :green? {:priority 0}, - :ligthing? {:priority 1}, - :school-use? {:priority 0}, - :range? {:priority 0}}}, - 4421 - {:description - {:fi - "Reittitoimituksella hyväksytty, virallinen moottorikelkkailureitti.", - :se "En officiell rutt som godkänts genom en ruttexpedition.", - :en "Officially approved route (in compliance with Act 670/1991)."}, - :tags {:fi []}, - :name - {:fi "Moottorikelkkareitti", - :se "Snöskoterled", - :en "Official snowmobile route"}, - :type-code 4421, - :main-category 4000, - :status "active", - :sub-category 4400, - :geometry-type "LineString", - :props - {:rest-places-count {:priority 0}, - :route-width-m {:priority 0}, - :may-be-shown-in-excursion-map-fi? {:priority 0}, - :route-length-km {:priority 1}, - :free-use? {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, - 2220 - {:description - {:fi - "Monitoimihalli on suuri liikuntatila, joka on merkittävä monien lajien kilpailu- ja tapahtumapaikka. Liikuntapinta-ala on suurempi kuin 5 000 m2.", - :se "Större tävlingsplats för ett flertal grenar, >= 5 000 m2.", - :en "Significant competition venue for various sports, >=5000 m2."}, - :tags {:fi ["liikuntahalli" "urheilutalo" "urheiluhalli"]}, - :name - {:fi "Monitoimihalli/areena", - :se "Allaktivitetshall/multiarena", - :en "Multipurpose hall/arena"}, - :type-code 2220, - :main-category 2000, - :status "active", - :sub-category 2200, - :geometry-type "Point", - :props - {:height-m {:priority 1}, - :surface-material {:priority 1}, - :basketball-fields-count {:priority 0}, - :surface-material-info {:priority 0}, - :automated-timing? {:priority 0}, - :stand-capacity-person {:priority 0}, - :free-use? {:priority 0}, - :sprint-lanes-count {:priority 0}, - :javelin-throw-places-count {:priority 0}, - :tennis-courts-count {:priority 0}, - :field-length-m {:priority 1}, - :circular-lanes-count {:priority 0}, - :match-clock? {:priority 0}, - :sprint-track-length-m {:priority 0}, - :inner-lane-length-m {:priority 0}, - :discus-throw-places {:priority 0}, - :badminton-courts-count {:priority 0}, - :hammer-throw-places-count {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :padel-courts-count {:priority 0}, - :polevault-places-count {:priority 0}, - :space-divisible {:priority 0}, - :toilet? {:priority 0}, - :gymnastics-space? {:priority 0}, - :running-track-surface-material {:priority 0}, - :area-m2 {:priority 1}, - :field-width-m {:priority 1}, - :scoreboard? {:priority 0}, - :shotput-count {:priority 0}, - :longjump-places-count {:priority 0}, - :football-fields-count {:priority 0}, - :floorball-fields-count {:priority 0}, - :auxiliary-training-area? {:priority 0}, - :squash-courts-count {:priority 0}, - :loudspeakers? {:priority 0}, - :customer-service-point? {:priority 0}, - :accessibility-info {:priority 0}, - :handball-fields-count {:priority 0}, - :volleyball-fields-count {:priority 0}, - :climbing-wall? {:priority 0}, - :school-use? {:priority 0}, - :highjump-places-count {:priority 0}}}, - 1320 - {:description - {:fi - "Lentopalloon varustettu kenttä, jossa on kiinteät lentopallotolpat.", - :se "Plan utrustad för volleyboll. Fasta volleybollställningar.", - :en "A field equipped for volleyball. Fixed volleyball apparatus."}, - :tags {:fi []}, - :name - {:fi "Lentopallokenttä", - :se "Volleybollplan", - :en "Volleyball court"}, - :type-code 1320, - :main-category 1000, - :status "active", - :sub-category 1300, - :geometry-type "Point", - :props - {:surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :height-of-basket-or-net-adjustable? {:priority 0}, - :free-use? {:priority 0}, - :field-length-m {:priority 1}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :area-m2 {:priority 1}, - :field-width-m {:priority 1}, - :lighting-info {:priority 0}, - :water-point {:priority 0}, - :ligthing? {:priority 1}, - :school-use? {:priority 0}}}, - 4402 - {:description - {:fi - "Talvikaudella hiihtoa varten ylläpidetty reitti. Hiihtotyylit kerrotaan ominaisuustiedoissa.", - :se - "Led avsedd för skidåkning. Ej sommaranvändning och -underhåll. Åkstilar anges i karakteristika.", - :en - "Route intended for skiing. Not in use and unmaintained in summer. Ski styles provided in properties."}, - :tags {:fi ["hiihto" "hiihtolatu"]}, - :name {:fi "Hiihtolatu", :se "Skidspår", :en "Ski track"}, - :type-code 4402, - :main-category 4000, - :status "active", - :sub-category 4400, - :geometry-type "LineString", - :props - {:surface-material {:priority 1}, - :surface-material-info {:priority 0}, - :free-use? {:priority 0}, - :may-be-shown-in-excursion-map-fi? {:priority 0}, - :outdoor-exercise-machines? {:priority 0}, - :ski-track-traditional? {:priority 0}, - :route-width-m {:priority 0}, - :may-be-shown-in-harrastuspassi-fi? {:priority 0}, - :toilet? {:priority 0}, - :rest-places-count {:priority 0}, - :shooting-positions-count {:priority 0}, - :lit-route-length-km {:priority 1}, - :ski-track-freestyle? {:priority 0}, - :school-use? {:priority 0}, - :route-length-km {:priority 1}}}}) + {:description + {:fi + "Luisteluun, jääkiekkoon, kaukalopalloon, curlingiin tai muuhun jääurheiluun tarkoitettu kaukalo. Käytössä talvikaudella.", + :se + "Rink avsedd för skridskoåkning, ishockey, rinkbandy osv. Används under vintersäsongen.", + :en + "Rink intended for ice-skating, ice hockey, rink bandy, etc."}, + :tags {:fi ["jääkiekkokaukalo"]}, + :name {:fi "Kaukalo", :se "Rink", :en "Rink"}, + :type-code 1530, + :main-category 1000, + :status "active", + :sub-category 1500, + :geometry-type "Point", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :stand-capacity-person {:priority 70}, + :free-use? {:priority 40}, + :field-length-m {:priority 90}, + :match-clock? {:priority 70}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :ice-rinks-count {:priority 80}, + :toilet? {:priority 70}, + :changing-rooms? {:priority 70}, + :area-m2 {:priority 90}, + :field-width-m {:priority 90}, + :lighting-info {:priority 50}, + :changing-rooms-m2 {:priority 70}, + :ligthing? {:priority 60}, + :school-use? {:priority 40}, + :light-roof? {:priority 70}}}, + 1520 + {:description + {:fi + "Luisteluun tarkoitettu luonnonmukainen kenttä. Jäädytetään käyttökuntoon talvikaudelle.", + :se + "Plan avsedd för skridskoåkning. Används under vintersäsongen.", + :en "Field intended for ice-skating."}, + :tags {:fi []}, + :name + {:fi "Luistelukenttä", + :se "Skridskobana", + :en "Ice-skating field"}, + :type-code 1520, + :main-category 1000, + :status "active", + :sub-category 1500, + :geometry-type "Point", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :stand-capacity-person {:priority 70}, + :free-use? {:priority 40}, + :field-length-m {:priority 90}, + :match-clock? {:priority 70}, + :fields-count {:priority 80}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :changing-rooms? {:priority 70}, + :area-m2 {:priority 90}, + :field-width-m {:priority 90}, + :lighting-info {:priority 50}, + :changing-rooms-m2 {:priority 70}, + :customer-service-point? {:priority 70}, + :ligthing? {:priority 60}, + :school-use? {:priority 40}, + :light-roof? {:priority 70}}}, + 2320 + {:description + {:fi + "Pysyvästi voimisteluun varustettu tila. Voimistelutilassa on erilaisia kiinteitä voimistelutelineitä ja -rakenteita (esim. volttimonttu, rekki tai trampoliini). Myös cheerleadingin ja sirkusharjoittelun olosuhteet luetaan voimistelutiloiksi. Tarkempi olosuhdetieto kerrotaan lisätiedoissa.", + :se "Permanent utrustning för att träna redskapsgymnastik.", + :en "Space permanently equipped for artistic gymnastics."}, + :tags {:fi ["monttu" "rekki" "nojapuut"]}, + :name + {:fi "Voimistelutila", + :se "Utrymme för redskapsgymnastik", + :en "Artistic gymnastics facility"}, + :type-code 2320, + :main-category 2000, + :status "active", + :sub-category 2300, + :geometry-type "Point", + :props + {:height-m {:priority 90}, + :surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :free-use? {:priority 40}, + :sport-specification {:priority 80}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :space-divisible {:priority 70}, + :gymnastic-routines-count {:priority 80}, + :area-m2 {:priority 90}, + :landing-places-count {:priority 80}, + :school-use? {:priority 40}}}, + 6130 + {:description + {:fi + "Pysyvästi esteratsastukseen varusteltu kenttä tai alue ulkona.", + :se "Bana med permanent utrustning för banhoppning", + :en "Field permanently equipped for show jumping. Outdoors."}, + :tags {:fi ["ratsastuskenttä"]}, + :name + {:fi "Esteratsastuskenttä/-alue", + :se "Bana för banhoppning", + :en "Show jumping field"}, + :type-code 6130, + :main-category 6000, + :status "active", + :sub-category 6100, + :geometry-type "Point", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :free-use? {:priority 40}, + :field-length-m {:priority 90}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :area-m2 {:priority 90}, + :field-width-m {:priority 90}, + :lighting-info {:priority 50}, + :ligthing? {:priority 60}, + :school-use? {:priority 40}}}, + 1395 + {:description + {:fi + "Yksi tai useampi pöytätennispöytä ulkona. Pöytätennispöydän tulee olla sijoitettu niin, että pelaamiseen on riittävä tila pöydän ympärillä. Pöydän tulee olla pelikäyttöön soveltuva.", + :se + "Ett eller flera bordtennisbord utomhus. Bordet är lämpligt för spel och bör vara placerat så att det finns tillräckligt utrymme för spel.", + :en + "One or more outdoor table tennis tables in the same area. The table must be positioned so that there is enough space for playing. The table must be suitable for the sport."}, + :tags {:fi ["pöytätennis" "pingis" "ping pong"]}, + :name + {:fi "Pöytätennisalue", + :se "Område med bordtennisbord", + :en "Table tennis area"}, + :type-code 1395, + :main-category 1000, + :status "active", + :sub-category 1300, + :geometry-type "Point", + :props + {:free-use? {:priority 40}, + :table-tennis-count {:priority 80}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :ligthing? {:priority 60}, + :school-use? {:priority 40}, + :water-point {:priority 70}, + :lighting-info {:priority 50}}}, + 6210 + {:description + {:fi + "Koiran koulutukseen, agilityyn tai muuhun harjoittamiseen varattu ulkoalue.", + :se + "Område reserverat för hundträning, agility eller annan hundhobby.", + :en + "Area reserved for dog training, agility or other dog sports."}, + :tags {:fi ["agility" "koirakenttä"]}, + :name + {:fi "Koiraurheilualue", + :se "Område för hundsport", + :en "Dog sports area"}, + :type-code 6210, + :main-category 6000, + :status "active", + :sub-category 6200, + :geometry-type "Point", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :free-use? {:priority 40}, + :field-length-m {:priority 90}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :area-m2 {:priority 90}, + :field-width-m {:priority 90}, + :lighting-info {:priority 50}, + :ligthing? {:priority 60}, + :track-length-m {:priority 90}}}, + 1370 + {:description + {:fi + "Tennikseen tarkoitettu kenttä. Mahdollinen lyöntiseinä ja kentän pintamateriaali merkitään lisätietoihin.", + :se + "En eller flera tennisbanor på samma område. Antalet banor, ytmaterial mm i karakteristika. Även uppgift om slagväggen.", + :en + "One or more tennis courts in the same area. Number of courts, surface material, etc. specified in properties, including information about a potential hit wall."}, + :tags {:fi ["tenniskenttä"]}, + :name + {:fi "Tenniskenttä", + :se "Område med tennisbanor", + :en "Tennis court area"}, + :type-code 1370, + :main-category 1000, + :status "active", + :sub-category 1300, + :geometry-type "Point", + :props + {:surface-material {:priority 89}, + :surface-material-info {:priority 88}, + :stand-capacity-person {:priority 70}, + :free-use? {:priority 40}, + :field-length-m {:priority 90}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :changing-rooms? {:priority 70}, + :area-m2 {:priority 90}, + :field-width-m {:priority 90}, + :lighting-info {:priority 50}, + :training-wall? {:priority 80}, + :water-point {:priority 70}, + :ligthing? {:priority 60}, + :school-use? {:priority 40}, + :light-roof? {:priority 70}}}, + 1360 + {:description + {:fi + "Pesäpalloon tarkoitettu kenttä. Jos kentän yhteydessä on katsomoita, lisätään kentän nimeen stadion-sana. Vähintään kansallisen tason pelipaikka. Pintamateriaali on esim. hiekka, hiekkatekonurmi tai muu synteettinen päällyste. Kentän koko on vähintään 50 x 100 m.", + :se + "En bobollsplan, kan ha flera läktare. Minimikrav: spelplats på nationell nivå. Sand, konstgräs med sand / annan syntetisk beläggning. >50 x 100 m.", + :en + "Finnish baseball field, may include stands. Can host at least national-level games. Sand, artificial turf / other synthetic surface, > 50 x 100 m. "}, + :tags {:fi ["pesäpallostadion"]}, + :name + {:fi "Pesäpallokenttä", :se "Bobollsplan", :en "Baseball field"}, + :type-code 1360, + :main-category 1000, + :status "active", + :sub-category 1300, + :geometry-type "Point", + :props + {:heating? {:priority 70}, + :surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :stand-capacity-person {:priority 70}, + :free-use? {:priority 40}, + :field-length-m {:priority 90}, + :match-clock? {:priority 70}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :changing-rooms? {:priority 70}, + :area-m2 {:priority 90}, + :field-width-m {:priority 90}, + :lighting-info {:priority 50}, + :scoreboard? {:priority 70}, + :loudspeakers? {:priority 70}, + :customer-service-point? {:priority 70}, + :water-point {:priority 70}, + :ligthing? {:priority 60}, + :covered-stand-person-count {:priority 70}, + :school-use? {:priority 40}}}, + 110 + {:description + {:fi + "Erämaalailla perustetut alueet pohjoisimmassa Lapissa. Metsähallitus tietolähteenä.", + :se + "Grundade enligt ödemarkslagen, i nordligaste Lappland. Källa: Forststyrelsen.", + :en + "Areas located in northernmost Lapland, established based on the Wildeness Act (1991/62). Source of information Metsähallitus."}, + :tags {:fi []}, + :name + {:fi "Erämaa-alue", :se "Vildmarksområden", :en "Wilderness area"}, + :type-code 110, + :main-category 0, + :status "active", + :sub-category 1, + :geometry-type "Polygon", + :props + {:area-km2 {:priority 90}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, + 2360 + {:description + {:fi "Pysyvästi käytössä oleva ampumarata sisätiloissa.", + :se "Permanent skjutbana inomhus.", + :en "Permanent indoor shooting range."}, + :tags {:fi ["ilmakivääri" "ilma-ase" "ammunta"]}, + :name + {:fi "Sisäampumarata", + :se "Inomhusskjutbana", + :en "Indoor shooting range"}, + :type-code 2360, + :main-category 2000, + :status "active", + :sub-category 2300, + :geometry-type "Point", + :props + {:surface-material {:priority 79}, + :surface-material-info {:priority 78}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :air-gun-shooting? {:priority 80}, + :pistol-shooting? {:priority 80}, + :shooting-positions-count {:priority 80}, + :area-m2 {:priority 90}, + :rifle-shooting? {:priority 80}, + :free-rifle-shooting? {:priority 80}, + :school-use? {:priority 40}, + :track-length-m {:priority 80}}}, + 5310 + {:description + {:fi + "Useiden eri moottoriurheilun lajien suorituspaikkoja, huoltotilat olemassa.", + :se + "Platser för flera olika motorsportgrenar, serviceutrymmen finns.", + :en + "Venues for various motor sports; service premises available."}, + :tags {:fi []}, + :name + {:fi "Moottoriurheilukeskus", + :se "Centrum för motorsport", + :en "Motor sports centre"}, + :type-code 5310, + :main-category 5000, + :status "active", + :sub-category 5300, + :geometry-type "Point", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :automated-timing? {:priority 70}, + :stand-capacity-person {:priority 70}, + :free-use? {:priority 40}, + :finish-line-camera? {:priority 70}, + :track-width-m {:priority 90}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :area-m2 {:priority 90}, + :lighting-info {:priority 50}, + :year-round-use? {:priority 80}, + :scoreboard? {:priority 70}, + :loudspeakers? {:priority 70}, + :ligthing? {:priority 60}, + :covered-stand-person-count {:priority 70}, + :track-length-m {:priority 90}}}, + 1560 + {:description + {:fi + "Alamäkiluistelua varten vuosittain rakennettava rata. Käytössä talvikaudella.", + :se "Permanent bana byggd för utförsåkning.", + :en "Permanent track built for downhill skating. "}, + :tags {:fi ["luistelu" "alamäkiluistelu"]}, + :name + {:fi "Alamäkiluistelurata", + :se "Skridskobana för utförsåkning", + :en "Downhill skating track"}, + :type-code 1560, + :main-category 1000, + :status "active", + :sub-category 1500, + :geometry-type "Point", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :lifts-count {:priority 70}, + :free-use? {:priority 40}, + :track-width-m {:priority 90}, + :altitude-difference {:priority 80}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :lighting-info {:priority 50}, + :ligthing? {:priority 60}, + :school-use? {:priority 40}, + :track-length-m {:priority 90}}}, + 205 + {:description + {:fi + "Rantautumiseen osoitettu paikka, ei järjestettyjä palveluita.", + :se + "Plats som anvisats för ilandstigning, inga ordnade tjänster.", + :en "Place intended for landing by boat, no services provided."}, + :tags {:fi ["laituri" "taukopaikka"]}, + :name + {:fi "Rantautumispaikka", + :se "Ilandstigningsplats", + :en "Boat dock"}, + :type-code 205, + :main-category 0, + :status "deprecated", + :sub-category 2, + :geometry-type "Point", + :props + {:toilet? {:priority 80}, + :boat-launching-spot? {:priority 90}, + :may-be-shown-in-excursion-map-fi? {:priority 0}, + :pier? {:priority 80}, + :school-use? {:priority 70}, + :free-use? {:priority 70}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, + 2150 + {:description + {:fi + "Muun rakennuksen yhteydessä oleva avoin liikuntatila, joka sopii monipuolisesti erilaisten liikuntamuotojen harrastamiseen. Salin liikuntapinta-ala vaihtelee tyypillisesti alle 300 neliöstä noin 750 neliöön. Esim. koulurakennuksessa sijaitseva liikuntasali.", + :se + "En idrottssal som är ansluten till en annan byggnad. Storlek och höjd anges i karakteristika.", + :en + "A gymnastics hall connected to another building. Size and height specified in properties."}, + :tags {:fi ["jumppasali" "voimistelusali"]}, + :name + {:fi "Liikuntasali", :se "Idrottssal", :en "Gymnastics hall"}, + :type-code 2150, + :main-category 2000, + :status "active", + :sub-category 2100, + :geometry-type "Point", + :props + {:height-m {:priority 90}, + :surface-material {:priority 89}, + :basketball-fields-count {:priority 80}, + :surface-material-info {:priority 88}, + :free-use? {:priority 40}, + :tennis-courts-count {:priority 80}, + :field-length-m {:priority 90}, + :match-clock? {:priority 70}, + :badminton-courts-count {:priority 80}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :space-divisible {:priority 70}, + :gymnastics-space? {:priority 80}, + :area-m2 {:priority 90}, + :field-width-m {:priority 90}, + :futsal-fields-count {:priority 80}, + :football-fields-count {:priority 80}, + :floorball-fields-count {:priority 80}, + :handball-fields-count {:priority 80}, + :volleyball-fields-count {:priority 80}, + :spinning-hall? {:priority 80}, + :school-use? {:priority 40}}}, + 2210 + {:description + {:fi + "Liikuntahalli on itsenäinen rakennus, jossa voi olla useita liikuntatiloja tai osiin jaettavissa oleva pääsali.", + :se + "Idrottshall med utrymmen för flera idrottsgrenar eller med ett i mindre sektioner indelbart huvudidrottsutrymme. Storleken varierar mellan ca 750 och 4999 m2. Inkluderar inomhusaktivitetsparker med faciliteter för flera fysiska aktiviteter.", + :en + "Building containing facilities for various sports or the main sports area can be split into smaller sections. Hall size varies between app. 750 - 4999 square meters. Includes indoor activity parks with facilities for multiple physical activities."}, + :tags {:fi ["urheilutalo" "urheiluhalli"]}, + :name {:fi "Liikuntahalli", :se "Idrottshall", :en "Sports hall "}, + :type-code 2210, + :main-category 2000, + :status "active", + :sub-category 2200, + :geometry-type "Point", + :props + {:height-m {:priority 90}, + :surface-material {:priority 89}, + :basketball-fields-count {:priority 80}, + :surface-material-info {:priority 88}, + :stand-capacity-person {:priority 70}, + :free-use? {:priority 40}, + :sprint-lanes-count {:priority 80}, + :javelin-throw-places-count {:priority 80}, + :tennis-courts-count {:priority 80}, + :field-length-m {:priority 90}, + :circular-lanes-count {:priority 80}, + :match-clock? {:priority 70}, + :inner-lane-length-m {:priority 80}, + :discus-throw-places {:priority 80}, + :badminton-courts-count {:priority 80}, + :hammer-throw-places-count {:priority 80}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :padel-courts-count {:priority 80}, + :polevault-places-count {:priority 80}, + :group-exercise-rooms-count {:priority 80}, + :space-divisible {:priority 70}, + :toilet? {:priority 70}, + :gymnastics-space? {:priority 80}, + :running-track-surface-material {:priority 80}, + :area-m2 {:priority 90}, + :field-width-m {:priority 90}, + :scoreboard? {:priority 70}, + :futsal-fields-count {:priority 80}, + :shotput-count {:priority 80}, + :longjump-places-count {:priority 80}, + :football-fields-count {:priority 80}, + :floorball-fields-count {:priority 80}, + :auxiliary-training-area? {:priority 80}, + :squash-courts-count {:priority 80}, + :customer-service-point? {:priority 70}, + :accessibility-info {:priority 40}, + :handball-fields-count {:priority 80}, + :volleyball-fields-count {:priority 80}, + :climbing-wall? {:priority 80}, + :school-use? {:priority 40}, + :highjump-places-count {:priority 80}}}, + 101 + {:description + {:fi + "Sijaitsevat taajamissa, max 1 km asutuksesta. Toimivat kävely-, leikki-, oleskelu-, lenkkeily- ja pyöräilypaikkoina. Kaavamerkintä V tai VL. Esimerkkejä lähi- tai ulkoilupuistoista: leikkipuistot, liikennepuistot, perhepuistot, oleskelupuistot, keskuspuistot ja kirkkopuistot.", + :se + "I tätorter, i omedelbar närhet till bebyggelse. Avsedd för daglig användning. Plats för lek, vistelse och promenader. Planbeteckning VL. Till exempel en lekpark.", + :en + "In population centres, in or near residential areas. Intended for daily use. Used for play, recreation and walks. Plan symbol VL. E.g. a playground."}, + :tags {:fi ["puisto" "lähiliikuntapaikka"]}, + :name + {:fi "Lähi-/ulkoilupuisto", + :se "Närpark", + :en "Neighbourhood park"}, + :type-code 101, + :main-category 0, + :status "active", + :sub-category 1, + :geometry-type "Polygon", + :props + {:playground? {:priority 90}, + :area-km2 {:priority 100}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :water-point {:priority 80}, + :toilet? {:priority 80}}}, + 102 + {:description + {:fi + "Päivittäin käytettäviä alueita, max 1 km asunnoista. Toimivat kävely-, leikki-, oleskelu-, lenkkeily- ja pyöräilypaikkoina. Kevyt liikenne voi mennä ulkoilupuiston läpi. Voi sisältää puistoa, metsää, peltoa, niittyä, vesialuetta. Kaavamerkintä V tai VL.", + :se + "Områden avsedda för daglig använding, max på 1 kilometers avstånd från bebyggelse. Fungerar som ett område för promenader, lekar, vistelse, joggning och cykling. Lätt trafikled kan fara igenom friluftsparken. Området kan bestå av park, skog, åker, äng och vattenled. Planbeteckning V eller VL.", + :en + "Used daily, max. 1 km from residential areas. Intended for walks, play, recreation, jogging and cycling. There may be bicycle and pedestrian traffic across the park. May consist of park, forest, fields, meadows, bodies of water. Symbol V or VL."}, + :tags {:fi ["puisto"]}, + :name + {:fi "Ulkoilupuisto", :se "Friluftspark", :en "Leisure park"}, + :type-code 102, + :main-category 0, + :status "deprecated", + :sub-category 1, + :geometry-type "Polygon", + :props + {:playground? {:priority 90}, + :area-km2 {:priority 100}, + :may-be-shown-in-excursion-map-fi? {:priority 0}, + :school-use? {:priority 70}, + :free-use? {:priority 70}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, + 7000 + {:description + {:fi + "Liikuntapaikan tai -paikkojen yhteydessä oleva, liikuntapaikan ylläpitoa tai käyttöä palveleva rakennus. Voi sisältää varastoja, pukuhuoneita, suihkutiloja yms.", + :se "Servicebyggnader i anslutning till idrottsanläggningar.", + :en + "Maintenance buildings in connection with sports facilities."}, + :tags {:fi ["konesuoja" "huoltotila"]}, + :name + {:fi "Huoltorakennukset", + :se "Servicebyggnader", + :en "Maintenance/service buildings"}, + :type-code 7000, + :main-category 7000, + :status "active", + :sub-category 7000, + :geometry-type "Point", + :props + {:free-use? {:priority 40}, + :ski-service? {:priority 70}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :shower? {:priority 70}, + :changing-rooms? {:priority 70}, + :area-m2 {:priority 90}, + :equipment-rental? {:priority 70}, + :sauna? {:priority 70}, + :school-use? {:priority 40}}}, + 1110 + {:description + {:fi + "Liikuntapuisto on useita liikuntapaikkoja käsittävä liikunta-alue. Liikuntapuistossa voi olla esim. erilaisia kenttiä, uimaranta, kuntorata, monitoimihalli, leikkipuisto jne. koottuna samalle alueelle. Lipakseen tallennetaan sekä tieto liikuntapuistosta että yksittäiset liikuntapaikat, joita puisto sisältää. Liikuntapaikat lasketaan omiksi paikoikseen.", + :se + "En idrottspark är ett idrottsområde med flera idrottsplatser. Där kan finnas olika planer, badstrand, konditionsbana, allaktivitetshall, lekpark osv samlade på samma område. I Lipas lagras uppgifter om såväl idrottsparken som enstaka faciliteter som finns i parken. Varje motionsplats räknas som en plats.", + :en + "A sports park is an area including several sports facilities, e.g., different fields, beach, a jogging track, a multi-purpose hall, a playground. 'Lipas' contains information both on the sports park and the individual sports facilities found there. The sports facilities are listed as individual items in the classification."}, + :tags {:fi ["puisto" "lähiliikunta" "lähiliikuntapaikka"]}, + :name {:fi "Liikuntapuisto", :se "Idrottspark", :en "Sports park"}, + :type-code 1110, + :main-category 1000, + :status "active", + :sub-category 1100, + :geometry-type "Polygon", + :props + {:free-use? {:priority 50}, + :fields-count {:priority 80}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :area-m2 {:priority 90}, + :lighting-info {:priority 60}, + :ligthing? {:priority 70}, + :accessibility-info {:priority 50}, + :playground? {:priority 80}, + :school-use? {:priority 50}}}, + 3250 + {:description + {:fi + "Vesiurheilukeskuksessa on vesistössä sijaitsevia liikuntapalveluita tai palvelukokonaisuus, joka voi muodostua erilaisista veden päällä tai vedessä olevista suorituspaikoista tai -radoista."}, + :tags {:fi []}, + :name {:fi "Vesiurheilukeskus"}, + :type-code 3250, + :main-category 3000, + :status "active", + :sub-category 3200, + :geometry-type "Point", + :props + {:free-use? {:priority 40}, + :pier? {:priority 80}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :shower? {:priority 70}, + :changing-rooms? {:priority 70}, + :pool-water-area-m2 {:priority 90}, + :sauna? {:priority 70}, + :customer-service-point? {:priority 70}}}, + 6220 + {:description + {:fi + "Erityisesti koiraharrastusta, agilityä, koulutusta tms. varten varustettu halli.", + :se + "Hall som utrustats särskilt för hundhobby, agility, träning osv.", + :en + "Hall specifically equipped for dog sports, agility, training, etc."}, + :tags {:fi ["agility" "koirahalli"]}, + :name + {:fi "Koiraurheiluhalli", + :se "Hundsporthall", + :en "Dog sports hall"}, + :type-code 6220, + :main-category 6000, + :status "active", + :sub-category 6200, + :geometry-type "Point", + :props + {:heating? {:priority 70}, + :surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :free-use? {:priority 40}, + :field-length-m {:priority 90}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :area-m2 {:priority 90}, + :field-width-m {:priority 90}, + :lighting-info {:priority 50}, + :ligthing? {:priority 60}}}, + 4530 + {:description + {:fi + "Pyöräillen tapahtuvaan suunnistamiseen, alueesta on pyöräsuunnistukseen soveltuva kartta.", + :se "Karta över område som lämpar sig för cykelorientering.", + :en "A map for mountain bike orienteering available."}, + :tags {:fi []}, + :name + {:fi "Pyöräsuunnistusalue", + :se "Cykelorienteringsområde", + :en " Mountain bike orienteering area"}, + :type-code 4530, + :main-category 4000, + :status "deprecated", + :sub-category 4500, + :geometry-type "Polygon", + :props + {:area-km2 {:priority 90}, + :school-use? {:priority 40}, + :free-use? {:priority 40}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, + 4720 + {:description + {:fi + "Merkitty luonnon kallio, jota voi käyttää kiipeilyyn. Jääkiipeily lisätietoihin. Myös boulderointikalliot.", + :se + "Märkt berg i naturen. Isklättring i tilläggsinformation. Även berg för bouldering.", + :en + "Marked natural cliff. Ice climbing specified in additional information. Also includes bouldering cliffs."}, + :tags {:fi []}, + :name + {:fi "Kiipeilykallio", :se "Klätterberg", :en "Climbing rock"}, + :type-code 4720, + :main-category 4000, + :status "active", + :sub-category 4700, + :geometry-type "Point", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :free-use? {:priority 40}, + :may-be-shown-in-excursion-map-fi? {:priority 0}, + :climbing-routes-count {:priority 80}, + :ice-climbing? {:priority 80}, + :climbing-wall-height-m {:priority 90}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :area-m2 {:priority 90}, + :lighting-info {:priority 50}, + :climbing-wall-width-m {:priority 90}, + :ligthing? {:priority 60}}}, + 1330 + {:description + {:fi + "Rantalentopallokenttä, pehmeä alusta. Kohde voi sijaita muuallakin kuin rannalla.", + :se + "Beachvolleybollplan, mjuk grund. Kan också ha annat läge än stranden.", + :en + "Beach volleyball court, soft basement. May also be located far from a beach."}, + :tags {:fi ["rantalentopallo" "rantalentopallokenttä"]}, + :name + {:fi "Beachvolley-/rantalentopallokenttä", + :se "Beachvolleyplan", + :en "Beach volleyball court"}, + :type-code 1330, + :main-category 1000, + :status "active", + :sub-category 1300, + :geometry-type "Point", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :height-of-basket-or-net-adjustable? {:priority 80}, + :free-use? {:priority 40}, + :field-length-m {:priority 90}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :area-m2 {:priority 90}, + :field-width-m {:priority 90}, + :lighting-info {:priority 50}, + :water-point {:priority 70}, + :ligthing? {:priority 60}, + :school-use? {:priority 40}}}, + 206 + {:description + {:fi + "Rakennettu tulentekopaikka tai keittokatos. Kohde voi olla esimerkiksi maasta eristetty katoksellinen tulisija tai tulisija avotulelle. Tulentekopaikan tarkempi kuvaus ja tieto mahdollisista rajoituksista lisätietoihin.", + :se + "En byggd eldningsplats eller ett kokskjul. Objektet kan till exempel vara en eldstad med tak som är isolerad från marken eller en eldstad för öppen eld. En mer detaljerad beskrivning av eldningsplatsen och information om eventuella begränsningar finns i ytterligare information.", + :en + "A constructed fireplace or cooking shelter. The site can be, for example, a covered fireplace isolated from the ground or a fireplace for open fires. A more detailed description of the fireplace and information about any possible restrictions can be found in the additional information."}, + :tags + {:fi + ["nuotiopaikka" + "keittokatos" + "grillauspaikka" + "ruoka" + "taukopaikka"]}, + :name + {:fi "Ruoanlaitto- / tulentekopaikka", + :se "Matlagningsplats", + :en "Cooking facilities"}, + :type-code 206, + :main-category 0, + :status "active", + :sub-category 2, + :geometry-type "Point", + :props + {:may-be-shown-in-excursion-map-fi? {:priority 0}, + :toilet? {:priority 70}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :free-use? {:priority 60}}}, + 4830 + {:description + {:fi + "Ulkona tai sisällä sijaitseva jousiammuntarata. Radan käyttö edellyttää erillistä lupaa, seuran jäsenyyttä tai harjoitusvuoroa. Radan varustus ja soveltuvat lajit kuvataan lisätiedoissa.", + :se "Ute eller inne. Utrustning och grenar i karakteristika.", + :en + "Outdoors or indoors. Equipment and the various sports detailed in properties."}, + :tags {:fi ["jousiampumarata"]}, + :name + {:fi "Jousiammuntarata", :se "Bågskyttebana", :en "Archery range"}, + :type-code 4830, + :main-category 4000, + :status "active", + :sub-category 4800, + :geometry-type "Point", + :props + {:free-use? {:priority 40}, + :track-width-m {:priority 90}, + :free-customer-use? {:priority 40}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :shooting-positions-count {:priority 90}, + :area-m2 {:priority 90}, + :lighting-info {:priority 50}, + :ligthing? {:priority 60}, + :track-length-m {:priority 90}}}, + 1180 + {:description + {:fi "Frisbeegolfin pelaamiseen rakennettu rata.", + :se "En bana byggt för frisbeegolf.", + :en "Track built for disc golf. "}, + :tags {:fi []}, + :name + {:fi "Frisbeegolfrata", + :se "Frisbeegolfbana", + :en "Disc golf course"}, + :type-code 1180, + :main-category 1000, + :status "active", + :sub-category 1100, + :geometry-type "Point", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :holes-count {:priority 90}, + :free-use? {:priority 50}, + :may-be-shown-in-excursion-map-fi? {:priority 0}, + :altitude-difference {:priority 80}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :lighting-info {:priority 60}, + :ligthing? {:priority 70}, + :accessibility-info {:priority 50}, + :school-use? {:priority 50}, + :track-type {:priority 80}, + :range? {:priority 80}, + :track-length-m {:priority 90}}}, + 4422 + {:description + {:fi + "Moottorikelkkailuun tarkoitettu reitti, jolla ei ole tehty virallista reittitoimitusta. Reitillä on kuitenkin ylläpitäjä ja maanomistajien lupa.", + :se "Ingen ruttexpedition.", + :en "No official approval."}, + :tags {:fi []}, + :name + {:fi "Moottorikelkkaura", + :se "Snöskoterspår", + :en "Unofficial snowmobile route"}, + :type-code 4422, + :main-category 4000, + :status "active", + :sub-category 4400, + :geometry-type "LineString", + :props + {:may-be-shown-in-excursion-map-fi? {:priority 0}, + :route-width-m {:priority 98}, + :route-length-km {:priority 99}, + :rest-places-count {:priority 70}, + :free-use? {:priority 40}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, + 4430 + {:description + {:fi + "Ratsastukseen ja/tai kärryillä ajoon tarkoitettu reitti. Sallitut käyttötavat kerrotaan reitin tarkemmissa tiedoissa.", + :se + "Led avsedd för ridning och/eller häst med kärra. Användningsanvisningar i karakteristika.", + :en + "Route intended for horseback riding and/or carriage riding. Different uses specified in additional information."}, + :tags {:fi ["ratsastusreitti"]}, + :name {:fi "Hevosreitti", :se "Hästled", :en "Horse track"}, + :type-code 4430, + :main-category 4000, + :status "active", + :sub-category 4400, + :geometry-type "LineString", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :free-use? {:priority 40}, + :route-width-m {:priority 98}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :rest-places-count {:priority 70}, + :lit-route-length-km {:priority 97}, + :school-use? {:priority 40}, + :route-length-km {:priority 99}}}, + 204 + {:description + {:fi + "Luonnon tarkkailuun tarkoitettu rakennelma, lintutorni tai vastaava.", + :se + "Anordning avsedd för observationer i naturen, t ex fågeltorn.", + :en + "Structure built for nature observation. E.g. bird observation tower."}, + :tags {:fi ["lintutorni" "näkötorni" "torni"]}, + :name + {:fi "Luontotorni", + :se "Naturtorn", + :en "Nature observation tower"}, + :type-code 204, + :main-category 0, + :status "active", + :sub-category 2, + :geometry-type "Point", + :props + {:toilet? {:priority 80}, + :may-be-shown-in-excursion-map-fi? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :free-use? {:priority 70}}}, + 106 + {:description + {:fi + "Monikäyttöalueiksi voidaan nimittää jokaisenoikeuksin ulkoiluun käytettäviä maa- ja metsätalousalueita. Monikäyttöalueita ovat erityisesti rakentamattomat rannat ja taajamien läheiset maa- ja metsätalousalueet. Kaavamerkintä MU. Virkistysmetsien metsätaloudessa on huomioitu mm. maisemalliset arvot, ja ne on perustettu Metsähallituksen päätöksellä. Virkistysmetsien osalta Lipas-aineisto perustuu Metsähallituksen tietoihin.", + :se + "Områden för mångsidig användning kan kallas jord- och skogsbruksområden som används för rekreation med allemansrätten. Områden för mångsidig användning är särskilt obebyggda stränder och jord- och skogsbruksområden nära tätorter. Planbeteckning MU. Inom skogsbruket i rekreationsskogar har man beaktat bl.a. landskapsvärden, och de har inrättats genom beslut av Forststyrelsen. När det gäller rekreationsskogar baseras Lipas-materialet på uppgifter från Forststyrelsen.", + :en + "Multi-use areas can be designated as agricultural and forestry areas used for outdoor activities under everyman's rights. Multi-use areas are particularly undeveloped shores and agricultural and forestry areas near urban areas. Plan designation MU. In the forestry of recreational forests, landscape values, among other things, have been considered, and they have been established by a decision of Metsähallitus. For recreational forests, the Lipas data is based on information from Metsähallitus."}, + :tags {:fi ["ulkoilualue" "virkistysalue"]}, + :name + {:fi + "Monikäyttöalue tai virkistysmetsä, jossa on virkistyspalveluita", + :se + "Mångbruksområde eller rekreationsskog med rekreationstjänster", + :en + "Multi-use area or recreational forest with recreational services"}, + :type-code 106, + :main-category 0, + :status "active", + :sub-category 1, + :geometry-type "Polygon", + :props + {:area-km2 {:priority 90}, + :may-be-shown-in-excursion-map-fi? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, + 2620 + {:description + {:fi + "Biljardisali on biljardin pelaamiseen tarkoitettu tila. Biljardipöytien määrä ja tyyppi kuvataan lisätiedoissa."}, + :tags {:fi []}, + :name {:fi "Biljardisali"}, + :type-code 2620, + :main-category 2000, + :status "active", + :sub-category 2600, + :geometry-type "Point", + :props + {:total-billiard-tables-count {:priority 90}, + :carom-tables-count {:priority 80}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :snooker-tables-count {:priority 80}, + :pool-tables-count {:priority 80}, + :customer-service-point? {:priority 70}, + :pyramid-tables-count {:priority 80}, + :kaisa-tables-count {:priority 80}, + :school-use? {:priority 40}}}, + 4610 + {:description + {:fi + "Ampumahiihdon harjoitteluun tarkoitettu alue, jossa on ainakin latu ja ampumapaikka/-paikkoja. ", + :se + "Annat träningsområde för skidskytte. Spår och skjutplats finns.", + :en + "Other training area for biathlon. Ski track and shooting range."}, + :tags {:fi ["ampumapaikka"]}, + :name + {:fi "Ampumahiihdon harjoittelualue", + :se "Träningsområde för skidskytte", + :en "Training area for biathlon"}, + :type-code 4610, + :main-category 4000, + :status "active", + :sub-category 4600, + :geometry-type "Point", + :props + {:stand-capacity-person {:priority 70}, + :free-use? {:priority 40}, + :ski-service? {:priority 70}, + :finish-line-camera? {:priority 70}, + :ski-track-traditional? {:priority 80}, + :route-width-m {:priority 98}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :rest-places-count {:priority 70}, + :changing-rooms? {:priority 70}, + :shooting-positions-count {:priority 80}, + :lit-route-length-km {:priority 97}, + :year-round-use? {:priority 80}, + :scoreboard? {:priority 70}, + :changing-rooms-m2 {:priority 70}, + :loudspeakers? {:priority 70}, + :ski-track-freestyle? {:priority 80}, + :route-length-km {:priority 99}}}, + 2610 + {:description + {:fi + "Keilailuun varustettu halli. Ratojen määrä ja palveluvarustus kirjataan lisätietoihin.", + :se "Antalet banor och serviceutrustning i karakteristika.", + :en "Number of alleys and service facilities in properties."}, + :tags {:fi []}, + :name {:fi "Keilahalli", :se "Bowlinghall", :en "Bowling alley"}, + :type-code 2610, + :main-category 2000, + :status "active", + :sub-category 2600, + :geometry-type "Point", + :props + {:free-use? {:priority 40}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :bowling-lanes-count {:priority 90}, + :toilet? {:priority 70}, + :area-m2 {:priority 90}, + :cosmic-bowling? {:priority 80}, + :scoreboard? {:priority 70}, + :loudspeakers? {:priority 70}, + :school-use? {:priority 40}}}, + 2110 + {:description + {:fi + "Erilasia liikuntapalveluita ja -tiloja tarjoava kuntokeskus. Kohteessa voi olla esimerkiksi kuntosali- ja ryhmäliikuntatiloja.", + :se + "Olika motionstjänster och -utrymmen, t ex gym och gruppidrottsutrymmen.", + :en + "Different sports services and premises, e.g., gym, group exercise premises. "}, + :tags {:fi ["kuntosali" "kuntoilu"]}, + :name + {:fi "Kuntokeskus", + :se "Konditionsidrottscentrum", + :en "Fitness centre"}, + :type-code 2110, + :main-category 2000, + :status "active", + :sub-category 2100, + :geometry-type "Point", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :free-customer-use? {:priority 40}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :group-exercise-rooms-count {:priority 80}, + :area-m2 {:priority 90}, + :weight-lifting-spots-count {:priority 80}, + :customer-service-point? {:priority 70}, + :spinning-hall? {:priority 80}, + :school-use? {:priority 40}, + :exercise-machines-count {:priority 80}}}, + 3120 + {:description + {:fi + "Yksittäinen tai useampi pieni uima-allas muun kuin uimahallin tai kylpylän yhteydessä. Uima-allastilat voivat olla pääasiassa esim. kuntoutus- tai terapiakäytössä. Altaiden määrä ja vesipinta-ala kerrotaan ominaisuustiedoissa.", + :se + "Enstaka simbassäng , ofta i anslutning till en annan byggnad.", + :en + "Individual swimming pool, often in connection with other buildings."}, + :tags {:fi []}, + :name + {:fi "Uima-allastila", :se "Simbassäng", :en "Swimming pool"}, + :type-code 3120, + :main-category 3000, + :status "active", + :sub-category 3100, + :geometry-type "Point", + :props + {:pool-tracks-count {:priority 87}, + :free-use? {:priority 40}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :pool-width-m {:priority 89}, + :pool-min-depth-m {:priority 80}, + :swimming-pool-count {:priority 90}, + :pool-water-area-m2 {:priority 90}, + :pool-length-m {:priority 88}, + :pool-max-depth-m {:priority 80}, + :accessibility-info {:priority 40}, + :pool-temperature-c {:priority 80}, + :school-use? {:priority 40}}}, + 104 + {:description + {:fi + "Sijaitsevat kauempana taajamasta, automatkan päässä. Monipuolinen polku- ja reittiverkosto. Käyttö painottuu viikonloppuihin ja loma-aikoihin. Palvelevat usein useaa kuntaa. Kaavamerkintä VR.", + :se + "Ett område på bil avstånd från tätorten, Området har en stor variation av stig- och ruttnätverk. Användningen av området fokuserar sig mest till helgerna och semester tiderna. Området betjänar oftast mer än en kommun. Planbeteckning VR.", + :en + "Located further away from population centres, accessible by car. Complex network of paths and routes. Use concentrated during weekends and holidays. Often serves several municipalities. Symbol VR."}, + :tags {:fi ["virkistysalue"]}, + :name + {:fi "Retkeilyalue", :se "Utflyktsområde", :en "Hiking area"}, + :type-code 104, + :main-category 0, + :status "deprecated", + :sub-category 1, + :geometry-type "Polygon", + :props + {:may-be-shown-in-excursion-map-fi? {:priority 0}, + :area-km2 {:priority 90}, + :school-use? {:priority 70}, + :free-use? {:priority 70}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, + 2330 + {:description + {:fi "Pysyvästi pöytätennikseen varustettu tila.", + :se "Permanent utrustning för att träna bordtennis.", + :en "Space permanently equipped for table tennis."}, + :tags {:fi ["pingis" "pingispöytä"]}, + :name + {:fi "Pöytätennistila", + :se "Utrymme för bordtennis", + :en "Table tennis venue"}, + :type-code 2330, + :main-category 2000, + :status "active", + :sub-category 2300, + :geometry-type "Point", + :props + {:height-m {:priority 90}, + :surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :free-use? {:priority 40}, + :active-space-width-m {:priority 90}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :area-m2 {:priority 90}, + :active-space-length-m {:priority 90}, + :table-tennis-count {:priority 80}, + :school-use? {:priority 40}}}, + 2280 + {:description + {:fi + "Tenniksen pelaamiseen varusteltu halli. Kenttien lukumäärä ja pintamateriaali kerrotaan kohteen lisätiedoissa.", + :se "Antalet banor i karakteristika.", + :en "Number of courts specified in properties."}, + :tags {:fi []}, + :name {:fi "Tennishalli", :se "Tennishall", :en "Tennis hall"}, + :type-code 2280, + :main-category 2000, + :status "active", + :sub-category 2200, + :geometry-type "Point", + :props + {:height-m {:priority 90}, + :surface-material {:priority 89}, + :surface-material-info {:priority 88}, + :stand-capacity-person {:priority 70}, + :free-use? {:priority 40}, + :tennis-courts-count {:priority 80}, + :field-length-m {:priority 90}, + :badminton-courts-count {:priority 80}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :padel-courts-count {:priority 80}, + :toilet? {:priority 70}, + :area-m2 {:priority 90}, + :field-width-m {:priority 90}, + :scoreboard? {:priority 70}, + :floorball-fields-count {:priority 80}, + :squash-courts-count {:priority 80}, + :customer-service-point? {:priority 70}, + :volleyball-fields-count {:priority 80}, + :school-use? {:priority 40}}}, + 6140 + {:description + {:fi "Raviurheilun harjoitus- tai kilparata.", + :se "Övnings- eller tävlingsbana för travsport.", + :en "Training or competition track for horse racing."}, + :tags {:fi []}, + :name {:fi "Ravirata", :se "Travbana", :en "Horse racing track"}, + :type-code 6140, + :main-category 6000, + :status "active", + :sub-category 6100, + :geometry-type "Point", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :automated-timing? {:priority 70}, + :stand-capacity-person {:priority 70}, + :free-use? {:priority 40}, + :finish-line-camera? {:priority 70}, + :track-width-m {:priority 90}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :lighting-info {:priority 50}, + :scoreboard? {:priority 70}, + :loudspeakers? {:priority 70}, + :ligthing? {:priority 60}, + :covered-stand-person-count {:priority 70}, + :track-length-m {:priority 90}}}, + 2140 + {:description + {:fi + "Sali, jossa voi harrastaa kamppailulajeja kuten painia, nyrkkeilyä tai budolajeja. Tilan koko ja varustus kerrotaan kohteen lisätiedoissa.", + :se + "Sal där man kan utöva självförsvarsgrenar, t ex brottning, boxning. Storleken anges i karakteristika.", + :en + "Hall for self-defence sports, e.g., wrestling, boxing. Size specified in properties. "}, + :tags {:fi ["paini" "judo" "tatami"]}, + :name + {:fi "Kamppailulajien sali", + :se "Sal för kampsport", + :en "Martial arts hall"}, + :type-code 2140, + :main-category 2000, + :status "active", + :sub-category 2100, + :geometry-type "Point", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :group-exercise-rooms-count {:priority 80}, + :space-divisible {:priority 70}, + :tatamis-count {:priority 80}, + :area-m2 {:priority 90}, + :wrestling-mats-count {:priority 80}, + :boxing-rings-count {:priority 80}, + :weight-lifting-spots-count {:priority 80}, + :customer-service-point? {:priority 70}, + :school-use? {:priority 40}, + :exercise-machines-count {:priority 80}}}, + 4220 + {:description + {:fi + "Hiihtoon tarkoitettu katettu tila (esim. tunneli, putki, halli).", + :se + "Utrymme avsett för skidåkning under tak (tunnel, rör, hall el dyl).", + :en + "Covered space (tunnel, tube, hall, etc.) intended for skiing."}, + :tags {:fi []}, + :name {:fi "Hiihtotunneli", :se "Skidtunnel", :en "Ski tunnel"}, + :type-code 4220, + :main-category 4000, + :status "active", + :sub-category 4200, + :geometry-type "Point", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :free-use? {:priority 40}, + :ski-service? {:priority 70}, + :altitude-difference {:priority 90}, + :route-width-m {:priority 97}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :area-m2 {:priority 90}, + :equipment-rental? {:priority 70}, + :accessibility-info {:priority 40}, + :route-length-km {:priority 99}}}, + 2230 + {:description + {:fi + "Ensisijaisesti jalkapalloiluun tarkoitettu halli. Halli voi olla ympärivuotisessa käytössä tai erikseen talviajalle pystytettävä kevythalli. Kentän pintamateriaalina on yleensä tekonurmi.", + :se + "Hall avsedd för fotboll. Ytmaterial, antalet planer och storlek i karakteristika.", + :en + "Hall intended for football. Surface material, number and size of courts specified in properties."}, + :tags {:fi []}, + :name + {:fi "Jalkapallohalli", :se "Fotbollshall", :en "Football hall"}, + :type-code 2230, + :main-category 2000, + :status "active", + :sub-category 2200, + :geometry-type "Point", + :props + {:height-m {:priority 90}, + :heating? {:priority 70}, + :surface-material {:priority 89}, + :basketball-fields-count {:priority 80}, + :surface-material-info {:priority 88}, + :stand-capacity-person {:priority 70}, + :free-use? {:priority 40}, + :tennis-courts-count {:priority 80}, + :field-length-m {:priority 90}, + :match-clock? {:priority 70}, + :sprint-track-length-m {:priority 80}, + :badminton-courts-count {:priority 80}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :area-m2 {:priority 90}, + :field-width-m {:priority 90}, + :scoreboard? {:priority 70}, + :football-fields-count {:priority 80}, + :auxiliary-training-area? {:priority 80}, + :loudspeakers? {:priority 70}, + :customer-service-point? {:priority 70}, + :volleyball-fields-count {:priority 80}, + :school-use? {:priority 40}}}, + 1350 + {:description + {:fi + "Suuri jalkapallokenttä, katsomoita. Vähintään kansallisen tason pelipaikka.", + :se + "Stor fotbollsplan, flera läktare. Minimikrav: spelplats på nationell nivå.", + :en + "Large football field, stands. Can host at least national-level games."}, + :tags {:fi ["jalkapallokenttä"]}, + :name + {:fi "Jalkapallostadion", + :se "Fotbollsstadion", + :en "Football stadium"}, + :type-code 1350, + :main-category 1000, + :status "active", + :sub-category 1300, + :geometry-type "Point", + :props + {:heating? {:priority 70}, + :surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :stand-capacity-person {:priority 70}, + :free-use? {:priority 40}, + :field-length-m {:priority 90}, + :match-clock? {:priority 70}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :area-m2 {:priority 90}, + :field-width-m {:priority 90}, + :lighting-info {:priority 50}, + :year-round-use? {:priority 80}, + :scoreboard? {:priority 70}, + :loudspeakers? {:priority 70}, + :customer-service-point? {:priority 70}, + :water-point {:priority 70}, + :ligthing? {:priority 60}, + :covered-stand-person-count {:priority 70}, + :school-use? {:priority 40}, + :light-roof? {:priority 70}}}, + 4840 + {:description + {:fi + "Maastoon rakennettu jousiammuntarata. Radan käyttö edellyttää erillistä lupaa, seuran jäsenyyttä tai harjoitusvuoroa. ", + :se "Bågskyttebana byggd i terrängen.", + :en "Archery course built in rough terrain."}, + :tags {:fi ["jousiampumarata"]}, + :name + {:fi "Jousiammuntamaastorata", + :se "Terrängbana för bågskytte", + :en "Field archery course"}, + :type-code 4840, + :main-category 4000, + :status "active", + :sub-category 4800, + :geometry-type "Point", + :props + {:free-use? {:priority 40}, + :free-customer-use? {:priority 40}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :shooting-positions-count {:priority 80}, + :lighting-info {:priority 50}, + :ligthing? {:priority 60}, + :track-length-m {:priority 90}}}, + 113 + {:description + {:fi + "Vapaa-ajankalastukseen sopiva alue. Kohteessa voi olla palvelurakenteita.", + :se + "Område eller en plats i ett naturligt vattendrag som ställts i ordning för fritidsfiske.", + :en + "Natural aquatic destination equipped and maintained for recreational fishing."}, + :tags {:fi ["kalastusalue" "kalastuspaikka"]}, + :name + {:fi "Kalastuskohde (alue)", + :se "Område eller plats för fiske", + :en "Fishing area/spot "}, + :type-code 113, + :main-category 0, + :status "active", + :sub-category 1, + :geometry-type "Polygon", + :props + {:free-use? {:priority 70}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :pier? {:priority 80}, + :customer-service-point? {:priority 80}, + :equipment-rental? {:priority 80}}}, + 1510 + {:description + {:fi + "Koneellisesti tai keinotekoisesti jäähdytetty ulkokenttä. Kentän koko ja varustustiedot löytyvät lisätiedoista. Käytössä talvikaudella.", + :se + "En utomhusbana som är mekaniskt eller artificiellt kyld. Information om banans storlek och utrustning finns i ytterligare information. Används under vintersäsongen.", + :en + "An outdoor rink that is mechanically or artificially cooled. Details about the size and equipment of the rink can be found in the additional information. Used during the winter season."}, + :tags {:fi ["luistelukenttä" "luistelu"]}, + :name + {:fi "Tekojääkenttä/tekojäärata", + :se "Konstis", + :en "Mechanically frozen open-air ice rink"}, + :type-code 1510, + :main-category 1000, + :status "active", + :sub-category 1500, + :geometry-type "Point", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :stand-capacity-person {:priority 70}, + :free-use? {:priority 40}, + :field-length-m {:priority 90}, + :match-clock? {:priority 70}, + :fields-count {:priority 80}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :ice-rinks-count {:priority 80}, + :toilet? {:priority 70}, + :changing-rooms? {:priority 70}, + :area-m2 {:priority 90}, + :field-width-m {:priority 90}, + :lighting-info {:priority 50}, + :changing-rooms-m2 {:priority 70}, + :customer-service-point? {:priority 70}, + :ligthing? {:priority 60}, + :school-use? {:priority 40}, + :light-roof? {:priority 70}}}, + 5350 + {:description + {:fi + "Pääasiallisesti kiihdytysautoiluun tai kiihdytysmoottoripyöräilyyn käytetty rata.", + :se "Huvudsakligen för accelerationskörning.", + :en "Mainly for drag racing."}, + :tags {:fi []}, + :name + {:fi "Kiihdytysrata", :se "Accelerationsbana", :en "Dragstrip"}, + :type-code 5350, + :main-category 5000, + :status "active", + :sub-category 5300, + :geometry-type "Point", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :automated-timing? {:priority 70}, + :stand-capacity-person {:priority 70}, + :free-use? {:priority 40}, + :track-width-m {:priority 90}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :area-m2 {:priority 90}, + :lighting-info {:priority 50}, + :year-round-use? {:priority 80}, + :scoreboard? {:priority 70}, + :loudspeakers? {:priority 70}, + :ligthing? {:priority 60}, + :covered-stand-person-count {:priority 70}, + :track-length-m {:priority 90}}}, + 2225 + {:description + {:fi + "Sisäleikkipuistot ovat yleensä pienille lapsille tarkoitettuja liikunnallisia leikkipaikkoja. Sisäaktiviteettipuistot ovat tyypillisesti lapsille ja nuorille tarkoitettuja liikuntakeskuksia, jotka sisältävät erilaisia liikunnallisia kohteita."}, + :tags {:fi []}, + :name {:fi "Sisäleikki-/sisäaktiviteettipuisto"}, + :type-code 2225, + :main-category 2000, + :status "active", + :sub-category 2200, + :geometry-type "Point", + :props + {:customer-service-point? {:priority 70}, + :height-m {:priority 90}, + :area-m2 {:priority 90}}}, + 4440 + {:description + {:fi + "Hiihtolatu, jossa on aina tai tiettyinä aikoina koirahiihto sallittua. Perinteinen tyyli tai vapaa tyyli.", + :se + "Ett skidspår där det alltid eller vissa tider är tillåtet att åka med hundspann. Klassisk stil eller fristil.", + :en + "Ski track on which dog skijoring is allowed either always or at given times. Traditional or free style."}, + :tags {:fi ["koiralatu"]}, + :name + {:fi "Koirahiihtolatu", + :se "Spår för hundspann", + :en "Dog skijoring track"}, + :type-code 4440, + :main-category 4000, + :status "active", + :sub-category 4400, + :geometry-type "LineString", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :free-use? {:priority 40}, + :ski-track-traditional? {:priority 80}, + :route-width-m {:priority 98}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :rest-places-count {:priority 70}, + :lit-route-length-km {:priority 97}, + :ski-track-freestyle? {:priority 80}, + :school-use? {:priority 40}, + :route-length-km {:priority 99}}}, + 2520 + {:description + {:fi + "Kilpajäähalli on jääurheilun kilpailu- ja ottelutapahtumiin soveltuva jäähalli. Katsomon koko, kenttien lukumäärä ja muut tarkemmat tiedot kuvataan lisätiedoissa.", + :se + "Läktare finns, storleken på läktaren anges i karakteristika, likaså antalet planer.", + :en + "Includes bleachers, whose size is specified in properties. Number of fields, heating, changing rooms, etc., specified in properties."}, + :tags {:fi ["jäähalli"]}, + :additional-type + {:small + {:fi "Pieni kilpahalli > 500 hlö", + :en "Small competition hall > 500 people", + :se "Liten tävlingshall > 500 personer"}, + :competition + {:fi "Kilpahalli < 3000 hlö", + :en "Competition hall < 3000 people", + :se "Tävlingshall < 3000 personer"}, + :large + {:fi "Suurhalli > 3000 hlö", + :en "Large hall > 3000 people", + :se "Större hall > 3000 personer"}}, + :name + {:fi "Kilpajäähalli", + :se "Tävlingsishall", + :en "Competition ice arena"}, + :type-code 2520, + :keywords {:fi ["Jäähalli"], :en [], :se []}, + :main-category 2000, + :status "active", + :sub-category 2500, + :geometry-type "Point", + :props + {:surface-material {:priority 79}, + :surface-material-info {:priority 78}, + :automated-timing? {:priority 70}, + :stand-capacity-person {:priority 70}, + :free-use? {:priority 40}, + :finish-line-camera? {:priority 70}, + :match-clock? {:priority 70}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :ice-rinks-count {:priority 80}, + :field-2-flexible-rink? {:priority 80}, + :toilet? {:priority 70}, + :area-m2 {:priority 90}, + :curling-lanes-count {:priority 80}, + :scoreboard? {:priority 70}, + :auxiliary-training-area? {:priority 80}, + :ringette-boundary-markings? {:priority 80}, + :field-1-flexible-rink? {:priority 80}, + :loudspeakers? {:priority 70}, + :school-use? {:priority 40}, + :field-3-flexible-rink? {:priority 80}}}, + 4710 + {:description + {:fi + "Rakennettu kiipeilyseinä ulkona, köysikiipeilyrata tai vastaava kiipeilyä varten rakennettu paikka. Myös rakennetut boulderointipaikat. Paikan tarkempi kuvaus ominaisuustietoihin.", + :se + "Byggd klättervägg utomhus, klätterbana eller annan plats byggd för klättring. Även platser för bouldering. Precisering i karakteristika.", + :en + "Built outdoor climbing wall, rope climbing path or other place built for climbing. Also bouldering venues. Clarification in 'properties'."}, + :tags {:fi ["kiipeilyseinä" "köysikiipeily"]}, + :name + {:fi "Ulkokiipeilypaikka", + :se "Utomhusklätterplats", + :en "Open-air climbing venue"}, + :type-code 4710, + :main-category 4000, + :status "active", + :sub-category 4700, + :geometry-type "Point", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :free-use? {:priority 40}, + :climbing-routes-count {:priority 80}, + :ice-climbing? {:priority 80}, + :climbing-wall-height-m {:priority 90}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :area-m2 {:priority 90}, + :lighting-info {:priority 60}, + :climbing-wall-width-m {:priority 90}, + :ligthing? {:priority 70}, + :school-use? {:priority 40}}}, + 304 + {:description + {:fi + "Tavallisen arkiliikunnan taukopaikka, päiväkäyttöön. Lisätietoihin merkitään kohteessa olevat palvelut, esim. kahvio, vuokrauspiste tai opastuspiste.", + :se "Rastplats för bruk under dagen, vardagsmotion.", + :en "Rest area for regular daily sports, for daytime use."}, + :tags {:fi ["tupa" "taukopaikka" "ulkoilumaja" "hiihtomaja"]}, + :name + {:fi "Ulkoilumaja/hiihtomaja", + :se "Friluftsstuga/skidstuga", + :en "Outdoor/ski lodge "}, + :type-code 304, + :main-category 0, + :status "active", + :sub-category 2, + :geometry-type "Point", + :props + {:toilet? {:priority 70}, + :may-be-shown-in-excursion-map-fi? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :customer-service-point? {:priority 70}, + :equipment-rental? {:priority 70}, + :free-use? {:priority 60}}}, + 4412 + {:description + {:fi + "Pyöräilyreitti, joka kulkee enimmäkseen päällystetyillä teillä tai sorateillä. Reitti voi olla merkitty maastoon tai se on digitaalisesti opastettu.", + :se "Cykelled, ej för mountainbikar.", + :en "Biking route, not intended for cross-country biking."}, + :tags {:fi []}, + :name {:fi "Pyöräilyreitti", :se "Cykelled", :en "Biking route"}, + :type-code 4412, + :main-category 4000, + :status "active", + :sub-category 4400, + :geometry-type "LineString", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :free-use? {:priority 40}, + :may-be-shown-in-excursion-map-fi? {:priority 0}, + :route-width-m {:priority 97}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :rest-places-count {:priority 70}, + :lit-route-length-km {:priority 98}, + :route-length-km {:priority 99}}}, + 4820 + {:description + {:fi + "Ampumarata jossa myös palveluita. SM-kisojen järjestäminen mahdollista.", + :se "Skjutbana med tjänster. Möjligt att arrangera FM-tävlingar.", + :en + "Shooting range with services. National competitions possible."}, + :tags {:fi ["ampumapaikka" "ammunta"]}, + :name + {:fi "Ampumaurheilukeskus", + :se "Sportskyttecentrum", + :en "Shooting sports centre"}, + :type-code 4820, + :main-category 4000, + :status "active", + :sub-category 4800, + :geometry-type "Point", + :props + {:stand-capacity-person {:priority 70}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :air-gun-shooting? {:priority 80}, + :toilet? {:priority 70}, + :pistol-shooting? {:priority 80}, + :shooting-positions-count {:priority 90}, + :area-m2 {:priority 90}, + :lighting-info {:priority 50}, + :rifle-shooting? {:priority 80}, + :year-round-use? {:priority 80}, + :scoreboard? {:priority 70}, + :loudspeakers? {:priority 70}, + :shotgun-shooting? {:priority 80}, + :free-rifle-shooting? {:priority 80}, + :ligthing? {:priority 60}, + :accessibility-info {:priority 40}, + :track-length-m {:priority 90}}}, + 1170 + {:description + {:fi "Ratapyöräilyä varten rakennettu paikka, ulkona (velodromi).", + :se "Utomhus, velodrom.", + :en "For track racing outdoors (velodrome)."}, + :tags {:fi ["velodromi"]}, + :name + {:fi "Pyöräilyrata/velodromi", :se "Velodrom", :en "Velodrome"}, + :type-code 1170, + :main-category 1000, + :status "active", + :sub-category 1100, + :geometry-type "Point", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :free-use? {:priority 50}, + :track-width-m {:priority 90}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :area-m2 {:priority 90}, + :lighting-info {:priority 60}, + :ligthing? {:priority 70}, + :school-use? {:priority 50}, + :track-length-m {:priority 90}}}, + 6150 + {:description + {:fi + "Islanninhevosten askellajiratsastukseen varattu rata ulkona.", + :se + "En bana utomhus avsedd för gångartstävlingar med islandshästar.", + :en + "An outdoor track designated for gaited riding competitions with Icelandic horses."}, + :tags + {:fi + ["islanninhevosrata" + "islanninhevosratsastus" + "ovaalibaana" + "askellajiratsastus" + "askellajirata"], + :se + ["islandshästbana" + "islandshästridning" + "ovalbana" + "gångartstävling" + "gångartsbana"], + :en + ["Icelandic horse track" + "Icelandic horse riding" + "oval track" + "gaited riding" + "gaited track"]}, + :name {:fi "Ovaalirata", :se "Ovalbana", :en "Oval Track"}, + :type-code 6150, + :main-category 6000, + :status "active", + :sub-category 6100, + :geometry-type "Point", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :free-use? {:priority 40}, + :track-width-m {:priority 90}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :customer-service-point? {:priority 70}, + :ligthing? {:priority 60}, + :track-length-m {:priority 90}}}, + 4404 + {:description + {:fi + "Erityisesti luontoharrastusta varten rakennettu ulkoilureitti. Reitin varrella opasteita tai infotauluja alueen luonnosta.", + :se + "I synnerhet för naturintresse, info- och orienteringstavlor längs leden.", + :en + "Intended particularly for nature activities; signposts or info boards along the route."}, + :tags {:fi ["retkeily"]}, + :name {:fi "Luontopolku", :se "Naturstig", :en "Nature trail"}, + :type-code 4404, + :main-category 4000, + :status "active", + :sub-category 4400, + :geometry-type "LineString", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :free-use? {:priority 40}, + :may-be-shown-in-excursion-map-fi? {:priority 0}, + :route-width-m {:priority 97}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :rest-places-count {:priority 70}, + :lit-route-length-km {:priority 98}, + :accessibility-info {:priority 40}, + :school-use? {:priority 40}, + :route-length-km {:priority 99}}}, + 108 + {:description + {:fi + "Metsähallituksen päätöksellä perustettu virkistysmetsä. Metsätaloudessa huomioidaan mm. maisemalliset arvot. Metsähallitus tietolähde.", + :se + "Grundad enligt Forststyrelsens beslut. I skogsbruket tas hänsyn till bl a landskapsvärden. Källa: Forststyrelsen.", + :en + "Recreational forest designated by Metsähallitus. E.g. scenic value is considered in forestry. Source of information Metsähallitus."}, + :tags {:fi []}, + :name + {:fi "Virkistysmetsä", + :se "Friluftsskog", + :en "Recreational forest"}, + :type-code 108, + :main-category 0, + :status "deprecated", + :sub-category 1, + :geometry-type "Polygon", + :props + {:area-km2 {:priority 90}, + :school-use? {:priority 70}, + :free-use? {:priority 70}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, + 4401 + {:description + {:fi + "Kuntoiluun tarkoitettu hoidettu liikuntareitti asutuksen läheisyydessä. Usein ainakin osittain valaistu.", + :se "Led avsedd för konditionssport i närheten av bebyggelse.", + :en "Route intended for jogging in or near a residential area."}, + :tags {:fi ["pururata"]}, + :name {:fi "Kuntorata", :se "Konditionsbana", :en "Jogging track"}, + :type-code 4401, + :main-category 4000, + :status "active", + :sub-category 4400, + :geometry-type "LineString", + :props + {:surface-material {:priority 89}, + :surface-material-info {:priority 88}, + :free-use? {:priority 40}, + :may-be-shown-in-excursion-map-fi? {:priority 0}, + :outdoor-exercise-machines? {:priority 80}, + :route-width-m {:priority 97}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :rest-places-count {:priority 70}, + :shooting-positions-count {:priority 80}, + :lit-route-length-km {:priority 98}, + :accessibility-info {:priority 40}, + :school-use? {:priority 40}, + :route-length-km {:priority 99}}}, + 2350 + {:description + {:fi + "Pysyvästi tanssi-, ilmaisu- tai ryhmäliikuntaan varustettu itsenäinen tila, joka ei ole osa esim. kuntokeskusta. Myös boutique-, fitness- ja mikrostudiot ovat tanssi- tai ryhmäliikuntatiloja.", + :se "Permanent utrustning för dans och kreativ motion.", + :en + "Space permanently equipped for dance or expressive movement exercise."}, + :tags {:fi ["peilisali" "baletti" "tanssisali"]}, + :name + {:fi "Tanssi-/ryhmäliikuntatila", + :se "Utrymme för dans", + :en "Dance studio"}, + :type-code 2350, + :main-category 2000, + :status "active", + :sub-category 2300, + :geometry-type "Point", + :props + {:height-m {:priority 90}, + :surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :free-use? {:priority 40}, + :active-space-width-m {:priority 90}, + :mirror-wall? {:priority 70}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :group-exercise-rooms-count {:priority 80}, + :area-m2 {:priority 90}, + :active-space-length-m {:priority 90}, + :school-use? {:priority 40}}}, + 2340 + {:description + {:fi "Pysyvästi miekkailuun varustettu tila.", + :se "Permanent utrustning för fäktning.", + :en "Space permanently equipped for fencing."}, + :tags {:fi []}, + :name + {:fi "Miekkailutila", + :se "Utrymme för fäktning", + :en "Fencing venue"}, + :type-code 2340, + :main-category 2000, + :status "active", + :sub-category 2300, + :geometry-type "Point", + :props + {:height-m {:priority 90}, + :surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :free-use? {:priority 40}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :area-m2 {:priority 90}, + :fencing-bases-count {:priority 80}, + :school-use? {:priority 40}}}, + 2120 + {:description + {:fi + "Liikuntatila, jossa on useita kuntosalilaitteita pysyvästi sijoitettuna.", + :se "Gymredskap osv. Storleken anges i karakteristika.", + :en "Gym equipment, etc. Size specified in properties."}, + :tags {:fi ["kuntoilu" "voimailu"]}, + :name {:fi "Kuntosali", :se "Gym", :en "Gym"}, + :type-code 2120, + :main-category 2000, + :status "active", + :sub-category 2100, + :geometry-type "Point", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :free-customer-use? {:priority 40}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :group-exercise-rooms-count {:priority 80}, + :area-m2 {:priority 90}, + :weight-lifting-spots-count {:priority 80}, + :customer-service-point? {:priority 70}, + :spinning-hall? {:priority 80}, + :school-use? {:priority 40}, + :exercise-machines-count {:priority 80}}}, + 109 + {:description + {:fi + "Ulkoilulailla perustetut, retkeilyä ja luonnon virkistyskäyttöä varten. Metsähallitus tietolähteenä.", + :se + "Grundat enligt lagen om friluftsliv för att användas för friluftsliv och rekreation i naturen. Källa: Forststyrelsen.", + :en + "Established based on the Outdoor Recreation Act for hiking and recreational use of nature. Source of information Metsähallitus."}, + :tags {:fi []}, + :name + {:fi "Valtion retkeilyalue", + :se "Statens friluftsområde", + :en "National hiking area"}, + :type-code 109, + :main-category 0, + :status "active", + :sub-category 1, + :geometry-type "Polygon", + :props + {:area-km2 {:priority 90}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, + 1650 + {:description + {:fi + "Ensisijaisesti golfin pelaamiseen tarkoitettu alue kesäkaudella. Reikien määrä merkitään lisätietoihin.", + :se "Officiell golfbana. Antalet hål anges i karakteristika.", + :en + "Official golf course. Number of holes included in properties."}, + :tags {:fi ["greeni" "puttialue" "range"]}, + :name {:fi "Golfkenttä (alue)", :se "Golfbana", :en "Golf course"}, + :type-code 1650, + :main-category 1000, + :status "active", + :sub-category 1600, + :geometry-type "Polygon", + :props + {:holes-count {:priority 90}, + :free-use? {:priority 40}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :lighting-info {:priority 50}, + :customer-service-point? {:priority 70}, + :green? {:priority 80}, + :ligthing? {:priority 60}, + :school-use? {:priority 40}, + :range? {:priority 80}}}, + 4441 + {:description + {:fi "Koiravaljakoille ylläpidetty reitti.", + :se "En rutt underhållen för hundspann.", + :en "A route maintained for dog sledding."}, + :tags {:fi ["valjakkoajo" "valjakkoreitti"], :se [], :en []}, + :name + {:fi "Koiravaljakkoreitti", + :se "Hundspannsrutt", + :en "Dog Sledding Route"}, + :type-code 4441, + :main-category 4000, + :status "active", + :sub-category 4400, + :geometry-type "LineString", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :route-length-km {:priority 99}, + :lit-route-length-km {:priority 97}, + :route-width-m {:priority 98}, + :free-use? {:priority 40}, + :year-round-use? {:priority 80}}}, + 5160 + {:description + {:fi + "Soudun ja melonnan sisäharjoittelutila on erityisesti näihin lajeihin pysyvästi tarkoitettu liikuntapaikka.", + :se "Separat, ej normal bassäng.", + :en "Separate training facility, not a regular swimming pool."}, + :tags {:fi ["kajakki" "kanootti" "melonta"]}, + :name + {:fi "Soudun ja melonnan sisäharjoittelutila", + :se "Inomhusträningsutrymme för rodd och paddling", + :en "Indoor training facility for rowing and canoeing"}, + :type-code 5160, + :main-category 5000, + :status "active", + :sub-category 5100, + :geometry-type "Point", + :props + {:area-m2 {:priority 90}, + :free-use? {:priority 40}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, + 1550 + {:description + {:fi + "Luisteluun tarkoitettu luonnonjäälle tai maalle rakennettava huollettu luistelureitti. Rakennetaan talvisin samalle alueelle. ", + :se + "Byggs varje vinter på samma område t ex i en idrottspark eller på havsis.", + :en + "Built yearly in the same area, e.g., in a sports park or on frozen lake/sea."}, + :tags {:fi ["luistelu" "retkiluistelu" "retkiluistelurata"]}, + :name + {:fi "Luistelureitti", :se "Skridskoled", :en "Ice-skating route"}, + :type-code 1550, + :main-category 1000, + :status "active", + :sub-category 1500, + :geometry-type "Point", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :free-use? {:priority 40}, + :may-be-shown-in-excursion-map-fi? {:priority 0}, + :track-width-m {:priority 90}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :lighting-info {:priority 50}, + :equipment-rental? {:priority 70}, + :customer-service-point? {:priority 70}, + :ligthing? {:priority 60}, + :school-use? {:priority 40}, + :track-length-m {:priority 90}}}, + 3230 + {:description + {:fi + "Pieni yleinen uimaranta tai uimapaikka, jossa pelastusväline ja ilmoitustaulu. Veden laadun seuranta ja alueen hoito järjestetty.", + :se + "Liten allmän badstrand eller badplats. Räddningsutrustning och en anslagstavla finns. Kvaliteten på vattnet följs upp och området underhålls.", + :en + "Small public beach or swimming site. Rescue equipment and a notice board are available. The quality of the water is monitored and the area is maintained."}, + :tags {:fi ["uimaranta"]}, + :name {:fi "Uimapaikka", :se "Badplats", :en "Swimming site"}, + :type-code 3230, + :main-category 3000, + :status "active", + :sub-category 3200, + :geometry-type "Point", + :props + {:free-use? {:priority 40}, + :pier? {:priority 80}, + :may-be-shown-in-excursion-map-fi? {:priority 0}, + :beach-length-m {:priority 80}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :shower? {:priority 70}, + :changing-rooms? {:priority 70}, + :sauna? {:priority 70}, + :other-platforms? {:priority 80}, + :school-use? {:priority 40}}}, + 5130 + {:description + {:fi "Pysyvä moottorivenekilpailujen rata-alue.", + :se "Permanent banområde för hastighetstävlingar.", + :en "Permanent track area for speed competitions."}, + :tags {:fi []}, + :name + {:fi "Moottoriveneurheilualue", + :se "Område för motorbåtsport", + :en "Motor boat sports area"}, + :type-code 5130, + :main-category 5000, + :status "active", + :sub-category 5100, + :geometry-type "Point", + :props + {:pier? {:priority 80}, + :area-km2 {:priority 90}, + :boat-places-count {:priority 80}, + :free-use? {:priority 40}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, + 5110 + {:description + {:fi + "Soutustadion sisältää pysyvästi soutuun käytettäviä rakenteita. Soutustadionissa on katsomo ja valmius ratamerkintöihin.", + :se + "Byggt för rodd, permanent. Läktare och förberett för banmärkning.", + :en + "Permanent construction for rowing. Bleachers, track markings possible."}, + :tags {:fi []}, + :name + {:fi "Soutustadion", :se "Roddstadion", :en "Rowing stadium"}, + :type-code 5110, + :main-category 5000, + :status "active", + :sub-category 5100, + :geometry-type "Point", + :props + {:automated-timing? {:priority 70}, + :stand-capacity-person {:priority 70}, + :free-use? {:priority 40}, + :pier? {:priority 80}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :area-m2 {:priority 90}, + :scoreboard? {:priority 70}, + :track-length-m {:priority 90}}}, + 3240 + {:description + {:fi + "Talviuintipaikka voi sijaita avannossa, avovedessä tai maauimalassa talvikaudella. Talviuintipaikka merkitään omaksi liikuntapaikakseen.", + :se + "Vinterbadplats kan vara belägen i en vak, öppet vatten eller utomhuspool. Vinterbadplats är markerad som egen idrottsanläggning", + :en + "Winter swimming area may be located in an ice hole, open water or open air pool. Winter swimming area is marked as its own sports facility."}, + :tags {:fi ["avanto" "avantouinti" "talviuinti"]}, + :name + {:fi "Talviuintipaikka", + :se "Vinterbadplats", + :en "Winter swimming area"}, + :type-code 3240, + :main-category 3000, + :status "active", + :sub-category 3200, + :geometry-type "Point", + :props + {:free-use? {:priority 40}, + :pier? {:priority 80}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :shower? {:priority 70}, + :changing-rooms? {:priority 70}, + :ice-reduction? {:priority 70}, + :sauna? {:priority 70}, + :school-use? {:priority 40}}}, + 4510 + {:description + {:fi + "Suunnistukseen käytetty alue. Lisätietoihin merkitään, jos aluetta käytetään mobo-, pyörä- tai hiihtosuunnistukseen. Suunnistusalueesta on saatavilla kartta ja maankäyttöön on maanomistajan suostumus.", + :se + "Anmält till orienteringsförbundet. Karta över området tillgänglig.", + :en + "The Finnish Orienteering Federation has been informed. A map of the area available."}, + :tags {:fi []}, + :name + {:fi "Suunnistusalue", + :se "Orienteringsområde", + :en "Orienteering area"}, + :type-code 4510, + :main-category 4000, + :status "active", + :sub-category 4500, + :geometry-type "Polygon", + :props + {:area-km2 {:priority 90}, + :school-use? {:priority 40}, + :free-use? {:priority 40}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :mobile-orienteering? {:priority 80}, + :bike-orienteering? {:priority 80}, + :ski-orienteering? {:priority 80}}}, + 4240 + {:description + {:fi "Katettu laskettelurinne.", + :se + "Slalombacke med tak. Höjdskillnad och längd i karakteristika.", + :en + "Covered ski slope. Height and length specified in attributes."}, + :tags {:fi []}, + :name + {:fi "Lasketteluhalli", + :se "Slalomhall", + :en "Downhill skiing hall"}, + :type-code 4240, + :main-category 4000, + :status "active", + :sub-category 4200, + :geometry-type "Point", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :free-use? {:priority 40}, + :ski-service? {:priority 70}, + :altitude-difference {:priority 90}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :area-m2 {:priority 90}, + :equipment-rental? {:priority 70}, + :route-length-km {:priority 99}}}, + 2270 + {:description + {:fi + "Ensisijaisesti squashin pelaamiseen tarkoitettu halli. Yksittäisen kentän mitat 9,75 m x 6,4 m. Vapaa korkeus ja pintamateriaali ilmoitetaan lisätiedoissa.", + :se + "En eller flera squashplaner. Antalet planer i karakteristika.", + :en + "One or more squash courts. Number of courts specified in properties."}, + :tags + {:fi ["squash" "squash-kenttä" "squashkenttä" "squashhalli"]}, + :name {:fi "Squash-halli", :se "Squashhall", :en "Squash hall"}, + :type-code 2270, + :main-category 2000, + :status "active", + :sub-category 2200, + :geometry-type "Point", + :props + {:height-m {:priority 90}, + :surface-material {:priority 89}, + :surface-material-info {:priority 88}, + :stand-capacity-person {:priority 80}, + :free-use? {:priority 40}, + :tennis-courts-count {:priority 80}, + :field-length-m {:priority 90}, + :badminton-courts-count {:priority 80}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :padel-courts-count {:priority 80}, + :toilet? {:priority 70}, + :area-m2 {:priority 90}, + :field-width-m {:priority 90}, + :scoreboard? {:priority 70}, + :floorball-fields-count {:priority 80}, + :squash-courts-count {:priority 80}, + :customer-service-point? {:priority 70}, + :volleyball-fields-count {:priority 80}, + :school-use? {:priority 40}}}, + 4210 + {:description + {:fi + "Pysyvästi lajiin varustettu tila, esim. curlingrata tai curlinghalli.", + :se "Curlingbana med tak och permanent utrustning för grenen.", + :en "Covered track permanently equipped for curling."}, + :tags {:fi ["curlinghalli" "curling-halli" "curling-rata"]}, + :name + {:fi "Curlingrata/-halli", :se "Curlingbana", :en "Curling sheet"}, + :type-code 4210, + :main-category 4000, + :status "active", + :sub-category 4200, + :geometry-type "Point", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :stand-capacity-person {:priority 70}, + :free-use? {:priority 40}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :changing-rooms? {:priority 70}, + :area-m2 {:priority 90}, + :curling-lanes-count {:priority 90}, + :changing-rooms-m2 {:priority 70}}}, + 301 + {:description + {:fi + "Päiväsaikainen levähdyspaikka retkeilijöille. Esimerkiksi kodalla tarkoitetaan kotamallista sääsuojaa tai levähdyspaikkaa ja laavu on kaltevakattoinen sääsuoja, joka sisältää tulipaikan. Lisätietoihin merkitään tieto tulentekopaikasta.", + :se "Viloplats för vandrare under dagtid.", + :en "Daytime rest stop for hikers."}, + :tags {:fi ["taukopaikka"]}, + :name + {:fi "Laavu, kota tai kammi", + :se "Vindskydd eller kåta", + :en "Lean-to, goahti (Lapp tent shelter) or 'kammi' earth lodge"}, + :type-code 301, + :main-category 0, + :status "active", + :sub-category 2, + :geometry-type "Point", + :props + {:may-be-shown-in-excursion-map-fi? {:priority 0}, + :toilet? {:priority 70}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :water-point {:priority 70}, + :free-use? {:priority 60}}}, + 111 + {:description + {:fi + "Kansallispuistot ovat luonnonsuojelualueita, joiden perustamisesta ja tarkoituksesta on säädetty lailla. Kansallispuistoissa on merkittyjä reittejä, luontopolkuja ja tulentekopaikkoja. Kansallispuistoissa voi myös yöpyä, sillä niissä on telttailualueita tai yöpymiseen tarkoitettuja rakennuksia. LIPAS-aineisto perustuu Metsähallituksen tietoihin.", + :se + "Naturskyddsområden med lagstadgad status och uppgift. Areal minst 1000 ha. Källa: Forststyrelsen.", + :en + "Nature conservation areas whose establishment and purpose are based on legislation. Min. area 1,000 ha. Source of information Metsähallitus."}, + :tags {:fi []}, + :name + {:fi "Kansallispuisto", :se "Nationalpark", :en "National park"}, + :type-code 111, + :main-category 0, + :status "active", + :sub-category 1, + :geometry-type "Polygon", + :props + {:area-km2 {:priority 90}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, + 4630 + {:description + {:fi + "Hiihtokilpailujen järjestämiseen soveltuva kisakeskus, jossa on esimerkiksi lähtö- ja maalialue, huoltotilat ja riittävä latuverkosto.", + :se "Start- och målområden, serviceutrymmen, spårsystem.", + :en "Start and finish area, service premises. Tracks."}, + :tags {:fi ["hiihtostadion"]}, + :name + {:fi "Kilpahiihtokeskus", + :se "Maastohiihtokeskus", + :en "Ski competition centre"}, + :type-code 4630, + :main-category 4000, + :status "active", + :sub-category 4600, + :geometry-type "Point", + :props + {:stand-capacity-person {:priority 70}, + :free-use? {:priority 40}, + :ski-service? {:priority 70}, + :finish-line-camera? {:priority 70}, + :ski-track-traditional? {:priority 80}, + :route-width-m {:priority 98}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :shower? {:priority 70}, + :rest-places-count {:priority 70}, + :changing-rooms? {:priority 70}, + :lit-route-length-km {:priority 97}, + :scoreboard? {:priority 70}, + :sauna? {:priority 70}, + :loudspeakers? {:priority 70}, + :accessibility-info {:priority 40}, + :ski-track-freestyle? {:priority 80}, + :route-length-km {:priority 99}}}, + 4810 + {:description + {:fi "Ulkoampumarata yhdelle tai useammalle lajille.", + :se "Utomhusskjutbana för en eller flera grenar.", + :en "Outdoor shooting range for one or more sports. "}, + :tags {:fi ["ampumapaikka" "ammunta"]}, + :name + {:fi "Ampumarata", :se "Skjutbana", :en "Open-air shooting range"}, + :type-code 4810, + :main-category 4000, + :status "active", + :sub-category 4800, + :geometry-type "Point", + :props + {:stand-capacity-person {:priority 70}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :air-gun-shooting? {:priority 80}, + :toilet? {:priority 70}, + :pistol-shooting? {:priority 80}, + :shooting-positions-count {:priority 90}, + :area-m2 {:priority 90}, + :lighting-info {:priority 50}, + :rifle-shooting? {:priority 80}, + :year-round-use? {:priority 70}, + :scoreboard? {:priority 70}, + :loudspeakers? {:priority 70}, + :shotgun-shooting? {:priority 80}, + :free-rifle-shooting? {:priority 80}, + :ligthing? {:priority 60}, + :accessibility-info {:priority 40}, + :track-length-m {:priority 90}}}, + 1540 + {:description + {:fi + "Pikaluisteluun varusteltu luistelurata. Radan koko ja pituus lisätään ominaisuustietoihin. Käytössä talvikaudella.", + :se "Bana för hastighetsåkning. Används under vintersäsongen.", + :en "Track size and length specified in properties."}, + :tags {:fi ["luistelurata"]}, + :name + {:fi "Pikaluistelurata", + :se "Bana för hastighetsåkning på skridsko", + :en "Speed-skating track"}, + :type-code 1540, + :main-category 1000, + :status "active", + :sub-category 1500, + :geometry-type "Point", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :stand-capacity-person {:priority 70}, + :free-use? {:priority 40}, + :track-width-m {:priority 90}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :area-m2 {:priority 90}, + :lighting-info {:priority 50}, + :changing-rooms-m2 {:priority 70}, + :customer-service-point? {:priority 70}, + :ligthing? {:priority 60}, + :school-use? {:priority 40}, + :track-length-m {:priority 90}}}, + 5320 + {:description + {:fi + "Pääasiassa moottoripyöräilyä varten rakennettu, luonnonmukainen ei-asfalttipintainen alue (esim. enduroreitit ja trial-harjoittelualueet maastoliikennealueilla).", + :se "Huvudsakligen för motorcykelsport.", + :en "Mainly for motorcycling."}, + :tags {:fi ["motocross"]}, + :name + {:fi "Moottoripyöräilyalue", + :se "Område för motorcykelsport", + :en "Motorcycling area"}, + :type-code 5320, + :main-category 5000, + :status "active", + :sub-category 5300, + :geometry-type "Point", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :automated-timing? {:priority 70}, + :stand-capacity-person {:priority 70}, + :free-use? {:priority 40}, + :track-width-m {:priority 90}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :area-m2 {:priority 90}, + :lighting-info {:priority 50}, + :year-round-use? {:priority 80}, + :scoreboard? {:priority 70}, + :loudspeakers? {:priority 70}, + :ligthing? {:priority 60}, + :covered-stand-person-count {:priority 70}, + :track-length-m {:priority 90}}}, + 3210 + {:description + {:fi + "Maauimala tai vesipuisto on ulkona sijaitseva, vedenpuhdistusjärjestelmällä varustettu uintiin tarkoitettu ja hoidettu vesistö tai uima-altaita/allas. Lisäksi kohteessa voi olla vesiliukumäkiä.", + :se "Vattenreningssystem.", + :en "Water treatment system."}, + :tags {:fi ["uima-allas" "ulkoallas" "ulkouima-allas"]}, + :name + {:fi "Maauimala/vesipuisto", + :se "Utebassäng", + :en "Open-air pool "}, + :type-code 3210, + :main-category 3000, + :status "active", + :sub-category 3200, + :geometry-type "Point", + :props + {:pool-tracks-count {:priority 87}, + :stand-capacity-person {:priority 70}, + :free-use? {:priority 40}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :pool-width-m {:priority 89}, + :pool-min-depth-m {:priority 80}, + :toilet? {:priority 70}, + :swimming-pool-count {:priority 90}, + :pool-water-area-m2 {:priority 90}, + :pool-length-m {:priority 88}, + :pool-max-depth-m {:priority 80}, + :loudspeakers? {:priority 70}, + :pool-temperature-c {:priority 80}, + :school-use? {:priority 40}}}, + 4640 + {:description + {:fi + "Hiihdon opetteluun ja harjoitteluun tarkoitettu paikka erityisesti lapsille. Erilaisia harjoittelupaikkoja, kuten latuja, mäkiä ym.", + :se "Träningsplats för skidåkning, teknikhaster mm.", + :en + "Ski training venue, an area of parallel short ski tracks for ski instruction, etc."}, + :tags {:fi []}, + :name + {:fi "Hiihtomaa", :se "Skidland", :en "Cross-country ski park"}, + :type-code 4640, + :main-category 4000, + :status "active", + :sub-category 4600, + :geometry-type "Point", + :props + {:free-use? {:priority 40}, + :ski-service? {:priority 70}, + :ski-track-traditional? {:priority 80}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :rest-places-count {:priority 70}, + :lit-route-length-km {:priority 98}, + :scoreboard? {:priority 70}, + :equipment-rental? {:priority 70}, + :loudspeakers? {:priority 70}, + :accessibility-info {:priority 0}, + :ski-track-freestyle? {:priority 80}, + :school-use? {:priority 40}, + :route-length-km {:priority 99}}}, + 1150 + {:description + {:fi + "Rullaluistelua, skeittausta, potkulautailua varten varustettu paikka. Ominaisuustiedoissa tarkemmat tiedot kohteesta.", + :se + "Plats utrustad för rullskridskoåkning, skejtning och sparkcykelåkning.", + :en + "An area equipped for roller-blading, skateboarding, kick scooting."}, + :tags + {:fi ["ramppi" "skeittipaikka" "skeittipuisto" "skeittiparkki"]}, + :name + {:fi "Skeitti-/rullaluistelupaikka", + :se "Plats för skejtning/rullskridskoåkning", + :en "Skateboarding/roller-blading rink "}, + :type-code 1150, + :main-category 1000, + :status "active", + :sub-category 1100, + :geometry-type "Point", + :props + {:area-m2 {:priority 90}, + :surface-material-info {:priority 80}, + :surface-material {:priority 80}, + :ligthing? {:priority 70}, + :school-use? {:priority 50}, + :free-use? {:priority 50}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :lighting-info {:priority 60}}}, + 2310 + {:description + {:fi + "Yksittäinen yleisurheilun olosuhde sisätiloissa esim. liikunta- tai monitoimihallin yhteydessä. Suorituspaikat kuvataan lisätiedoissa.", + :se + "Fristående, ej i anslutning till en friidrottshall. I karakteristika anges övningsplatserna.", + :en + "Stand-alone, not in an athletics hall. Venues specified under properties."}, + :tags {:fi ["yleisurheilu" "juoksurata"]}, + :name + {:fi "Yksittäinen yleisurheilun suorituspaikka", + :se "Enstaka övningsplats för friidrott", + :en "Stand-alone athletics venue"}, + :type-code 2310, + :main-category 2000, + :status "active", + :sub-category 2300, + :geometry-type "Point", + :props + {:height-m {:priority 90}, + :surface-material {:priority 89}, + :surface-material-info {:priority 88}, + :free-use? {:priority 40}, + :javelin-throw-places-count {:priority 80}, + :sprint-track-length-m {:priority 80}, + :inner-lane-length-m {:priority 80}, + :discus-throw-places {:priority 80}, + :hammer-throw-places-count {:priority 80}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :polevault-places-count {:priority 80}, + :area-m2 {:priority 90}, + :shotput-count {:priority 80}, + :longjump-places-count {:priority 80}, + :school-use? {:priority 40}, + :highjump-places-count {:priority 80}}}, + 5210 + {:description + {:fi + "Harraste- tai urheiluilmailuun tarkoitettu alue, esim. lentopaikka.", + :se "Flygsportarena, t ex en flygplats.", + :en "Area for air sports, e.g. an airfield."}, + :tags + {:fi + ["lentäminen" + "lento" + "lentokone" + "ilmailu" + "ilmailualue" + "lentokenttä"]}, + :name + {:fi "Urheiluilmailualue", + :se "Område för flygsport", + :en "Sport aviation area"}, + :type-code 5210, + :main-category 5000, + :status "active", + :sub-category 5200, + :geometry-type "Point", + :props + {:track-length-m {:priority 90}, + :area-m2 {:priority 90}, + :surface-material-info {:priority 80}, + :surface-material {:priority 80}, + :track-width-m {:priority 90}, + :free-use? {:priority 40}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, + 2380 + {:description + {:fi "Parkouria varten varustettu sisätila.", + :se "Inomhusutrymme utrustat för parkour.", + :en "Indoor space equipped for parkour. "}, + :tags {:fi ["parkour"]}, + :name {:fi "Parkour-sali", :se "Parkoursal", :en "Parkour hall"}, + :type-code 2380, + :main-category 2000, + :status "active", + :sub-category 2300, + :geometry-type "Point", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :free-use? {:priority 40}, + :parkour-hall-equipment-and-structures {:priority 80}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :area-m2 {:priority 90}, + :highest-obstacle-m {:priority 80}, + :auxiliary-training-area? {:priority 70}, + :school-use? {:priority 40}}}, + 103 + {:description + {:fi + "Voivat sijaita taajaman reunoilla, vyöhykkeittäin taajaman sisällä tai taajaman ulkopuolella. Kohteissa voi olla myös taajamasta lähteviä tai taajamaan palaavia reittejä tai polku- ja reittiverkosto. Kohteet sisältävät vaihtelevaa maastoa ja luonnonmukaisia tai puistomaisia alueita. Kohteet voivat myös sijaita vesialuiden lähellä kuten rannoilla tai saarissa. Kohteiden pääasiallinen käyttö on retkeilyä ja luonnossa virkistäytymistä, mutta niitä voidaan käyttää monipuolisesti erilaisen liikunnan kuten hiihdon, lenkkeilyn tai uinnin harrastamiseen. Kaavamerkintä esim. VR. HUOM! Uusien liikunta- ja ulkoilupaikkojen lisäksi Ulkoilu-/virkistysalueluokka sisältää ennen vuotta 2024 Ulkoilualueet ja Retkeilyalueet tyyppiluokkiin lisätyt olosuhteet", + :se + "Området befinner sig i utkanten av tätorter eller i zoner inom tätorten. På 1-10 kilometers avstånd från bebyggelse. Friluftsområdet används för t.ex. promenader, skidning, joggning, simning. Serverar oftast friluftsaktiviteter för en kommun. Området erbjuder en stor variation av motions möjligheter. Området kan bestå av skog, kärr, åkrar, naturenliga områden och parkliknande delar. Planbeteckning VR.", + :en + "On the edge of population centres or zoned within population centres. 1-10 km from residential areas. Used for e.g. walks, skiing, jogging, swimming. Serves usually recreational needs within one municipality, offers versatile sports facilities. May include forest, swamp, fields, natural areas and park areas. Symbol VR."}, + :tags {:fi ["puisto" "virkistysalue"]}, + :name + {:fi "Ulkoilu-/virkistysalue", + :se "Friluftsområde", + :en "Outdoor area"}, + :type-code 103, + :main-category 0, + :status "active", + :sub-category 1, + :geometry-type "Polygon", + :props + {:may-be-shown-in-excursion-map-fi? {:priority 0}, + :area-km2 {:priority 90}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :water-point {:priority 80}}}, + 201 + {:description + {:fi + "Vapaa-ajankalastukseen sopiva kohde. Kohteessa voi olla palvelurakenteita.", + :se + "Område eller en plats i ett naturligt vattendrag som ställts i ordning för fritidsfiske.", + :en + "Natural aquatic destination equipped and maintained for recreational fishing."}, + :tags {:fi ["kalastusalue" "kalastuspaikka"]}, + :name + {:fi "Kalastuskohde (piste)", + :se "Område eller plats för fiske", + :en "Fishing area/spot "}, + :type-code 201, + :main-category 0, + :status "active", + :sub-category 2, + :geometry-type "Point", + :props + {:toilet? {:priority 80}, + :free-use? {:priority 70}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :pier? {:priority 80}, + :customer-service-point? {:priority 80}, + :equipment-rental? {:priority 80}}}, + 1220 + {:description + {:fi + "Hyvin varusteltu yleisurheilukenttä. Yleissurheilukentällä on ratoja ja yleisurheilun suorituspaikkoja. Myös kisakäyttö on mahdollista. Lyhytrataiset (juoksurata alle 400 m) yleisurheilukentät tallennettaan yleisurheilun harjoitusalueeksi. Yleisurheilukentällä sijaitseva jalkapallon tai muun lajin keskeinen suorituspaikka merkitään omaksi liikuntapaikakseen (esim. jalkapallostadion tai pallokenttä). ", + :se + "En plan, banor och träningsplatser för friidrott. Centrum, banor, ytbeläggningar samt träningsplatser med beskrivningar.", + :en + "Field, track and athletic venues/facilities. Centre, tracks, surfaces, venues specified in properties. "}, + :tags + {:fi + ["keihäs" + "keihäänheitto" + "moukari" + "pituushyppy" + "juoksurata" + "kolmiloikka" + "seiväs" + "kuula" + "urheilukenttä"]}, + :name + {:fi "Yleisurheilukenttä", + :se "Friidrottsplan", + :en "Athletics field"}, + :type-code 1220, + :main-category 1000, + :status "active", + :sub-category 1200, + :geometry-type "Point", + :props + {:heating? {:priority 70}, + :surface-material {:priority 89}, + :surface-material-info {:priority 88}, + :automated-timing? {:priority 70}, + :stand-capacity-person {:priority 70}, + :free-use? {:priority 40}, + :sprint-lanes-count {:priority 80}, + :javelin-throw-places-count {:priority 80}, + :finish-line-camera? {:priority 70}, + :field-length-m {:priority 90}, + :circular-lanes-count {:priority 80}, + :match-clock? {:priority 70}, + :sprint-track-length-m {:priority 80}, + :inner-lane-length-m {:priority 80}, + :discus-throw-places {:priority 80}, + :hammer-throw-places-count {:priority 80}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :polevault-places-count {:priority 80}, + :toilet? {:priority 70}, + :running-track-surface-material {:priority 80}, + :area-m2 {:priority 90}, + :field-width-m {:priority 90}, + :lighting-info {:priority 50}, + :scoreboard? {:priority 70}, + :shotput-count {:priority 80}, + :longjump-places-count {:priority 80}, + :loudspeakers? {:priority 70}, + :customer-service-point? {:priority 70}, + :ligthing? {:priority 60}, + :covered-stand-person-count {:priority 70}, + :school-use? {:priority 40}, + :highjump-places-count {:priority 80}, + :training-spot-surface-material {:priority 80}}}, + 4411 + {:description + {:fi + "Maastopyöräilyyn tarkoitettu reitti, joka kulkee vaihtelevassa maastossa ja on merkitty maastoon. Reitti voi hyödyntää muita olemassa olevia ulkoilureittipohjia.", + :se "Led avsedd framför allt för mountainbikar, märkt.", + :en "Marked route intended especially for cross-country biking."}, + :tags {:fi []}, + :name + {:fi "Maastopyöräilyreitti", + :se "Mountainbikeled", + :en "Cross-country biking route"}, + :type-code 4411, + :main-category 4000, + :status "active", + :sub-category 4400, + :geometry-type "LineString", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :free-use? {:priority 40}, + :may-be-shown-in-excursion-map-fi? {:priority 0}, + :route-width-m {:priority 97}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :rest-places-count {:priority 70}, + :lit-route-length-km {:priority 98}, + :school-use? {:priority 40}, + :route-length-km {:priority 99}}}, + 1140 + {:description + {:fi "Parkouria varten varustettu alue.", + :se "Område utrustat för parkour.", + :en "An area equipped for parkour."}, + :tags {:fi []}, + :name + {:fi "Parkour-alue", :se "Parkourområde", :en "Parkour area"}, + :type-code 1140, + :main-category 1000, + :status "active", + :sub-category 1100, + :geometry-type "Point", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :free-use? {:priority 50}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :area-m2 {:priority 90}, + :lighting-info {:priority 60}, + :highest-obstacle-m {:priority 80}, + :ligthing? {:priority 70}, + :climbing-wall? {:priority 80}, + :school-use? {:priority 50}}}, + 4520 + {:description + {:fi + "Hiihtosuunnistukseen soveltuva alue, alueesta hiihtosuunnistuskartta saatavilla.", + :se + "Skidorienteringskarta över området, ej för sommarorientering.", + :en + "A ski orienteering map of the area available; no summer orienteering."}, + :tags {:fi []}, + :name + {:fi "Hiihtosuunnistusalue", + :se "Skidorienteringsområde", + :en "Ski orienteering area"}, + :type-code 4520, + :main-category 4000, + :status "deprecated", + :sub-category 4500, + :geometry-type "Polygon", + :props + {:area-km2 {:priority 90}, + :school-use? {:priority 40}, + :free-use? {:priority 40}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, + 107 + {:description + {:fi + "Matkailupalvelujen alueet ovat matkailua palveleville toiminnoille varattuja alueita, jotka sisältävät myös sisäiset liikenneväylät ja -alueet, alueen toimintoja varten tarpeelliset palvelut ja virkistysalueet sekä yhdyskuntateknisen huollon alueet. Kohteet voivat toimia myös retkeilyauto- ja pyörämatkailijoiden tauko- ja yöpymispaikkoina. Kaavamerkintä RM.", + :se + "Områden med turisttjänster har reserverats för turist- och semestercentra, semesterbyar, semesterhotell och motsvarande aktörer. De har egna trafikleder och -områden samt områden för egna serviceenheter och egen infrastruktur för aktiviteter. Planbeteckning RM.", + :en + "Area reserved for tourism and holiday centres, holiday villages, hotels, etc., also including internal traffic routes and areas; services and recreational areas needed for operations, as well as technical maintenance areas. Symbol RM."}, + :tags {:fi ["ulkoilualue" "virkistysalue" "leirintäalue"]}, + :name + {:fi "Matkailupalveluiden alue", + :se "Område med turisttjänster", + :en "Tourist services area"}, + :type-code 107, + :main-category 0, + :status "active", + :sub-category 1, + :geometry-type "Polygon", + :props + {:area-km2 {:priority 90}, + :free-use? {:priority 70}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 80}}}, + 6110 + {:description + {:fi "Ratsastukseen varustettu kenttä.", + :se "Bana avsedd för ridning. Storlek i karakteristika.", + :en + "Field reserved for horseback riding. Size specified in properties."}, + :tags {:fi []}, + :name + {:fi "Ratsastuskenttä", :se "Ridbana", :en "Equestrian field"}, + :type-code 6110, + :main-category 6000, + :status "active", + :sub-category 6100, + :geometry-type "Point", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :free-use? {:priority 40}, + :field-length-m {:priority 90}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :show-jumping? {:priority 80}, + :area-m2 {:priority 90}, + :field-width-m {:priority 90}, + :lighting-info {:priority 50}, + :ligthing? {:priority 60}, + :school-use? {:priority 40}}}, + 1120 + {:description + {:fi + "Lähiliikuntapaikka on tarkoitettu päivittäiseen ulkoiluun ja liikuntaan. Se sijaitsee asutuksen läheisyydessä, on pienimuotoinen ja alueelle on vapaa pääsy. Yleensä tarjolla on erilaisia suorituspaikkoja. Suorituspaikat tulee tallentaa omiksi liikuntapaikoikseen (esim. pallokenttä, ulkokuntosali tai parkour-alue). Lähiliikuntapaikka voi olla myös koulun tai päiväkodin piha, jos liikuntapaikan käyttö on mahdollista kouluajan ulkopuolella.", + :se + "Ett näridrottsområde är avsett för daglig utomhusaktivitet och motion. Det ligger nära bostadsområden, är småskaligt och har fri tillgång. Vanligtvis erbjuds olika aktivitetsplatser. Aktivitetsplatserna bör registreras som egna idrottsplatser (t.ex. bollplan, utomhusgym eller parkourområde). Ett näridrottsområde kan också vara en skolgård eller en daghemsgård om idrottsplatsen kan användas utanför skoltid.", + :en + "A local sports facility is intended for daily outdoor activities and exercise. It is located near residential areas, is small-scale, and has free access. Usually, various activity sites are available. Activity sites should be recorded as individual sports facilities (e.g., ball field, outdoor gym, or parkour area). A local sports facility can also be a school or daycare yard if the sports facility can be used outside school hours."}, + :tags + {:fi + ["ässäkenttä" "monitoimikenttä" "monitoimikaukalo" "lähipuisto"]}, + :name + {:fi "Lähiliikuntapaikka", + :se "Näridrottsplats", + :en "Neighbourhood sports area"}, + :type-code 1120, + :main-category 1000, + :status "active", + :sub-category 1100, + :geometry-type "Point", + :props + {:surface-material {:priority 90}, + :surface-material-info {:priority 90}, + :fields-count {:priority 80}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :ice-rinks-count {:priority 80}, + :area-m2 {:priority 90}, + :lighting-info {:priority 60}, + :ligthing? {:priority 70}, + :accessibility-info {:priority 50}, + :playground? {:priority 80}, + :school-use? {:priority 50}, + :exercise-machines-count {:priority 80}}}, + 1390 + {:description + {:fi + "Padelin pelaamiseen tarkoitettu kenttä ulkona. Pintamateriaali hiekkatekonurmi. Lajivaatimusten mukaiset seinät. Voi olla myös katettu.", + :se + "En utomhusbana avsedd för padelspel. Underlagsmaterialet är sandkonstgräs. Väggar enligt sportens krav. Kan även vara täckt.", + :en + "An outdoor court intended for playing padel. The surface material is sand artificial grass. Walls meet the sport's requirements. It can also be covered."}, + :tags {:fi ["padel" "padel-kenttä"]}, + :name + {:fi "Padelkenttä", + :se "Område med padelbanor", + :en "Padel court area"}, + :type-code 1390, + :main-category 1000, + :status "active", + :sub-category 1300, + :geometry-type "Point", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :free-use? {:priority 40}, + :field-length-m {:priority 90}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :area-m2 {:priority 90}, + :field-width-m {:priority 90}, + :lighting-info {:priority 50}, + :water-point {:priority 70}, + :ligthing? {:priority 60}, + :school-use? {:priority 40}, + :light-roof? {:priority 70}}}, + 5340 + {:description + {:fi "Pääasiallisesti kartingajoon tai supermotoon käytetty rata.", + :se "Huvudsakligen för karting.", + :en "Mainly for karting."}, + :tags {:fi []}, + :name {:fi "Karting-rata", :se "Kartingbana", :en "Kart circuit"}, + :type-code 5340, + :main-category 5000, + :status "active", + :sub-category 5300, + :geometry-type "Point", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :automated-timing? {:priority 70}, + :free-use? {:priority 40}, + :track-width-m {:priority 90}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :area-m2 {:priority 90}, + :lighting-info {:priority 50}, + :year-round-use? {:priority 80}, + :ligthing? {:priority 60}, + :track-length-m {:priority 90}}}, + 302 + {:description + {:fi + "Autiotupa, varaustupa, taukotupa, päivätupa. Yöpymis- ja levähdyspaikka retkeilijöille. Autiotupa avoin, varaustupa lukittu ja maksullinen. Päivätupa päiväkäyttöön.", + :se + "Övernattningsstuga, reserveringsstuga, raststuga, dagstuga. Övernattnings- och rastplats för vandrare. Övernattningsstugan öppen, reserveringsstugan låst och avgiftsbelagd. Dagstuga för bruk under dagen.", + :en + "Open hut, reservable hut, rest hut, day hut. Overnight resting place for hikers. An open hut is freely available; a reservable hut locked and subject to a charge. A day hut is for daytime use."}, + :tags {:fi ["taukopaikka"]}, + :name {:fi "Tupa", :se "Stuga", :en "Hut"}, + :type-code 302, + :main-category 0, + :status "active", + :sub-category 2, + :geometry-type "Point", + :props + {:may-be-shown-in-excursion-map-fi? {:priority 0}, + :toilet? {:priority 70}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :water-point {:priority 70}, + :free-use? {:priority 60}}}, + 4405 + {:description + {:fi + "Maastossa oleva retkeilyreitti, yleensä kauempana asutuksesta. Reitin varrella retkeilyn palveluita, esim. laavuja.", + :se + "Utflyktsled i terrängen, oftast längre borta från bebyggelse. Längs rutten friluftstjänster, t ex vindskydd.", + :en + "Natural hiking route, usually further away from residential areas. Provides hiking facilities, e.g. lean-to structures."}, + :tags {:fi ["retkeily" "vaellus" "vaelluspolku"]}, + :name + {:fi "Retkeilyreitti", :se "Utflyktsled", :en "Hiking route"}, + :type-code 4405, + :main-category 4000, + :status "active", + :sub-category 4400, + :geometry-type "LineString", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :free-use? {:priority 40}, + :may-be-shown-in-excursion-map-fi? {:priority 0}, + :route-width-m {:priority 97}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :rest-places-count {:priority 70}, + :lit-route-length-km {:priority 98}, + :accessibility-info {:priority 40}, + :route-length-km {:priority 99}}}, + 6120 + {:description + {:fi "Kylmä tai lämmin katettu tila ratsastukseen.", + :se "Kallt eller varmt takförsett utrymme för ridning.", + :en "Cold or warm, covered space for horseback riding."}, + :tags {:fi ["ratsastushalli" "maneesi"]}, + :name + {:fi "Ratsastusmaneesi", :se "Ridmanege", :en "Riding manège"}, + :type-code 6120, + :main-category 6000, + :status "active", + :sub-category 6100, + :geometry-type "Point", + :props + {:heating? {:priority 70}, + :surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :stand-capacity-person {:priority 70}, + :free-use? {:priority 40}, + :field-length-m {:priority 90}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :show-jumping? {:priority 80}, + :area-m2 {:priority 90}, + :field-width-m {:priority 90}, + :lighting-info {:priority 50}, + :school-use? {:priority 40}}}, + 4407 + {:description + {:fi + "Asfaltoitu rullahiihtoon lumettomana aikana tarkoitettu reitti. Reitti kulkee maastossa, ja sen käyttöä muilla kulkutavoilla on rajoitettu.", + :se + "En asfalterad bana avsedd för rullskidåkning under snöfria perioder. Banan går genom terrängen och användningen av andra färdsätt är begränsad.", + :en + "An asphalt track intended for roller skiing during snow-free periods. The track runs through terrain, and the use of other modes of travel is restricted."}, + :tags + {:fi ["rullahiihto"], + :se ["rullskidåkning"], + :en ["roller skiing"]}, + :name + {:fi "Rullahiihtorata", + :se "Rullskidbana", + :en "Roller Ski Track"}, + :type-code 4407, + :main-category 4000, + :status "active", + :sub-category 4400, + :geometry-type "LineString", + :props + {:surface-material {:priority 89}, + :surface-material-info {:priority 88}, + :free-use? {:priority 40}, + :outdoor-exercise-machines? {:priority 80}, + :route-width-m {:priority 97}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :rest-places-count {:priority 70}, + :lit-route-length-km {:priority 98}, + :route-length-km {:priority 99}}}, + 1310 + {:description + {:fi + "Koripalloon varustettu kenttä, kiinteät tai siirrettävät koritelineet. Minikenttä ja yhden korin kenttä lisätiedoissa.", + :se + "Plan utrustad för basket med fasta eller flyttbara ställningar. Miniplan och enkorgsplan i tilläggsupgifter.", + :en + "A field equipped for basketball, with fixed or movable apparatus. 'Mini-court' and 'one-basket court' included in additional information. "}, + :tags {:fi []}, + :name + {:fi "Koripallokenttä", :se "Basketplan", :en "Basketball court"}, + :type-code 1310, + :main-category 1000, + :status "active", + :sub-category 1300, + :geometry-type "Point", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :height-of-basket-or-net-adjustable? {:priority 80}, + :free-use? {:priority 40}, + :field-length-m {:priority 90}, + :match-clock? {:priority 70}, + :may-be-shown-in-harrastuspassi-fi? {:priority 40}, + :toilet? {:priority 70}, + :area-m2 {:priority 90}, + :field-width-m {:priority 90}, + :lighting-info {:priority 50}, + :scoreboard? {:priority 70}, + :water-point {:priority 70}, + :ligthing? {:priority 60}, + :basketball-field-type {:priority 80}, + :school-use? {:priority 40}}}, + 202 + {:description + {:fi "Telttailualue tai muu leiriytymiseen osoitettu paikka.", + :se "Tältplats eller annat område ordnat för tältning.", + :en "Camping site for tents or other encampment. "}, + :tags + {:fi ["yöpyminen" "taukopaikka" "telttapaikka" "leirintäalue"]}, + :name + {:fi "Telttailu ja leiriytyminen", + :se "Tältning och läger", + :en "Camping"}, + :type-code 202, + :main-category 0, + :status "active", + :sub-category 2, + :geometry-type "Point", + :props + {:toilet? {:priority 70}, + :may-be-shown-in-excursion-map-fi? {:priority 0}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :water-point {:priority 70}, + :free-use? {:priority 70}}}, + 1190 + {:description + {:fi + "Yleinen mäenlaskuun esimerkiksi pulkalla tai liukurilla tarkoitettu mäki. Kohde on ylläpidetty ja hoidettu, ja se voi muodostua luonnon mäestä tai rakennetuista kumpareista.", + :se + "En allmän backe avsedd för åkning med till exempel pulka eller stjärtlapp. Backen är underhållen och skött och kan bestå av en naturlig backe eller konstruerade högar.", + :en + "A common hill intended for sledding with, for example, a sled or a slider. The hill is maintained and taken care of, and it can consist of a natural hill or constructed mounds."}, + :tags {:fi ["pulkkailu" "pulkka" "mäenlasku"]}, + :name {:fi "Pulkkamäki", :se "Pulkabacke", :en "Sledding hill"}, + :type-code 1190, + :main-category 1000, + :status "active", + :sub-category 1100, + :geometry-type "Point", + :props + {:ligthing? {:priority 70}, + :school-use? {:priority 50}, + :may-be-shown-in-harrastuspassi-fi? {:priority 50}, + :toilet? {:priority 70}, + :lighting-info {:priority 60}}}, + 1620 + {:description + {:fi + "Ensisijaisesti golfin pelaamiseen tarkoitettu alue kesäkaudella. Reikien määrä merkitään lisätietoihin.", + :se "Officiell golfbana. Antalet hål anges i karakteristika.", + :en + "Official golf course. Number of holes included in properties."}, + :tags {:fi ["greeni" "puttialue" "range"]}, + :name + {:fi "Golfkenttä (piste)", :se "Golfbana", :en "Golf course"}, + :type-code 1620, + :main-category 1000, + :status "active", + :sub-category 1600, + :geometry-type "Point", + :props + {:holes-count {:priority 90}, + :free-use? {:priority 40}, + :may-be-shown-in-harrastuspassi-fi? {:priority 70}, + :toilet? {:priority 70}, + :lighting-info {:priority 50}, + :customer-service-point? {:priority 70}, + :green? {:priority 80}, + :ligthing? {:priority 60}, + :school-use? {:priority 40}, + :range? {:priority 80}}}, + 2250 + {:description + {:fi + "Ensisijaisesti skeittausta varten varustettu halli. Hallia voidaan käyttää bmx-pyöräilyn tai muiden soveltuvien lajien harrastamiseen.", + :se + "Hall utrustad för skejtning, rullskridskoåkning, bmx-åkning osv.", + :en + "An area for skateboarding, roller-blading, BMX biking, etc."}, + :tags {:fi ["ramppi"]}, + :name + {:fi "Skeittihalli", :se "Skateboardhall", :en "Indoor skatepark"}, + :type-code 2250, + :main-category 2000, + :status "active", + :sub-category 2200, + :geometry-type "Point", + :props + {:height-m {:priority 90}, + :surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :free-use? {:priority 40}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :area-m2 {:priority 90}, + :scoreboard? {:priority 70}, + :customer-service-point? {:priority 70}, + :school-use? {:priority 40}}}, + 2530 + {:description + {:fi "Pikaluisteluun tarkoitettu halli.", + :se + "Hall avsedd för hastighetsåkning på skridsko. Storlek > 333 1/3 m.", + :en "Hall intended for speed-skating. Size > 333.3 m."}, + :tags {:fi ["jäähalli"]}, + :name + {:fi "Pikaluisteluhalli", + :se "Skridskohall", + :en "Speed-skating hall"}, + :type-code 2530, + :main-category 2000, + :status "active", + :sub-category 2500, + :geometry-type "Point", + :props + {:field-2-area-m2 {:priority 80}, + :surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :field-3-length-m {:priority 80}, + :field-2-length-m {:priority 80}, + :automated-timing? {:priority 70}, + :stand-capacity-person {:priority 70}, + :free-use? {:priority 40}, + :field-1-length-m {:priority 80}, + :finish-line-camera? {:priority 70}, + :match-clock? {:priority 70}, + :field-1-width-m {:priority 80}, + :field-3-width-m {:priority 80}, + :field-2-width-m {:priority 80}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :ice-rinks-count {:priority 80}, + :field-1-area-m2 {:priority 80}, + :toilet? {:priority 70}, + :area-m2 {:priority 90}, + :scoreboard? {:priority 70}, + :auxiliary-training-area? {:priority 80}, + :loudspeakers? {:priority 70}, + :field-3-area-m2 {:priority 80}, + :school-use? {:priority 40}}}, + 112 + {:description + {:fi + "Muut luonnonsuojelualueet kuin kansallispuistot. Tietoja kerätään vain sellaisilta luonnonsuojelualueilta ja luonnonpuistoilta, joiden virkistyskäyttö on mahdollista. Esim. kunta- tai yksityisomisteisille maille perustetut suojelualueet. Kaavamerkintä S, SL.", + :se + "Andra naturskyddsområden än nationalparker och naturparker. Endast de naturskyddsområden där friluftsanvändning är möjlig. T ex skyddsområden som grundats på kommunal eller privat mark. Planbeteckning S, SL.", + :en + "Nature conservation areas other than national parks and natural parks. Only nature conservation areas with opportunities for recreation. E.g. protection areas established on municipal and private land. Symbol S, SL."}, + :tags {:fi ["virkistysalue"]}, + :name + {:fi "Muu luonnonsuojelualue, jolla on virkistyspalveluita", + :se "Annat naturskyddsområde med rekreationstjänster", + :en "Other nature conservation area with recreational services"}, + :type-code 112, + :main-category 0, + :status "active", + :sub-category 1, + :geometry-type "Polygon", + :props + {:may-be-shown-in-excursion-map-fi? {:priority 0}, + :area-km2 {:priority 90}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, + 2130 + {:description + {:fi + "Painonnostoon tai toiminnalliseen voimaharjoitteluun varustettu kuntoilutila tai voimailusali. Esimerkiksi crossfit- ja painonnostosalit.", + :se + "Utrustad för tyngdlyftning och boxning. Storleken anges i karakteristika.", + :en + "Equipped for weightlifting and boxing. Size specified in properties."}, + :tags {:fi ["kuntosali" "kuntoilu" "painonnosto" "voimanosto"]}, + :name + {:fi "Voimailusali", + :se "Styrketräningssal", + :en "Weight training hall "}, + :type-code 2130, + :main-category 2000, + :status "active", + :sub-category 2100, + :geometry-type "Point", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :free-customer-use? {:priority 40}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :group-exercise-rooms-count {:priority 80}, + :tatamis-count {:priority 80}, + :area-m2 {:priority 90}, + :wrestling-mats-count {:priority 80}, + :boxing-rings-count {:priority 80}, + :weight-lifting-spots-count {:priority 80}, + :customer-service-point? {:priority 70}, + :school-use? {:priority 40}, + :exercise-machines-count {:priority 80}}}, + 4406 + {:description + {:fi + "Talvisin tai ympärivuotisesti käytössä oleva maastoreitti, joka soveltuu usealle kulkutavalle (esim. jalan, lumikengille, läskipyörälle). Lisätietoihin merkitään, jos reitti on ympärivuotisessa käytössä ja mahdolliset kulkutavat.", + :se + "En terrängled som används på vintern eller året runt och som är lämplig för flera färdsätt (t.ex. till fots, med snöskor, fatbike). Ytterligare information anger om leden är i bruk året runt och möjliga färdsätt.", + :en + "A terrain trail used in winter or year-round, suitable for multiple modes of travel (e.g., on foot, with snowshoes, fat bike). Additional information indicates if the trail is in year-round use and possible modes of travel."}, + :tags + {:fi ["yhteiskäyttöreitti" "talvipolku"], + :se ["gemensam led" "vinterstig"], + :en ["shared trail" "winter path"]}, + :name + {:fi "Monikäyttöreitti", + :se "Multianvändningsled", + :en "Multi-use Trail"}, + :type-code 4406, + :main-category 4000, + :status "active", + :sub-category 4400, + :geometry-type "LineString", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :travel-mode-info {:priority 80}, + :route-width-m {:priority 97}, + :toilet? {:priority 70}, + :rest-places-count {:priority 80}, + :lit-route-length-km {:priority 98}, + :travel-modes {:priority 80}, + :year-round-use? {:priority 80}, + :route-length-km {:priority 99}}}, + 3220 + {:description + {:fi + "Yleinen uimaranta, EU-uimaranta. Pelastusväline ja ilmoitustaulu, jäteastia ja käymälä. Veden laadun seuranta ja alueen hoito järjestetty.", + :se + "Allmän badstrand, EU badstrand. Räddningsutrustning, en anslagstavla samt ett sopkärl och en toalett finns. Kvaliteten på vattnet följs upp och området underhålls.", + :en + "Public beach, EU bathing beach. Rescue equipment, a notice board, a waste bin, and a toilet are available. The quality of the water is monitored and the area is maintained."}, + :tags {:fi ["uimapaikka"]}, + :name {:fi "Uimaranta", :se "Badstrand", :en "Public beach"}, + :type-code 3220, + :main-category 3000, + :status "active", + :sub-category 3200, + :geometry-type "Point", + :props + {:free-use? {:priority 40}, + :pier? {:priority 80}, + :may-be-shown-in-excursion-map-fi? {:priority 0}, + :beach-length-m {:priority 90}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :shower? {:priority 70}, + :changing-rooms? {:priority 70}, + :sauna? {:priority 70}, + :other-platforms? {:priority 80}, + :school-use? {:priority 40}}}, + 5330 + {:description + {:fi + "Suuri rata-autoiluun tai moottoripyöräilyyn tarkoitettu asfaltoitu moottoriurheilupaikka.", + :se "Stor motorsportplats avsedd för bankörning.", + :en "Large motor sports venue for formula racing."}, + :tags {:fi ["autourheilu"]}, + :name + {:fi "Moottorirata", :se "Motorbana", :en "Formula race track"}, + :type-code 5330, + :main-category 5000, + :status "active", + :sub-category 5300, + :geometry-type "Point", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :automated-timing? {:priority 70}, + :stand-capacity-person {:priority 70}, + :free-use? {:priority 40}, + :finish-line-camera? {:priority 70}, + :track-width-m {:priority 90}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :lighting-info {:priority 50}, + :year-round-use? {:priority 80}, + :scoreboard? {:priority 70}, + :loudspeakers? {:priority 70}, + :ligthing? {:priority 60}, + :track-length-m {:priority 90}}}, + 4230 + {:description + {:fi "Lumilautailua varten rakennettu halli.", + :se + "Tunnel avsedd för snowboardåkning. Olika användningsmöjligheter i tilläggsinformation.", + :en + "Tunnel intended for snowboarding. Different uses specified in additional information."}, + :tags {:fi ["laskettelu"]}, + :name + {:fi "Lumilautatunneli", + :se "Snowboardtunnel", + :en "Snowboarding tunnel"}, + :type-code 4230, + :main-category 4000, + :status "active", + :sub-category 4200, + :geometry-type "Point", + :props + {:height-m {:priority 90}, + :surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :free-use? {:priority 40}, + :ski-service? {:priority 70}, + :altitude-difference {:priority 90}, + :route-width-m {:priority 97}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :area-m2 {:priority 90}, + :equipment-rental? {:priority 70}, + :route-length-km {:priority 99}}}, + 4320 + {:description + {:fi + "Mäkihyppyyn soveltuva mäki, vauhtimäessä on jää-, keramiikka- tai muovilatu. Mäen koko, materiaalit ja mahdollinen kesäkäyttö kuvataan lisätiedoissa.", + :se + "Is-, keramik- eller plastspår. K-punkt samt sommar- och vinteranvändning i karakteristika. Minimikrav: en liten backe med k-punkt på 75 m eller mera.", + :en + "Ice, ceramic or plastic track. Summer and winter use specified in attributes, along with K point, etc. Minimum normal hill, K point minimum 75 m."}, + :tags {:fi ["mäkihyppy" "hyppyri"]}, + :name {:fi "Hyppyrimäki", :se "Hoppbacke", :en "Ski jumping hill"}, + :type-code 4320, + :main-category 4000, + :status "active", + :sub-category 4300, + :geometry-type "Point", + :props + {:skijump-hill-type {:priority 80}, + :lifts-count {:priority 70}, + :plastic-outrun? {:priority 80}, + :free-use? {:priority 40}, + :ski-service? {:priority 70}, + :skijump-hill-material {:priority 80}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :hs-point {:priority 90}, + :k-point {:priority 90}, + :toilet? {:priority 70}, + :changing-rooms? {:priority 70}, + :year-round-use? {:priority 80}, + :changing-rooms-m2 {:priority 70}, + :jumps-count {:priority 80}, + :inruns-material {:priority 80}}}, + 3130 + {:description + {:fi + "Monipuolinen uimala kuntoutus-, virkistys- tai hyvinvointipalveluilla. Vesipinta-ala ja allasmäärät/tyypit ominaisuuksiin.", + :se + "Mångsidig badinrättning med rehabiliterings- och rekreationstjänster. Vattenareal samt antal och typ av bassänger i karakteristika.", + :en + "Versatile spa with rehabilitation or wellness services. Water volume and number/types of pools specified in properties."}, + :tags {:fi []}, + :name {:fi "Kylpylä", :se "Badinrättning", :en "Spa"}, + :type-code 3130, + :main-category 3000, + :status "active", + :sub-category 3100, + :geometry-type "Point", + :props + {:free-use? {:priority 40}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :area-m2 {:priority 90}, + :swimming-pool-count {:priority 90}, + :pool-water-area-m2 {:priority 90}, + :accessibility-info {:priority 40}, + :school-use? {:priority 40}}}, + 3110 + {:description + {:fi + "Halli, jossa on yksi tai useampia uima-altaita. Altaiden määrä ja vesipinta-ala kysytään ominaisuustiedoissa.", + :se + "Hall med en eller flera simbassänger. Antalet bassänger och vattenareal anges i karakteristika.", + :en + "Hall with one or several swimming pools. Number of pools and water surface area is requested in properties."}, + :tags {:fi []}, + :name + {:fi "Uimahalli", + :se "Simhall", + :en "Public indoor swimming pool"}, + :type-code 3110, + :main-category 3000, + :status "active", + :sub-category 3100, + :geometry-type "Point", + :props + {:automated-timing? {:priority 70}, + :stand-capacity-person {:priority 70}, + :free-use? {:priority 40}, + :finish-line-camera? {:priority 70}, + :match-clock? {:priority 70}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :area-m2 {:priority 90}, + :swimming-pool-count {:priority 90}, + :pool-water-area-m2 {:priority 90}, + :scoreboard? {:priority 70}, + :loudspeakers? {:priority 70}, + :accessibility-info {:priority 40}, + :school-use? {:priority 40}}}, + 203 + {:description + {:fi + "Kohteessa on veneilyyn liittyviä palveluita kuten säilytysmahdollisuus, vesillelaskupaikka tai veneen kiinnitysmahdollisuus. Kohteelle määritetään venesatamaluokka, jonka palveluvarustus kuvataan lisätiedoissa. Jos kyse on melontalaiturista, se kirjataan kyseisen laituriluokan alle. Kohde tulee merkitä tärkeimmän laiturin läheisyyteen, jos sellainen kohteessa on.", + :se "Tjänster för båtfarare. Precisering i karakteristika.", + :en "Facilities related to boating. Specififed in 'attributes'."}, + :tags {:fi ["satama" "laituri"]}, + :name + {:fi "Veneilyn palvelupaikka", + :se "Serviceplats för båtfarare", + :en "Boating services"}, + :type-code 203, + :main-category 0, + :status "active", + :sub-category 2, + :geometry-type "Point", + :props + {:free-use? {:priority 70}, + :pier? {:priority 80}, + :may-be-shown-in-excursion-map-fi? {:priority 0}, + :boat-launching-spot? {:priority 80}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :boating-service-class {:priority 90}, + :customer-service-point? {:priority 80}, + :water-point {:priority 70}, + :accessibility-info {:priority 70}}}, + 4620 + {:description + {:fi + "Vähintään kansallisen tason kilpailujen järjestämiseen soveltuva ampumahiihtokeskus. Ampumahiihtokeskuksessa useita ampumapaikkoja ja latuverkosto.", + :se "Tillräckligt stort för åtminstone nationella tävlingar.", + :en "For minimum national level competitions."}, + :tags {:fi ["ampumapaikka"]}, + :name + {:fi "Ampumahiihtokeskus", + :se "Skidskyttecentrum", + :en "Biathlon centre"}, + :type-code 4620, + :main-category 4000, + :status "active", + :sub-category 4600, + :geometry-type "Point", + :props + {:stand-capacity-person {:priority 70}, + :free-use? {:priority 40}, + :ski-service? {:priority 70}, + :finish-line-camera? {:priority 70}, + :ski-track-traditional? {:priority 80}, + :route-width-m {:priority 98}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :shower? {:priority 70}, + :rest-places-count {:priority 70}, + :changing-rooms? {:priority 70}, + :shooting-positions-count {:priority 80}, + :lit-route-length-km {:priority 97}, + :year-round-use? {:priority 80}, + :scoreboard? {:priority 70}, + :sauna? {:priority 70}, + :loudspeakers? {:priority 70}, + :accessibility-info {:priority 40}, + :ski-track-freestyle? {:priority 80}, + :route-length-km {:priority 99}}}, + 5360 + {:description + {:fi + "Pääasiallisesti jokamiesajoa, rallicrossia tai moottoripyöräilyä varten.", + :se "Huvudsakligen för allemanskörning och/eller rallycross.", + :en "Mainly for everyman racing and/or rallycross."}, + :tags {:fi []}, + :name + {:fi "Jokamies- ja rallicross-rata", + :se "Allemans- och rallycrossbana", + :en "Everyman racing and rallycross track "}, + :type-code 5360, + :main-category 5000, + :status "active", + :sub-category 5300, + :geometry-type "Point", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :automated-timing? {:priority 70}, + :stand-capacity-person {:priority 70}, + :free-use? {:priority 40}, + :finish-line-camera? {:priority 70}, + :track-width-m {:priority 90}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :area-m2 {:priority 90}, + :lighting-info {:priority 50}, + :year-round-use? {:priority 80}, + :scoreboard? {:priority 70}, + :loudspeakers? {:priority 70}, + :ligthing? {:priority 60}, + :covered-stand-person-count {:priority 70}, + :track-length-m {:priority 90}}}, + 2290 + {:description + {:fi "Petanque-peliin tarkoitettu halli.", + :se + "Hall avsedd för petanque. Storlek, antalet planer och utrustning i karakteristika.", + :en "Hall intended for petanque."}, + :tags {:fi ["petankki"]}, + :name + {:fi "Petanque-halli", :se "Petanquehall", :en "Petanque hall"}, + :type-code 2290, + :main-category 2000, + :status "active", + :sub-category 2200, + :geometry-type "Point", + :props + {:height-m {:priority 90}, + :surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :free-use? {:priority 40}, + :fields-count {:priority 80}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :area-m2 {:priority 90}, + :scoreboard? {:priority 70}, + :customer-service-point? {:priority 70}, + :school-use? {:priority 40}}}, + 2260 + {:description + {:fi + "Ensisijaisesti sulkapallon pelaamiseen tarkoitettu halli. Vapaa korkeus ilmoitetaan lisätiedoissa.", + :se "Hall i första hand avsedd för badminton.", + :en "Hall intended primarily for badminton."}, + :tags {:fi []}, + :name + {:fi "Sulkapallohalli", :se "Badmintonhall", :en "Badminton hall"}, + :type-code 2260, + :main-category 2000, + :status "active", + :sub-category 2200, + :geometry-type "Point", + :props + {:height-m {:priority 90}, + :surface-material {:priority 89}, + :surface-material-info {:priority 88}, + :stand-capacity-person {:priority 70}, + :free-use? {:priority 40}, + :tennis-courts-count {:priority 80}, + :field-length-m {:priority 90}, + :badminton-courts-count {:priority 80}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :padel-courts-count {:priority 80}, + :toilet? {:priority 70}, + :area-m2 {:priority 90}, + :field-width-m {:priority 90}, + :scoreboard? {:priority 70}, + :floorball-fields-count {:priority 80}, + :squash-courts-count {:priority 80}, + :customer-service-point? {:priority 70}, + :volleyball-fields-count {:priority 80}, + :school-use? {:priority 40}}}, + 1160 + {:description + {:fi + "Pyöräilyä ja temppuilua varten varattu alue, esim. bmx-, pump track- tai dirt-pyöräilyalue.", + :se + "Ett område avsett för cykling och trick, till exempel BMX-, pump track- eller dirtcyklingsområde.", + :en + "An area designated for cycling and stunts, such as a BMX, pump track, or dirt biking area."}, + :tags {:fi ["pumptrack" "bmx" "pump" "track"]}, + :name + {:fi "Pyöräilyalue", :se "Cykelåkningsområde", :en "Cycling area"}, + :type-code 1160, + :main-category 1000, + :status "active", + :sub-category 1100, + :geometry-type "Point", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :stand-capacity-person {:priority 70}, + :free-use? {:priority 50}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :area-m2 {:priority 90}, + :lighting-info {:priority 60}, + :customer-service-point? {:priority 70}, + :ligthing? {:priority 70}, + :accessibility-info {:priority 50}, + :covered-stand-person-count {:priority 70}, + :school-use? {:priority 50}}}, + 1210 + {:description + {:fi + "Yleisurheilun harjoitusalueeksi merkitään kohde, jossa on yleisurheilun harjoitteluun soveltuvia suorituspaikkoja, esim. kenttä, ratoja tai eri lajien suorituspaikkoja, mutta ei virallisen yleisurheilukentän kaikkia suorituspaikkoja. Lyhytrataiset (juoksurata alle 400 m) yleisurheilukentät tallennetaan yleisurheilun harjoitusalueeksi.", + :se + "Ett område för friidrottsträning markeras där det finns anläggningar som är lämpliga för friidrottsträning, till exempel en plan, banor eller platser för olika grenar, men inte alla anläggningar för en officiell friidrottsarena. Kortbaniga friidrottsarenor (löparbana under 400 m) registreras som friidrottsträningsområden.", + :en + "An athletics training area is designated for locations with facilities suitable for athletics training, such as a field, tracks, or various event areas, but not all facilities of an official athletics stadium. Short track athletics fields (running track under 400 m) are recorded as athletics training areas."}, + :tags + {:fi + ["keihäs" + "keihäänheitto" + "moukari" + "pituushyppy" + "juoksurata" + "kolmiloikka" + "seiväs" + "kuula" + "urheilukenttä" + "yleisurheilukenttä"]}, + :name + {:fi "Yleisurheilun harjoitusalue", + :se "Träningsområde för friidrott", + :en "Athletics training area"}, + :type-code 1210, + :main-category 1000, + :status "active", + :sub-category 1200, + :geometry-type "Point", + :props + {:heating? {:priority 70}, + :surface-material {:priority 89}, + :surface-material-info {:priority 88}, + :free-use? {:priority 50}, + :sprint-lanes-count {:priority 80}, + :javelin-throw-places-count {:priority 80}, + :field-length-m {:priority 90}, + :circular-lanes-count {:priority 80}, + :sprint-track-length-m {:priority 80}, + :inner-lane-length-m {:priority 80}, + :discus-throw-places {:priority 80}, + :hammer-throw-places-count {:priority 80}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :polevault-places-count {:priority 80}, + :toilet? {:priority 70}, + :running-track-surface-material {:priority 80}, + :area-m2 {:priority 90}, + :field-width-m {:priority 90}, + :lighting-info {:priority 60}, + :shotput-count {:priority 80}, + :longjump-places-count {:priority 80}, + :ligthing? {:priority 70}, + :school-use? {:priority 50}, + :highjump-places-count {:priority 80}, + :training-spot-surface-material {:priority 80}}}, + 5140 + {:description + {:fi + "Rakennettu pysyvästi vesihiihdolle. Vesihiihtoalueella on laituri.", + :se "Byggt för vattenskidåkning, permanent. Minimikrav: brygga.", + :en + "Permanent construction for water skiing. Minimum equipment pier."}, + :tags {:fi []}, + :name + {:fi "Vesihiihtoalue", + :se "Område för vattenskidåkning", + :en "Water ski area"}, + :type-code 5140, + :main-category 5000, + :status "active", + :sub-category 5100, + :geometry-type "Point", + :props + {:pier? {:priority 80}, + :area-km2 {:priority 90}, + :free-use? {:priority 40}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, + 4310 + {:description + {:fi + "Mäkihypyn harjoitteluun rakennettu mäki. K-piste ominaisuustietoihin, materiaalit, kesä- ja talvikäyttö ominaisuuksiin. ", + :se + "K-punkt, material samt sommar- och vinteranvändning i karakteristika.", + :en + "K point in properties; materials, summer and winter use specified in attributes. "}, + :tags {:fi ["mäkihyppy" "hyppyri" "hyppyrimäki"]}, + :name + {:fi "Harjoitushyppyrimäki", + :se "Träningshoppbacke", + :en "Ski jumping hill for training"}, + :type-code 4310, + :main-category 4000, + :status "deprecated", + :sub-category 4300, + :geometry-type "Point", + :props + {:skijump-hill-type {:priority 80}, + :lifts-count {:priority 70}, + :plastic-outrun? {:priority 80}, + :free-use? {:priority 40}, + :ski-service? {:priority 70}, + :skijump-hill-material {:priority 80}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :k-point {:priority 90}, + :toilet? {:priority 70}, + :year-round-use? {:priority 80}, + :p-point {:priority 90}, + :inruns-material {:priority 80}, + :school-use? {:priority 40}}}, + 207 + {:description + {:fi + "Opastuspiste on ulkoilureitin, virkistysalueen tai muun liikuntapaikan yhteydessä oleva lisätieto. Paikassa voi olla esimerkiksi opastustaulu ja kartta tai laajempi palvelupiste. Opastuspiste-merkintää voidaan käyttää myös ilmoittamaan reitin lähtöpisteen.", + :se + "En informationspunkt är en extra information vid en friluftsled, ett rekreationsområde eller en annan idrottsplats. På platsen kan det till exempel finnas en informationstavla och karta eller en mer omfattande servicestation. Informationspunkt-markeringen kan också användas för att ange startpunkten för en rutt.", + :en + "An information point is additional information associated with an outdoor trail, recreational area, or other sports facility. The location may include, for example, an information board and map or a more extensive service point. The information point marking can also be used to indicate the starting point of a route."}, + :tags {:fi ["info" "opastaulu" "infopiste"]}, + :name {:fi "Opastuspiste", :se "Informationspunkt", :en "Info"}, + :type-code 207, + :main-category 0, + :status "deprecated", + :sub-category 2, + :geometry-type "Point", + :props + {:parking-place? {:priority 70}, + :may-be-shown-in-excursion-map-fi? {:priority 0}, + :toilet? {:priority 70}, + :school-use? {:priority 60}, + :free-use? {:priority 60}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, + 1130 + {:description + {:fi + "Ulkokuntoilupaikka on esimerkiksi kuntoilulaitteita, voimailulaitteita tai kuntoportaat sisältävä liikuntapaikka. Kohde voi olla osa liikuntapuistoa, liikuntareitin varrella oleva kuntoilupaikka tai ns. ulkokuntosali.", + :se + "En utomhusträningsplats är en idrottsplats som innehåller till exempel träningsutrustning, styrketräningsutrustning eller träningsstegar. Platsen kan vara en del av en idrottspark, en träningsplats längs en motionsslinga eller en så kallad utomhusgym.", + :en + "An outdoor fitness area is a sports facility that includes, for example, exercise equipment, strength training equipment, or fitness stairs. The location can be part of a sports park, a fitness spot along a trail, or a so-called outdoor gym"}, + :tags + {:fi + ["kuntoilulaite" + "ulkokuntoilupiste" + "kuntoilupiste" + "kuntoilupaikka" + "kuntoportaat"]}, + :name + {:fi "Ulkokuntoilupaikka", + :se "Konditionspark för utomhusaktiviteter", + :en "Street workout park"}, + :type-code 1130, + :main-category 1000, + :status "active", + :sub-category 1100, + :geometry-type "Point", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :free-use? {:priority 0}, + :fitness-stairs-length-m {:priority 80}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :area-m2 {:priority 90}, + :lighting-info {:priority 60}, + :ligthing? {:priority 70}, + :playground? {:priority 80}, + :school-use? {:priority 0}, + :exercise-machines-count {:priority 80}}}, + 5120 + {:description + {:fi "Pysyvästi purjehdusta varten varustettu alue.", + :se "Byggt för segling, permanent.", + :en "Permanent construction for sailing."}, + :tags {:fi []}, + :name + {:fi "Purjehdusalue", :se "Seglingsområde", :en "Sailing area"}, + :type-code 5120, + :main-category 5000, + :status "active", + :sub-category 5100, + :geometry-type "Point", + :props + {:area-km2 {:priority 90}, + :pier? {:priority 80}, + :boat-places-count {:priority 80}, + :free-use? {:priority 40}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, + 4110 + {:description + {:fi + "Laskettelun suorituspaikka on lasketteluun tai lumilautailuun tarkoitettu liikuntapaikka, esim. laskettelukeskus. Laskettelun suorituspaikassa voi olla laskettelurinteitä, parkkeja tai muita rinnerakenteita ja hiihtohissejä.", + :se + "Slalombacke, rodelbana, pipe, puckelpist, freestyle ramp, trickbana.", + :en "Ski slopes, half pipes and other slope structures."}, + :tags {:fi ["rinne" "laskettelu" "laskettelurinne"]}, + :name + {:fi "Laskettelun suorituspaikka", + :se "Slalombackar och alpina skidcentra", + :en "Ski slopes and downhill ski resorts"}, + :type-code 4110, + :main-category 4000, + :status "active", + :sub-category 4100, + :geometry-type "Point", + :props + {:lifts-count {:priority 80}, + :freestyle-slope? {:priority 80}, + :free-use? {:priority 40}, + :ski-service? {:priority 70}, + :sledding-hill? {:priority 80}, + :longest-slope-m {:priority 90}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :snowpark-or-street? {:priority 80}, + :max-vertical-difference {:priority 90}, + :toilet? {:priority 70}, + :halfpipe-count {:priority 80}, + :equipment-rental? {:priority 70}, + :slopes-count {:priority 90}, + :shortest-slope-m {:priority 90}, + :jumps-count {:priority 80}, + :customer-service-point? {:priority 70}, + :lit-slopes-count {:priority 80}, + :accessibility-info {:priority 40}}}, + 4452 + {:description + {:fi + "Merkitty vesireitti, ei kuitenkaan veneväylä. Vesireitti on reittiehdotus-tyyppinen suositeltu vesiretkeilyyn soveltuva reitti. Esim. kirkkovenesoutureitti.", + :se + "Märkt vattenled, endast ruttförslag t ex för kyrkbåtsrodd, inte som farled för småbåtar.", + :en + "Marked water route, not a navigation channel. Route suggestions included. E.g., route for \"church rowing boats\"."}, + :tags {:fi ["kanootti" "kajakki" "melonta"]}, + :name + {:fi "Vesiretkeilyreitti", + :se "Utflyktsled i vattendrag", + :en "Water route"}, + :type-code 4452, + :main-category 4000, + :status "active", + :sub-category 4400, + :geometry-type "LineString", + :props + {:may-be-shown-in-excursion-map-fi? {:priority 0}, + :route-length-km {:priority 90}, + :rest-places-count {:priority 70}, + :school-use? {:priority 40}, + :free-use? {:priority 40}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :jumps-count {:priority 80}}}, + 5370 + {:description + {:fi "Pääasiallisesti jääspeedwayta varten.", + :se "Huvudsakligen för isracing.", + :en "Speedway mainly for ice racing."}, + :tags {:fi ["speedway"]}, + :name + {:fi "Speedway-/jääspeedwayrata", + :se "Isracingbana", + :en "Ice speedway track"}, + :type-code 5370, + :main-category 5000, + :status "active", + :sub-category 5300, + :geometry-type "Point", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :automated-timing? {:priority 70}, + :stand-capacity-person {:priority 70}, + :free-use? {:priority 40}, + :finish-line-camera? {:priority 70}, + :track-width-m {:priority 90}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :lighting-info {:priority 50}, + :year-round-use? {:priority 80}, + :scoreboard? {:priority 70}, + :loudspeakers? {:priority 70}, + :ligthing? {:priority 60}, + :track-length-m {:priority 90}}}, + 2240 + {:description + {:fi + "Ensisijaisesti salibandyyn tarkoitettu halli. Kenttien määrä ja pintamateriaali kirjataan lisätietoihin.", + :se + "Hall i första hand avsedd för innebandy. Antalet planer samt ytmaterial i karakteristika.", + :en + "Hall primarily intended for floorball. Number of courts and surface material specified in properties."}, + :tags {:fi ["sähly"]}, + :name + {:fi "Salibandyhalli", :se "Innebandyhall", :en "Floorball hall"}, + :type-code 2240, + :main-category 2000, + :status "active", + :sub-category 2200, + :geometry-type "Point", + :props + {:height-m {:priority 90, :derived? true}, + :surface-material {:priority 89, :derived? true}, + :surface-material-info {:priority 88, :derived? true}, + :stand-capacity-person {:priority 70, :derived? true}, + :free-use? {:priority 40}, + :field-length-m {:priority 90, :derived? true}, + :badminton-courts-count {:priority 80}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :area-m2 {:priority 90, :derived? true}, + :field-width-m {:priority 90, :derived? true}, + :scoreboard? {:priority 70}, + :floorball-fields-count {:priority 80, :derived? true}, + :auxiliary-training-area? {:priority 80}, + :customer-service-point? {:priority 70}, + :school-use? {:priority 40}}}, + 2510 + {:description + {:fi + "Harjoitusjäähalli on pääasiassa jääurheilun harjoitteluun ja jääliikuntaan käytettävä jäähalli.", + :se + "Antalet planer och omklädningshytter, uppvärmning osv anges i karakteristika.", + :en + "Number of fields, heating, changing rooms, etc., specified in properties."}, + :tags {:fi ["jäähalli"]}, + :name + {:fi "Harjoitusjäähalli", + :se "Övningsishall", + :en "Training ice arena"}, + :type-code 2510, + :keywords {:fi ["Jäähalli"], :en [], :se []}, + :main-category 2000, + :status "active", + :sub-category 2500, + :geometry-type "Point", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :automated-timing? {:priority 70}, + :stand-capacity-person {:priority 70}, + :free-use? {:priority 40}, + :finish-line-camera? {:priority 70}, + :match-clock? {:priority 70}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :ice-rinks-count {:priority 80}, + :field-2-flexible-rink? {:priority 80}, + :toilet? {:priority 70}, + :area-m2 {:priority 90}, + :curling-lanes-count {:priority 80}, + :scoreboard? {:priority 70}, + :auxiliary-training-area? {:priority 80}, + :ringette-boundary-markings? {:priority 80}, + :field-1-flexible-rink? {:priority 80}, + :loudspeakers? {:priority 70}, + :school-use? {:priority 40}, + :field-3-flexible-rink? {:priority 80}}}, + 1640 + {:description + {:fi "Ratagolfliiton hyväksymät ratagolf-/minigolfradat.", + :se + "Bangolf / minigolf, enligt Finlands Bangolfförbundets regler.", + :en + "A course built for miniature golf, accepted by the Ratagolf Union."}, + :tags {:fi ["minigolf"]}, + :name {:fi "Ratagolf", :se "Bangolf", :en "Minigolf course"}, + :type-code 1640, + :main-category 1000, + :status "active", + :sub-category 1600, + :geometry-type "Point", + :props + {:holes-count {:priority 90}, + :free-use? {:priority 40}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :lighting-info {:priority 50}, + :customer-service-point? {:priority 70}, + :green? {:priority 80}, + :ligthing? {:priority 60}, + :school-use? {:priority 40}, + :range? {:priority 80}}}, + 1380 + {:description + {:fi "Rullakiekon pelaamiseen varustettu kenttä.", + :se "Plan utrustad för inlinehockey.", + :en "Field equipped for roller hockey."}, + :tags {:fi ["rullakiekko"]}, + :name + {:fi "Rullakiekkokenttä", + :se "Inlinehockeyplan", + :en "Roller hockey field"}, + :type-code 1380, + :main-category 1000, + :status "active", + :sub-category 1300, + :geometry-type "Point", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :free-use? {:priority 40}, + :field-length-m {:priority 90}, + :match-clock? {:priority 70}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :area-m2 {:priority 90}, + :field-width-m {:priority 90}, + :lighting-info {:priority 50}, + :water-point {:priority 70}, + :ligthing? {:priority 60}, + :school-use? {:priority 40}}}, + 4451 + {:description + {:fi + "Erityisesti melontaan tarkoitettu vesistöreitti. Reitistä on laadittu reittikuvaus ja maastossa löytyy opasteita (esim. rantautumispaikoista). Reittiehdotus-tyyppinen, ei navigointiin.", + :se + "Särskilt för paddling, märkt med ruttförslag, ej för navigering.", + :en + "Marked route particularly for canoeing. Route suggestions are not intended for navigation."}, + :tags {:fi ["kanootti" "kajakki"]}, + :name {:fi "Melontareitti", :se "Paddlingsled", :en "Canoe route"}, + :type-code 4451, + :main-category 4000, + :status "active", + :sub-category 4400, + :geometry-type "LineString", + :props + {:route-length-km {:priority 90}, + :rest-places-count {:priority 70}, + :may-be-shown-in-excursion-map-fi? {:priority 0}, + :free-use? {:priority 40}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, + 4403 + {:description + {:fi + "Jalkaisin tapahtuvaan ulkoiluun tarkoitettu reitti. Suhteellisen leveä ja helppokulkuinen reitti, yleensä valaistu ja pinnoitettu.", + :se + "Promenadled. Relativt bred och lättilgänglig, eventuellt belyst och asfalterad.", + :en + "Route intended for outdoor pedestrian activities. Relatively broad and passable. Potentially lit and surfaced."}, + :tags {:fi ["ulkoilu" "kävely" "ulkoilureitti" "kävelyreitti"]}, + :name + {:fi "Kävelyreitti/ulkoilureitti", + :se "Promenadled/friluftsled", + :en "Walking route/outdoor route"}, + :type-code 4403, + :main-category 4000, + :status "active", + :sub-category 4400, + :geometry-type "LineString", + :props + {:surface-material {:priority 89}, + :surface-material-info {:priority 88}, + :free-use? {:priority 40}, + :may-be-shown-in-excursion-map-fi? {:priority 0}, + :outdoor-exercise-machines? {:priority 80}, + :route-width-m {:priority 97}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :rest-places-count {:priority 70}, + :lit-route-length-km {:priority 98}, + :accessibility-info {:priority 40}, + :route-length-km {:priority 99}}}, + 5150 + {:description + {:fi + "Melontaan tarkoitettu palvelupaikka, jossa voi olla esim. vuokrauspalveluita. Melontakeskuksesta voi lähteä melontareitti tai sen yhteydessä voi olla melontaratoja.", + :se + "En paddlingsanläggning med uthyrningstjänster. Från paddlingscentret kan det finnas paddelleder eller paddelbanor i närheten.", + :en + "A canoeing facility with rental services. From the canoeing center, there may be canoeing routes or paddling tracks nearby."}, + :tags {:fi ["melonta" "kajakki" "kanootti" "melontakeskus"]}, + :name + {:fi "Melontakeskus", + :se "Centrum för paddling", + :en "Canoeing centre"}, + :type-code 5150, + :main-category 5000, + :status "active", + :sub-category 5100, + :geometry-type "Point", + :props + {:free-use? {:priority 40}, + :pier? {:priority 80}, + :canoeing-club? {:priority 80}, + :altitude-difference {:priority 90}, + :rapid-canoeing-centre? {:priority 80}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :equipment-rental? {:priority 70}, + :activity-service-company? {:priority 80}}}, + 1630 + {:description + {:fi + "Golfia varten varustettu sisäharjoittelutila. Voi olla useita erilaisia suorituspaikkoja.", + :se "Övningsutrymme byggt för golf. Storlek i karakteristika.", + :en + "Training space built for golf. Size specified in properties."}, + :tags {:fi ["greeni" "puttialue"]}, + :name + {:fi "Golfin harjoitushalli", + :se "Övningshall för golf", + :en "Golf training hall"}, + :type-code 1630, + :main-category 2000, + :status "active", + :sub-category 2200, + :geometry-type "Point", + :props + {:height-m {:priority 90}, + :holes-count {:priority 90}, + :free-use? {:priority 40}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :area-m2 {:priority 90}, + :customer-service-point? {:priority 70}, + :green? {:priority 80}, + :school-use? {:priority 40}, + :range? {:priority 80}}}, + 2295 + {:description + {:fi + "Yksi tai useampi padelkenttä sisällä. Pintamateriaali tekonurmi (hiekkatekonurmi). Lajivaatimusten mukaiset seinät. Vapaa korkeus ilmoitetaan lisätiedoissa.", + :se + "En eller flera padelbanor inomhus. Ytmaterial konstgräs (med sand), 20 x 10 m. Väggar måste uppfylla spelets krav. Höjd anges i karakteristika.", + :en + "One or more indoor padel courts. The court has an artificial grass surface and its measurements are 20 x 10 metres. The walls must meet the requirements for the sport. Height given in 'properties'."}, + :tags {:fi ["padel" "padel-halli"]}, + :name {:fi "Padelhalli", :se "Padelhall", :en "Padel hall"}, + :type-code 2295, + :main-category 2000, + :status "active", + :sub-category 2200, + :geometry-type "Point", + :props + {:height-m {:priority 90}, + :surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :stand-capacity-person {:priority 70}, + :free-use? {:priority 40}, + :field-length-m {:priority 90}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :padel-courts-count {:priority 80}, + :toilet? {:priority 70}, + :area-m2 {:priority 90}, + :field-width-m {:priority 90}, + :scoreboard? {:priority 70}, + :school-use? {:priority 40}}}, + 2370 + {:description + {:fi "Kiipeilyyn varustettu sisätila. Myös boulderointipaikat.", + :se + "Inomhusutrymme utrustat för klättring, även platser för bouldering.", + :en + "Indoor space equipped for climbing. Also bouldering venues."}, + :tags {:fi ["kiipeilyseinä"]}, + :name + {:fi "Sisäkiipeilyseinä", + :se "Klättervägg inomhus", + :en "Indoor climbing wall"}, + :type-code 2370, + :main-category 2000, + :status "active", + :sub-category 2300, + :geometry-type "Point", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :climbing-routes-count {:priority 80}, + :climbing-wall-height-m {:priority 90}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :area-m2 {:priority 90}, + :climbing-wall-width-m {:priority 90}, + :school-use? {:priority 40}}}, + 1340 + {:description + {:fi + "Palloiluun tarkoitettu kenttä, jonka pintamateriaali on esim. hiekka, nurmi tai hiekkatekonurmi. Kentällä on mahdollista pelata yhtä tai useampaa palloilulajia. Kentän koko merkitään lisätietoihin. Kevyt poistettava kate on mahdollinen.", + :se + "Plan avsedd för bollspel. Sand, konstgräs med sand el dyl, storleken varierar. En eller flera bollspelsgrenar möjliga.", + :en + "A field intended for ball games. Sand, grass, artificial turf, etc., size varies. One or more types of ball games possible."}, + :tags {:fi []}, + :name {:fi "Pallokenttä", :se "Bollplan", :en "Ball field"}, + :type-code 1340, + :main-category 1000, + :status "active", + :sub-category 1300, + :geometry-type "Point", + :props + {:heating? {:priority 70}, + :surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :stand-capacity-person {:priority 70}, + :free-use? {:priority 40}, + :field-length-m {:priority 90}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :changing-rooms? {:priority 70}, + :area-m2 {:priority 90}, + :field-width-m {:priority 90}, + :lighting-info {:priority 50}, + :year-round-use? {:priority 80}, + :customer-service-point? {:priority 70}, + :water-point {:priority 70}, + :ligthing? {:priority 60}, + :school-use? {:priority 40}, + :light-roof? {:priority 70}}}, + 1610 + {:description + {:fi + "Golfin harjoittelua varten varustettu alue. Harjoitusalue voi sisältää useampia suorituspaikkoja, kuten rangen ja puttausviheriön. Harjoitusalue sijaitsee ulkona.", + :se + "Ett område utrustat för golfträning. Träningsområdet kan innehålla flera träningsplatser, såsom en range och en puttningsgreen. Träningsområdet ligger utomhus.", + :en + "An area equipped for golf practice. The practice area may include multiple facilities, such as a driving range and a putting green. The practice area is located outdoors."}, + :tags {:fi ["greeni" "puttialue" "range"]}, + :name + {:fi "Golfin harjoitusalue", + :se "Träningsområde för golf", + :en "Golf training area"}, + :type-code 1610, + :main-category 1000, + :status "active", + :sub-category 1600, + :geometry-type "Point", + :props + {:holes-count {:priority 90}, + :free-use? {:priority 40}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :lighting-info {:priority 50}, + :customer-service-point? {:priority 70}, + :green? {:priority 80}, + :ligthing? {:priority 60}, + :school-use? {:priority 40}, + :range? {:priority 80}}}, + 4421 + {:description + {:fi + "Reittitoimituksella hyväksytty, virallinen moottorikelkkailureitti.", + :se "En officiell rutt som godkänts genom en ruttexpedition.", + :en + "Officially approved route (in compliance with Act 670/1991)."}, + :tags {:fi []}, + :name + {:fi "Moottorikelkkareitti", + :se "Snöskoterled", + :en "Official snowmobile route"}, + :type-code 4421, + :main-category 4000, + :status "active", + :sub-category 4400, + :geometry-type "LineString", + :props + {:rest-places-count {:priority 70}, + :route-width-m {:priority 98}, + :may-be-shown-in-excursion-map-fi? {:priority 0}, + :route-length-km {:priority 99}, + :free-use? {:priority 40}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}}}, + 2220 + {:description + {:fi + "Monitoimihalli on suuri liikuntatila, joka on merkittävä monien lajien kilpailu- ja tapahtumapaikka. Liikuntapinta-ala on suurempi kuin 5 000 m2.", + :se "Större tävlingsplats för ett flertal grenar, >= 5 000 m2.", + :en + "Significant competition venue for various sports, >=5000 m2."}, + :tags {:fi ["liikuntahalli" "urheilutalo" "urheiluhalli"]}, + :name + {:fi "Monitoimihalli/areena", + :se "Allaktivitetshall/multiarena", + :en "Multipurpose hall/arena"}, + :type-code 2220, + :main-category 2000, + :status "active", + :sub-category 2200, + :geometry-type "Point", + :props + {:height-m {:priority 80}, + :surface-material {:priority 89}, + :basketball-fields-count {:priority 80}, + :surface-material-info {:priority 88}, + :automated-timing? {:priority 70}, + :stand-capacity-person {:priority 70}, + :free-use? {:priority 40}, + :sprint-lanes-count {:priority 80}, + :javelin-throw-places-count {:priority 80}, + :tennis-courts-count {:priority 80}, + :field-length-m {:priority 90}, + :circular-lanes-count {:priority 80}, + :match-clock? {:priority 70}, + :sprint-track-length-m {:priority 80}, + :inner-lane-length-m {:priority 80}, + :discus-throw-places {:priority 80}, + :badminton-courts-count {:priority 80}, + :hammer-throw-places-count {:priority 80}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :padel-courts-count {:priority 80}, + :polevault-places-count {:priority 80}, + :space-divisible {:priority 70}, + :toilet? {:priority 70}, + :gymnastics-space? {:priority 80}, + :running-track-surface-material {:priority 80}, + :area-m2 {:priority 90}, + :field-width-m {:priority 90}, + :scoreboard? {:priority 70}, + :shotput-count {:priority 80}, + :longjump-places-count {:priority 80}, + :football-fields-count {:priority 80}, + :floorball-fields-count {:priority 80}, + :auxiliary-training-area? {:priority 80}, + :squash-courts-count {:priority 80}, + :loudspeakers? {:priority 70}, + :customer-service-point? {:priority 70}, + :accessibility-info {:priority 40}, + :handball-fields-count {:priority 80}, + :volleyball-fields-count {:priority 80}, + :climbing-wall? {:priority 80}, + :school-use? {:priority 40}, + :highjump-places-count {:priority 80}}}, + 1320 + {:description + {:fi + "Lentopalloon varustettu kenttä, jossa on kiinteät lentopallotolpat.", + :se "Plan utrustad för volleyboll. Fasta volleybollställningar.", + :en + "A field equipped for volleyball. Fixed volleyball apparatus."}, + :tags {:fi []}, + :name + {:fi "Lentopallokenttä", + :se "Volleybollplan", + :en "Volleyball court"}, + :type-code 1320, + :main-category 1000, + :status "active", + :sub-category 1300, + :geometry-type "Point", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :height-of-basket-or-net-adjustable? {:priority 80}, + :free-use? {:priority 40}, + :field-length-m {:priority 90}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :area-m2 {:priority 90}, + :field-width-m {:priority 90}, + :lighting-info {:priority 50}, + :water-point {:priority 70}, + :ligthing? {:priority 60}, + :school-use? {:priority 40}}}, + 4402 + {:description + {:fi + "Talvikaudella hiihtoa varten ylläpidetty reitti. Hiihtotyylit kerrotaan ominaisuustiedoissa.", + :se + "Led avsedd för skidåkning. Ej sommaranvändning och -underhåll. Åkstilar anges i karakteristika.", + :en + "Route intended for skiing. Not in use and unmaintained in summer. Ski styles provided in properties."}, + :tags {:fi ["hiihto" "hiihtolatu"]}, + :name {:fi "Hiihtolatu", :se "Skidspår", :en "Ski track"}, + :type-code 4402, + :main-category 4000, + :status "active", + :sub-category 4400, + :geometry-type "LineString", + :props + {:surface-material {:priority 80}, + :surface-material-info {:priority 80}, + :free-use? {:priority 40}, + :may-be-shown-in-excursion-map-fi? {:priority 0}, + :outdoor-exercise-machines? {:priority 80}, + :ski-track-traditional? {:priority 80}, + :route-width-m {:priority 97}, + :may-be-shown-in-harrastuspassi-fi? {:priority 0}, + :toilet? {:priority 70}, + :rest-places-count {:priority 70}, + :shooting-positions-count {:priority 80}, + :lit-route-length-km {:priority 98}, + :ski-track-freestyle? {:priority 80}, + :school-use? {:priority 40}, + :route-length-km {:priority 99}}}}) (def active (reduce-kv (fn [m k v] (if (not= "active" (:status v)) (dissoc m k) m)) all all)) From 538ce252f430fcdffc0a12659ce1a01b4daa821b Mon Sep 17 00:00:00 2001 From: Valtteri Harmainen Date: Thu, 14 Nov 2024 20:34:48 +0200 Subject: [PATCH 27/68] Fix grammar --- webapp/src/cljc/lipas/data/activities.cljc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/webapp/src/cljc/lipas/data/activities.cljc b/webapp/src/cljc/lipas/data/activities.cljc index 1b6285412..f05dcef42 100644 --- a/webapp/src/cljc/lipas/data/activities.cljc +++ b/webapp/src/cljc/lipas/data/activities.cljc @@ -227,10 +227,10 @@ ;; NOTE: select default value has to be be manually applied into the data during save or somewhere ;; for this field, it is done on lipas.ui.utils/make-saveable :default "active" - :label {:fi "UTP tietojen tila" + :label {:fi "UTP-tietojen tila" :se "Status för UTP-information" :en "Status of UTP data"} - :description {:fi "Aktiivisia tietoja voidaan siirtaa Lipas-järjestelmästä eteenpäin. Luonnos tilaiset tiedot eivät siirry eteenpäin." + :description {:fi "Aktiivisia tietoja voidaan siirtää Lipas-järjestelmästä eteenpäin. Luonnos-tilaiset tiedot eivät siirry eteenpäin." :se "Aktiv data kan överföras vidare från Lipas-systemet. Data med status utkast överförs inte vidare." :en "Active data can be transferred onward from the Lipas system. Draft status data will not be transferred onward."} :opts status-opts}} @@ -496,7 +496,7 @@ :description {:fi "Jos kohde on pyhiinvaellusreitti, aktivoi liukukytkin. HUOM! Pyhiinvaellusreitti on ulkoilureitti, joka tarjoaa mahdollisuuden liikkumiseen, hiljentymiseen ja hengellisyyteen/henkisyyteen.  Reitin varrelle on rakennettu mobiilisti tai maastoon opasteita ja sisältöjä, jotka ohjaavat vaeltajaa." :se "" :en ""} - :label {:fi "Pyhinvaelluskohde" + :label {:fi "Pyhiinvaelluskohde" :se "" :en "Pilgrimage destination"}}}) From 4c6ad6c148bcb952211c08d6918e21026556e32d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 31 Oct 2024 02:19:00 +0000 Subject: [PATCH 28/68] Bump elliptic from 6.5.7 to 6.6.0 in /webapp Bumps [elliptic](https://github.com/indutny/elliptic) from 6.5.7 to 6.6.0. - [Commits](https://github.com/indutny/elliptic/compare/v6.5.7...v6.6.0) --- updated-dependencies: - dependency-name: elliptic dependency-type: indirect ... Signed-off-by: dependabot[bot] --- webapp/package-lock.json | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/webapp/package-lock.json b/webapp/package-lock.json index 789843b63..fc3518800 100644 --- a/webapp/package-lock.json +++ b/webapp/package-lock.json @@ -1976,11 +1976,10 @@ "license": "ISC" }, "node_modules/elliptic": { - "version": "6.5.7", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.7.tgz", - "integrity": "sha512-ESVCtTwiA+XhY3wyh24QqRGBoP3rEdDUl3EDUUo9tft074fi19IrdpH7hLCMMP3CIj7jb3W96rn8lt/BqIlt5Q==", + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.0.tgz", + "integrity": "sha512-dpwoQcLc/2WLQvJvLRHKZ+f9FgOdjnq11rurqwekGQygGPsYSK29OMMD2WalatiqQ+XGFDglTNixpPfI+lpaAA==", "dev": true, - "license": "MIT", "dependencies": { "bn.js": "^4.11.9", "brorand": "^1.1.0", From 395f598fbb943c2ff2b792cc7e6eff674703b8b5 Mon Sep 17 00:00:00 2001 From: Valtteri Harmainen Date: Sun, 10 Nov 2024 12:51:42 +0200 Subject: [PATCH 29/68] Fix sports-site copy feature allowing all types via helper --- webapp/src/cljs/lipas/ui/map/views.cljs | 5 +++-- webapp/src/cljs/lipas/ui/sports_sites/subs.cljs | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/webapp/src/cljs/lipas/ui/map/views.cljs b/webapp/src/cljs/lipas/ui/map/views.cljs index 7910a10aa..4b2fb6872 100644 --- a/webapp/src/cljs/lipas/ui/map/views.cljs +++ b/webapp/src/cljs/lipas/ui/map/views.cljs @@ -283,9 +283,9 @@ (string/includes? (string/lower-case (string/join (% :tags))) lower-case-term)) table-data))) -(defn type-helper-table [{:keys [tr on-select]}] +(defn type-helper-table [{:keys [tr on-select types]}] (r/with-let [search-term (r/atom "") - table-data (<== [:lipas.ui.sports-sites.subs/type-table])] + table-data (<== [:lipas.ui.sports-sites.subs/type-table types])] (let [filtered-table-data (filter-by-term @search-term table-data) sorted-and-filtered-table-data (sort-by :name filtered-table-data)] [mui/grid {:container true} @@ -326,6 +326,7 @@ ;; Apu ankka table [type-helper-table {:tr tr + :types types :geom-help-open? geom-help-open? :on-select (fn [element] (swap! geom-help-open? not) diff --git a/webapp/src/cljs/lipas/ui/sports_sites/subs.cljs b/webapp/src/cljs/lipas/ui/sports_sites/subs.cljs index be77ee4df..f3b424018 100644 --- a/webapp/src/cljs/lipas/ui/sports_sites/subs.cljs +++ b/webapp/src/cljs/lipas/ui/sports_sites/subs.cljs @@ -154,8 +154,8 @@ (rf/reg-sub ::type-table :<- [::active-types] :<- [:lipas.ui.subs/locale] - (fn [[types locale]] - (for [[type-code m] types] + (fn [[types locale] [_ types-override]] + (for [[type-code m] (or types-override types)] {:type-code type-code :name (get-in m [:name locale]) :geometry-type (:geometry-type m) From ac3727f1f68152799d6754a88f7ea4a78efcfb44 Mon Sep 17 00:00:00 2001 From: Juho Teperi Date: Wed, 6 Nov 2024 15:19:33 +0200 Subject: [PATCH 30/68] Fix some activities set-field calls without lipas-id Rename the global fn so it isn't accidentally used instead of version with partially bounds args. --- .../src/cljs/lipas/ui/sports_sites/activities/views.cljs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/webapp/src/cljs/lipas/ui/sports_sites/activities/views.cljs b/webapp/src/cljs/lipas/ui/sports_sites/activities/views.cljs index 577260ff1..23793e530 100644 --- a/webapp/src/cljs/lipas/ui/sports_sites/activities/views.cljs +++ b/webapp/src/cljs/lipas/ui/sports_sites/activities/views.cljs @@ -18,7 +18,7 @@ (declare make-field) -(defn set-field +(defn set-field* [lipas-id & args] (==> [:lipas.ui.sports-sites.events/edit-field lipas-id (butlast args) (last args)])) @@ -894,7 +894,7 @@ (defn single-route [{:keys [read-only? route-props lipas-id type-code route activity-k - locale _label _description _set-field] + locale _label _description _set-field set-field] :as props}] (r/with-let [route-form-state (r/atom route) _ (add-watch route-form-state :lol @@ -1073,7 +1073,7 @@ geoms (<== [::subs/geoms read-only?]) geom-type (<== [::subs/geom-type read-only?]) value (<== [::subs/lipas-prop-value lipas-prop-k read-only?]) - set-field (partial set-field lipas-id :properties lipas-prop-k)] + set-field (partial set-field* lipas-id :properties lipas-prop-k)] [:<> ;; Because the value (from display-data) is completely different type than ;; edit-data, we need to display it using different component. Same logic as ->field. @@ -1288,7 +1288,7 @@ activity-k (-> activity :value keyword) field-sorter (<== [::subs/field-sorter activity-k]) locale (tr) - set-field (partial set-field lipas-id :activities activity-k) + set-field (partial set-field* lipas-id :activities activity-k) editing? (and can-edit? (<== [:lipas.ui.sports-sites.subs/editing? lipas-id])) read-only? (not editing?) props (or (some-> (get-in activity [:type->props type-code]) From 99b44bb11d1680a85f5e26598adcf2a208f08212 Mon Sep 17 00:00:00 2001 From: Juho Teperi Date: Tue, 19 Nov 2024 15:26:34 +0200 Subject: [PATCH 31/68] Fix resurrect BE call from FE --- webapp/src/cljs/lipas/ui/sports_sites/events.cljs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/webapp/src/cljs/lipas/ui/sports_sites/events.cljs b/webapp/src/cljs/lipas/ui/sports_sites/events.cljs index 8f384fcc8..bee580612 100644 --- a/webapp/src/cljs/lipas/ui/sports_sites/events.cljs +++ b/webapp/src/cljs/lipas/ui/sports_sites/events.cljs @@ -270,7 +270,8 @@ (let [site (get-in db [:sports-sites lipas-id]) rev (-> (utils/make-revision site (utils/timestamp)) (utils/make-editable) - (assoc :status "active")) + (assoc :status "active") + (utils/make-saveable)) draft false] {:dispatch [::commit-rev rev draft on-success on-failure]}))) From 2fda8ac82fc8a7f7cca07493c8f670e808242a9f Mon Sep 17 00:00:00 2001 From: Juho Teperi Date: Mon, 4 Nov 2024 17:03:15 +0200 Subject: [PATCH 32/68] Use OpenAI JSON schema response format --- webapp/src/clj/lipas/ai/core.clj | 53 +++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/webapp/src/clj/lipas/ai/core.clj b/webapp/src/clj/lipas/ai/core.clj index 8cebb35f3..4aee708ab 100644 --- a/webapp/src/clj/lipas/ai/core.clj +++ b/webapp/src/clj/lipas/ai/core.clj @@ -3,6 +3,7 @@ [clj-http.client :as client] [clojure.walk :as walk] [lipas.backend.config :as config] + [malli.json-schema :as json-schema] [taoensso.timbre :as log])) (def openai-config @@ -14,7 +15,7 @@ (def ptv-system-instruction "Olet avustaja, joka auttaa käyttäjiä tuottamaan sisältöä - Palvelutietovarantoon. Tuotat JSON-muotoista sisältöä. Sinulle + Palvelutietovarantoon. Sinulle esitetään kysymyksiä, ja käytät ensisijaisesti lähdeaineistoa ja toissijaisesti omaa tietoasi antaaksesi vastauksia. Noudata vastuksissa seuraavia tyyliohjeita: @@ -37,17 +38,10 @@ Annat vastaukset englanniksi, suomeksi ja ruotsiksi. Eri kieliversiot voivat poiketa kieliasultaan toisistaan. Tärkeää on, että kieliasu - on luettavaa ja selkeää. - -Vastauksesi sisältö on koodattu - JSON-objekteiksi. JSON-sisällön tarkka muoto voidaan antaa - kehotteessa. Anna käännetyt versiot kaikista pyydetyistä tiedoista - avaimilla \"fi\" suomeksi, \"se\" ruotsiksi ja \"en\" - englanniksi. Jos teksti sisältää lainauksia, käytä pakomerkkiä \\ - ennen lainausmerkkiä, jotta JSON-rakenne pysyy eheänä.") + on luettavaa ja selkeää.") (def ptv-system-instruction-v2 - "You are an assistant who helps users produce content for the Service Information Repository (Palvelutietovaranto). You generate content in JSON format. You will be asked questions and should primarily use source material and secondarily your own knowledge to provide answers. Follow these style guidelines in your responses: + "You are an assistant who helps users produce content for the Service Information Repository (Palvelutietovaranto). You will be asked questions and should primarily use source material and secondarily your own knowledge to provide answers. Follow these style guidelines in your responses: • Use a neutral tone in your responses. • Avoid promotional language. • The texts are not marketing communications. @@ -63,23 +57,45 @@ Vastauksesi sisältö on koodattu • Present only one topic per paragraph. • Divide the text into paragraphs. • A paragraph should contain a maximum of four sentences. -Provide answers in English, Finnish, and Swedish. Different language versions can differ in their phrasing. It is important that the language is readable and clear. - Your responses are encoded as JSON objects. The exact format of the JSON content can be specified in the prompt. Provide translated versions of all requested information with the keys \"fi\" for Finnish, \"se\" for Swedish, and \"en\" for English. If the text contains quotes, use an escape character \\ before the quotation mark to maintain the integrity of the JSON structure.") +Provide answers in English, Finnish, and Swedish. Different language versions can differ in their phrasing. It is important that the language is readable and clear.") (comment (println ptv-system-instruction-v2)) +(defn localized-string-schema [string-props] + [:map + {:closed true} + [:fi [:string string-props]] + [:se [:string string-props]] + [:en [:string string-props]]]) + +(def response-schema + [:map + {:json-schema/name "Reponse" + :closed true} + [:description (localized-string-schema nil)] + [:summary (localized-string-schema {:max 150})]]) + +(def Response + (json-schema/transform response-schema)) + (defn complete [{:keys [completions-url model n #_temperature top-p presence-penalty message-format max-tokens] - :or {message-format {:type "json_object"} - n 1 + :or {n 1 #_#_temperature 0 top-p 0.5 presence-penalty -2 max-tokens 4096}} system-instruction prompt] - (let [body {:model model + (let [;; Response format with JSON Schema should ensure + ;; the response is valid JSON and according to the schema, + ;; without specfying this in the prompts. + message-format (or message-format + {:type "json_schema" + :json_schema {:name "Response" + :schema Response}}) + body {:model model :n n :max_tokens max-tokens #_#_:temperature temperature @@ -91,7 +107,7 @@ Provide answers in English, Finnish, and Swedish. Different language versions ca params {:headers default-headers :body (json/encode body)}] - (log/info prompt) + (log/infof "AI Prompt: %s" prompt) (-> (client/post completions-url params) :body @@ -110,6 +126,8 @@ Provide answers in English, Finnish, and Swedish. Different language versions ca (defn ->prompt-doc [sports-site] + ;; Might include (some) of the UTP data now? + ;; Could be a good thing, but might make the prompt data too large? (walk/postwalk #(if (map? %) (dissoc % :geoms :geometries :simple-geoms :images :videos :id :fids :event-date) %) @@ -126,8 +144,7 @@ Provide answers in English, Finnish, and Swedish. Different language versions ca "Laadi tämän viestin lopussa olevan JSON-rakenteen kuvaamasta liikuntapaikasta tiivistelmä (max 150 merkkiä) ja pidempi tekstikuvaus, jotka sopivat Palvelutietovarannossa palvelun - kuvaukseen. Haluan vastauksen muodossa {\"description\": - {...käännökset...}, \"summary\" {...käännökset...}}. %s") + kuvaukseen. %s") (defn generate-ptv-service-descriptions [doc] From 3ff257d2806176bc7c1e14a9f93c225b01237962 Mon Sep 17 00:00:00 2001 From: Juho Teperi Date: Mon, 4 Nov 2024 17:04:54 +0200 Subject: [PATCH 33/68] Cleanup --- webapp/src/clj/lipas/ai/core.clj | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/webapp/src/clj/lipas/ai/core.clj b/webapp/src/clj/lipas/ai/core.clj index 4aee708ab..eab5405b5 100644 --- a/webapp/src/clj/lipas/ai/core.clj +++ b/webapp/src/clj/lipas/ai/core.clj @@ -71,8 +71,7 @@ Provide answers in English, Finnish, and Swedish. Different language versions ca (def response-schema [:map - {:json-schema/name "Reponse" - :closed true} + {:closed true} [:description (localized-string-schema nil)] [:summary (localized-string-schema {:max 150})]]) From c3d0ed939276695ba51dbb773c0e97913b81afdc Mon Sep 17 00:00:00 2001 From: Juho Teperi Date: Mon, 4 Nov 2024 17:11:49 +0200 Subject: [PATCH 34/68] Fix AI schema --- webapp/src/clj/lipas/ai/core.clj | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/webapp/src/clj/lipas/ai/core.clj b/webapp/src/clj/lipas/ai/core.clj index eab5405b5..6a6fa8e3e 100644 --- a/webapp/src/clj/lipas/ai/core.clj +++ b/webapp/src/clj/lipas/ai/core.clj @@ -73,7 +73,10 @@ Provide answers in English, Finnish, and Swedish. Different language versions ca [:map {:closed true} [:description (localized-string-schema nil)] - [:summary (localized-string-schema {:max 150})]]) + ;; Structured Outputs doesn't support maxLength + ;; https://platform.openai.com/docs/guides/structured-outputs#some-type-specific-keywords-are-not-yet-supported + ;; The prompt mentions summary should be max 150 chars + [:summary (localized-string-schema nil #_{:max 150})]]) (def Response (json-schema/transform response-schema)) @@ -93,6 +96,10 @@ Provide answers in English, Finnish, and Swedish. Different language versions ca message-format (or message-format {:type "json_schema" :json_schema {:name "Response" + ;; This is probably needed? Providing an unsupported Schema, + ;; like with maxLength, without this doesn't throw an error, + ;; but with this enabled it does. + :strict true :schema Response}}) body {:model model :n n From d5d4688762a0a8c02dc9c8379123ae878bebcac2 Mon Sep 17 00:00:00 2001 From: Juho Teperi Date: Mon, 4 Nov 2024 17:31:48 +0200 Subject: [PATCH 35/68] Make ptv tokens per org-id --- webapp/src/clj/lipas/integration/ptv/core.clj | 84 +++++++++++-------- webapp/src/cljc/lipas/data/ptv.cljc | 10 ++- webapp/src/cljs/lipas/ui/ptv/events.cljs | 5 ++ webapp/src/cljs/lipas/ui/ptv/views.cljs | 2 + 4 files changed, 67 insertions(+), 34 deletions(-) diff --git a/webapp/src/clj/lipas/integration/ptv/core.clj b/webapp/src/clj/lipas/integration/ptv/core.clj index 92348d2f0..018e01faa 100644 --- a/webapp/src/clj/lipas/integration/ptv/core.clj +++ b/webapp/src/clj/lipas/integration/ptv/core.clj @@ -19,8 +19,7 @@ :service-url "https://api.palvelutietovaranto.trn.suomi.fi/api/v11/Service" :service-location-url "https://api.palvelutietovaranto.trn.suomi.fi/api/v11/ServiceChannel/ServiceLocation" :creds - {:org-id ptv-data/uta-org-id-test - :main-user + {:main-user {:username "paakayttaja41.testi@testi.fi" :password "Paatestaaja41-1041*"} :maintainer @@ -38,8 +37,7 @@ :service-url "https://api.palvelutietovaranto.trn.suomi.fi/api/v11/Service" :service-location-url "https://api.palvelutietovaranto.trn.suomi.fi/api/v11/ServiceChannel/ServiceLocation" :creds - {:org-id ptv-data/uta-org-id-test - :main-user + {:main-user {:username "paakayttaja35.testi@testi.fi" :password "Paatestaaja35-1035*"} :maintainer @@ -49,7 +47,9 @@ {:username "API14@testi.fi" :password "APIinterfaceUser14-1014*"}}}) -(def current-token (atom nil)) +;; Org-id => {:token ... :payload ...} +;; TODO: Move this to IG component state? +(defonce current-token (atom {})) (defn unix-time [] (/ (System/currentTimeMillis) 1000)) @@ -87,15 +87,17 @@ (-> token (str/split #"\.") second b64/decode (String.) (json/decode keyword))) (defn get-token - [] - (if (or (not @current-token) (expired? (:payload @current-token))) - (let [new-token (authenticate {:token-url (:token-url test-config) - :username (get-in test-config [:creds :api :username]) - :password (get-in test-config [:creds :api :password]) - :org-id (get-in test-config [:creds :org-id])})] - (:token (reset! current-token {:token new-token - :payload (parse-payload new-token)}))) - (:token @current-token))) + [org-id] + ;; NOTE: deref + swap + (let [x (get @current-token org-id)] + (if (or (not x) (expired? (:payload x))) + (let [new-token (authenticate {:token-url (:token-url test-config) + :username (get-in test-config [:creds :api :username]) + :password (get-in test-config [:creds :api :password]) + :org-id org-id})] + (:token (swap! current-token assoc org-id {:token new-token + :payload (parse-payload new-token)}))) + (:token x)))) (def ->ptv-service ptv-data/->ptv-service) (def ->ptv-service-location ptv-data/->ptv-service-location) @@ -104,22 +106,34 @@ ;; return :sourceId (wtf) (defn get-org-services [{:keys [service-url token] - :or {service-url (:service-url test-config) - token (get-token)}} + :or {service-url (:service-url test-config)}} org-id] - (let [params {:headers {:Content-Type "application/json" + (let [token (or token (get-token org-id)) + params {:headers {:Content-Type "application/json" :Authorization (str "bearer " token)} :query-params {:organizationId org-id}}] (-> (client/get (str service-url "/list/organization") params) :body (json/decode keyword)))) +(defn get-org-service-channels + [{:keys [api-url token] + :or {api-url (:api-url test-config)}} + org-id] + (let [token (or token (get-token org-id)) + params {:headers {:Content-Type "application/json" + :Authorization (str "bearer " token)}}] + (-> (client/get (str api-url "/api/v11/ServiceChannel/organization/" org-id) params) + :body + (json/decode keyword)))) + (defn create-service - [{:keys [service-url token] - :or {service-url (:service-url test-config) - token (get-token)}} + [{:keys [org-id service-url token] + :or {service-url (:service-url test-config)} + :as _config} service] - (let [params {:headers {:Content-Type "application/json" + (let [token (or token (get-token org-id)) + params {:headers {:Content-Type "application/json" :Authorization (str "bearer " token)} :body (json/encode service)}] (log/info "Create PTV service" service) @@ -128,13 +142,13 @@ (json/decode keyword)))) (defn update-service - [{:keys [service-url token _org-id] - :or {service-url (:service-url test-config) - token (get-token)}} + [{:keys [service-url token org-id] + :or {service-url (:service-url test-config)}} service-id data] (log/info "Update PTV service with id " service-id "and data" data) - (let [ params {:headers {:Content-Type "application/json" + (let [token (or token (get-token org-id)) + params {:headers {:Content-Type "application/json" :Authorization (str "bearer " token)} :body (json/encode data)}] (-> (client/put (str service-url "/" service-id) params) @@ -142,11 +156,11 @@ (json/decode keyword)))) (defn create-service-location - [{:keys [service-location-url token _org-id] - :or {service-location-url (:service-location-url test-config) - token (get-token)}} + [{:keys [service-location-url token org-id] + :or {service-location-url (:service-location-url test-config)}} service-location] - (let [params {:headers {:Content-Type "application/json" + (let [token (or token (get-token org-id)) + params {:headers {:Content-Type "application/json" :Authorization (str "bearer " token)} :body (json/encode service-location)}] (log/info "Create PTV service location" service-location) @@ -155,12 +169,12 @@ (json/decode keyword)))) (defn update-service-location - [{:keys [service-location-url token _org-id] - :or {service-location-url (:service-location-url test-config) - token (get-token)}} + [{:keys [service-location-url token org-id] + :or {service-location-url (:service-location-url test-config)}} service-location-id data] - (let [params {:headers {:Content-Type "application/json" + (let [token (or token (get-token org-id)) + params {:headers {:Content-Type "application/json" :Authorization (str "bearer " token)} :body (json/encode data)}] (-> (client/put (str service-location-url "/" service-location-id) params) @@ -192,3 +206,7 @@ :hits :hits (->> (map :_source))))) + +(comment + (get-org-services {} ptv-data/liminka-org-id-test) + (get-org-service-channels {} ptv-data/liminka-org-id-test)) diff --git a/webapp/src/cljc/lipas/data/ptv.cljc b/webapp/src/cljc/lipas/data/ptv.cljc index a00b101d5..0d377aa55 100644 --- a/webapp/src/cljc/lipas/data/ptv.cljc +++ b/webapp/src/cljc/lipas/data/ptv.cljc @@ -13,14 +13,22 @@ ;; json-patch https://github.com/borgeby/clj-json-pointer +;; org 10 #_(def uta-org-id-test "52e0f6dc-ec1f-48d5-a0a2-7a4d8b657d53") ;; Testiorganisaatio 6 (Kunta) (def uta-org-id-test "3d1759a2-e47a-4947-9a31-cab1c1e2512b") -< + +;; org 9 +(def liminka-org-id-test "7fdd7f84-e52a-4c17-a59a-d7c2a3095ed5") + +;; org 8 #_(def uta-org-id-test "92374b0f-7d3c-4017-858e-666ee3ca2761") #_(def uta-org-id-prod "7b83257d-06ad-4e3b-985d-16a5c9d3fced") +;; TODO: Tulossa 5 kuntaa, muut: +;; (Lumijoki. Pyhäjärvi, Ii, Liminka ja Oulu sekä tietenkin bonuksena Utajärvi). + (def lang->locale {"fi" :fi, "sv" :se, "en" :en}) diff --git a/webapp/src/cljs/lipas/ui/ptv/events.cljs b/webapp/src/cljs/lipas/ui/ptv/events.cljs index 28fc941bc..312945c80 100644 --- a/webapp/src/cljs/lipas/ui/ptv/events.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/events.cljs @@ -35,6 +35,11 @@ {:org-id ptv-data/uta-org-id-test :city-codes [889] :owners ["city" "city-main-owner"] + :supported-languages ["fi" "se" "en"]} + ptv-data/liminka-org-id-test + {:org-id ptv-data/liminka-org-id-test + :city-codes [425] + :owners ["city" "city-main-owner"] :supported-languages ["fi" "se" "en"]}}) (rf/reg-event-fx ::fetch-integration-candidates diff --git a/webapp/src/cljs/lipas/ui/ptv/views.cljs b/webapp/src/cljs/lipas/ui/ptv/views.cljs index 931496d23..fdf8a7eae 100644 --- a/webapp/src/cljs/lipas/ui/ptv/views.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/views.cljs @@ -20,6 +20,8 @@ (def orgs [{:name "Utajärven kunta (test)" :id ptv-data/uta-org-id-test} + {:name "Limingan kunta (test)" + :id ptv-data/liminka-org-id-test} #_{:name "Utajärven kunta (prod)" :id ptv-data/uta-org-id-prod}]) From 30228f27bb005d2bf1e5dce04b4d4950ea809772 Mon Sep 17 00:00:00 2001 From: Juho Teperi Date: Tue, 5 Nov 2024 09:30:38 +0200 Subject: [PATCH 36/68] Log AI result --- webapp/src/clj/lipas/ai/core.clj | 23 +++++++++---------- webapp/src/clj/lipas/integration/ptv/core.clj | 2 +- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/webapp/src/clj/lipas/ai/core.clj b/webapp/src/clj/lipas/ai/core.clj index 6a6fa8e3e..6d4ba1d21 100644 --- a/webapp/src/clj/lipas/ai/core.clj +++ b/webapp/src/clj/lipas/ai/core.clj @@ -110,25 +110,24 @@ Provide answers in English, Finnish, and Swedish. Different language versions ca :response_format message-format :messages [{:role "system" :content system-instruction} {:role "user" :content prompt}]} + _ (log/infof "AI Prompt sent: %s" prompt) params {:headers default-headers - :body (json/encode body)}] - - (log/infof "AI Prompt: %s" prompt) - - (-> (client/post completions-url params) - :body - (json/decode keyword) - :choices - first - (update-in [:message :content] #(json/decode % keyword))))) + :body (json/encode body)} + result (-> (client/post completions-url params) + :body + (json/decode keyword) + :choices + first + (update-in [:message :content] #(json/decode % keyword)))] + (log/infof "AI Result: %s" result) + result)) (def generate-utp-descriptions-prompt "Laadi tämän viestin lopussa olevan JSON-rakenteen kuvaamasta liikuntapaikasta tiivistelmä (max 150 merkkiä) ja tekstikuvaus, jotka sopivat Palvelutietovarannossa palvelupaikan kuvaukseen. Yksityiskohtaiset rakennustekniset tiedot ja olosuhdetiedot jätetään kuvauksista - pois. Haluan vastauksen muodossa {\"description\": - {...käännökset...}, \"summary\" {...käännökset...}}. %s") + pois. %s") (defn ->prompt-doc [sports-site] diff --git a/webapp/src/clj/lipas/integration/ptv/core.clj b/webapp/src/clj/lipas/integration/ptv/core.clj index 018e01faa..72853cd3a 100644 --- a/webapp/src/clj/lipas/integration/ptv/core.clj +++ b/webapp/src/clj/lipas/integration/ptv/core.clj @@ -123,7 +123,7 @@ (let [token (or token (get-token org-id)) params {:headers {:Content-Type "application/json" :Authorization (str "bearer " token)}}] - (-> (client/get (str api-url "/api/v11/ServiceChannel/organization/" org-id) params) + (-> (client/get (str api-url "/v11/ServiceChannel/organization/" org-id) params) :body (json/decode keyword)))) From eb69030888eac87b0f21a88565613da5dce51f35 Mon Sep 17 00:00:00 2001 From: Juho Teperi Date: Tue, 5 Nov 2024 15:28:26 +0200 Subject: [PATCH 37/68] Reorganize ptv backend code --- webapp/src/clj/lipas/backend/core.clj | 99 ------- webapp/src/clj/lipas/backend/handler.clj | 115 ++------ webapp/src/clj/lipas/backend/ptv.clj | 23 +- .../lipas/{ai/core.clj => backend/ptv/ai.clj} | 5 +- webapp/src/clj/lipas/backend/ptv/core.clj | 109 +++++++ webapp/src/clj/lipas/backend/ptv/handler.clj | 72 +++++ .../src/clj/lipas/backend/ptv/integration.clj | 266 ++++++++++++++++++ webapp/src/clj/lipas/integration/ptv/core.clj | 212 -------------- webapp/src/cljs/lipas/ui/map/projection.cljs | 2 +- 9 files changed, 481 insertions(+), 422 deletions(-) rename webapp/src/clj/lipas/{ai/core.clj => backend/ptv/ai.clj} (99%) create mode 100644 webapp/src/clj/lipas/backend/ptv/core.clj create mode 100644 webapp/src/clj/lipas/backend/ptv/handler.clj create mode 100644 webapp/src/clj/lipas/backend/ptv/integration.clj delete mode 100644 webapp/src/clj/lipas/integration/ptv/core.clj diff --git a/webapp/src/clj/lipas/backend/core.clj b/webapp/src/clj/lipas/backend/core.clj index 987dcf77e..2ae269a3b 100644 --- a/webapp/src/clj/lipas/backend/core.clj +++ b/webapp/src/clj/lipas/backend/core.clj @@ -7,7 +7,6 @@ [clojure.java.jdbc :as jdbc] [clojure.string :as str] [dk.ative.docjure.spreadsheet :as excel] - [lipas.ai.core :as ai] [lipas.backend.accessibility :as accessibility] [lipas.backend.analysis.diversity :as diversity] [lipas.backend.analysis.reachability :as reachability] @@ -24,7 +23,6 @@ [lipas.data.owners :as owners] [lipas.data.types :as types] [lipas.i18n.core :as i18n] - [lipas.integration.ptv.core :as ptv] [lipas.integration.utp.cms :as utp-cms] [lipas.reports :as reports] [lipas.roles :as roles] @@ -905,103 +903,6 @@ [{:keys [_filename _data _user] :as params}] (utp-cms/upload-image! params)) -;; PTV -(defn get-ptv-integration-candidates - [search criteria] - (ptv/get-eligible-sites search criteria)) - -(defn generate-ptv-descriptions - [{:keys [client indices] :as _search} - {:keys [lipas-id]}] - (let [idx (get-in indices [:sports-site :search]) - doc (-> (search/fetch-document client idx lipas-id) :body :_source)] - (-> (ai/generate-ptv-descriptions doc) - :message - :content))) - -(defn make-overview - [sites] - {:city-name (->> sites first :search-meta :location :city :name) - :service-name (->> sites first :search-meta :type :sub-category :name) - :sports-facilities (for [site sites] - {:type (-> site :search-meta :type :name :fi)})}) - -(defn generate-ptv-service-descriptions - [search - {:keys [_id sub-category-id city-codes]}] - (let [type-codes (->> (types/by-sub-category sub-category-id) - (map :type-code)) - sites (ptv/get-eligible-sites search {:type-codes type-codes - :city-codes city-codes - :owners ["city" "city-main-owner"]}) - doc (make-overview sites)] - (-> (ai/generate-ptv-service-descriptions doc) - :message - :content))) - -(defn upsert-ptv-service! - [{:keys [id source-id] :as m}] - {:pre [(some? source-id)]} - (let [config {:org-id (get-in ptv/test-config [:creds :org-id])} - data (ptv/->ptv-service (merge config m))] - (if id - (ptv/update-service config id data) - (ptv/create-service config data)))) - -(defn fetch-ptv-services - [{:keys [org-id] :as m}] - {:pre [(some? org-id)]} - (ptv/get-org-services {} org-id)) - -(def persisted-ptv-keys [:languages - :summary - :description - :last-sync - :org-id - :sync-enabled - :service-integration - :descriptions-integration - :service-channel-integration - :service-ids - :service-channel-ids]) - -(defn upsert-ptv-service-location! - [db search user {:keys [org ptv-meta sports-site] :as m}] - (assert (:lipas-id sports-site)) - (let [site (db/get-sports-site db (:lipas-id sports-site)) - _ (assert (some? site) - (str "Sports site " (:lipas-id sports-site) " not found in DB")) - config {:org-id (get-in ptv/test-config [:creds :org-id])} - id (first (get-in site [:ptv :service-channel-ids])) - site (update site :ptv merge ptv-meta) - data (ptv/->ptv-service-location org gis/wgs84->tm35fin-no-wrap (enrich site)) - ptv-resp (if id - (ptv/update-service-location config id data) - (ptv/create-service-location config data)) - now (utils/timestamp)] - - (save-sports-site! db search user (-> site - (assoc :event-date now) - (assoc :ptv (-> ptv-meta - (select-keys persisted-ptv-keys) - (assoc :last-sync now))))) - - ptv-resp)) - -(defn save-ptv-integration-definitions - "Saves ptv definitions under key :ptv. Does not notify webhooks, - integrations or analysis queues since they're not likely interested - in this." - [db search user lipas-id->ptv-meta] - (jdbc/with-db-transaction [tx db] - (doseq [[lipas-id ptv] lipas-id->ptv-meta] - ;; TODO take when-let -> let and add assert - (when-let [site (-> (get-sports-site tx lipas-id) - (assoc :event-date (utils/timestamp)) - (assoc :ptv ptv))] - (upsert-sports-site! tx user site) - (index! search site :sync))))) - (comment (require '[lipas.backend.config :as config]) (def db-spec (:db config/default-config)) diff --git a/webapp/src/clj/lipas/backend/handler.clj b/webapp/src/clj/lipas/backend/handler.clj index 79ffbad73..140571aab 100644 --- a/webapp/src/clj/lipas/backend/handler.clj +++ b/webapp/src/clj/lipas/backend/handler.clj @@ -1,25 +1,25 @@ (ns lipas.backend.handler - (:require - [clojure.java.io :as io] - [clojure.spec.alpha :as s] - [lipas.backend.core :as core] - [lipas.backend.jwt :as jwt] - [lipas.backend.middleware :as mw] - [lipas.roles :as roles] - [lipas.schema.core] - [lipas.utils :as utils] - [muuntaja.core :as m] - [reitit.coercion.spec] - [reitit.ring :as ring] - [reitit.ring.coercion :as coercion] - [reitit.ring.middleware.exception :as exception] - [reitit.ring.middleware.multipart :as multipart] - [reitit.ring.middleware.muuntaja :as muuntaja] - [reitit.swagger :as swagger] - [reitit.swagger-ui :as swagger-ui] - [ring.middleware.params :as params] - [ring.util.io :as ring-io] - [taoensso.timbre :as log])) + (:require [clojure.java.io :as io] + [clojure.spec.alpha :as s] + [lipas.backend.core :as core] + [lipas.backend.jwt :as jwt] + [lipas.backend.middleware :as mw] + [lipas.backend.ptv.handler :as ptv-handler] + [lipas.roles :as roles] + [lipas.schema.core] + [lipas.utils :as utils] + [muuntaja.core :as m] + [reitit.coercion.spec] + [reitit.ring :as ring] + [reitit.ring.coercion :as coercion] + [reitit.ring.middleware.exception :as exception] + [reitit.ring.middleware.multipart :as multipart] + [reitit.ring.middleware.muuntaja :as muuntaja] + [reitit.swagger :as swagger] + [reitit.swagger-ui :as swagger-ui] + [ring.middleware.params :as params] + [ring.util.io :as ring-io] + [taoensso.timbre :as log])) (defn exception-handler ([status type] @@ -54,7 +54,7 @@ exception-handlers))) (defn create-app - [{:keys [db emailer search mailchimp aws]}] + [{:keys [db emailer search mailchimp aws] :as ctx}] (ring/ring-handler (ring/router @@ -705,76 +705,7 @@ {:status 200 :body (core/search-lois-with-params search body-params)})}}] - ;; PTV - ["/actions/get-ptv-integration-candidates" - {:post - {:no-doc false - :require-role :ptv/manage - :parameters {:body map?} - :handler - (fn [{:keys [body-params]}] - {:status 200 - :body (core/get-ptv-integration-candidates search body-params)})}}] - - ["/actions/generate-ptv-descriptions" - {:post - {:no-doc false - :require-role :ptv/manage - :parameters {:body map?} - :handler - (fn [{:keys [body-params]}] - {:status 200 - :body (core/generate-ptv-descriptions search body-params)})}}] - - ["/actions/generate-ptv-service-descriptions" - {:post - {:no-doc false - :require-role :ptv/manage - :parameters {:body map?} - :handler - (fn [{:keys [body-params]}] - {:status 200 - :body (core/generate-ptv-service-descriptions search body-params)})}}] - - ["/actions/save-ptv-service" - {:post - {:no-doc false - :require-role :ptv/manage - :parameters {:body map?} - :handler - (fn [{:keys [body-params]}] - {:status 200 - :body (core/upsert-ptv-service! body-params)})}}] - - ["/actions/fetch-ptv-services" - {:post - {:no-doc false - :require-role :ptv/manage - :parameters {:body map?} - :handler - (fn [{:keys [body-params]}] - {:status 200 - :body (core/fetch-ptv-services body-params)})}}] - - ["/actions/save-ptv-service-location" - {:post - {:no-doc false - :require-role :ptv/manage - :parameters {:body map?} - :handler - (fn [{:keys [body-params identity]}] - {:status 200 - :body (core/upsert-ptv-service-location! db search identity body-params)})}}] - - ["/actions/save-ptv-meta" - {:post - {:no-doc false - :require-role :ptv/manage - :parameters {:body map?} - :handler - (fn [{:keys [body-params identity]}] - {:status 200 - :body (core/save-ptv-integration-definitions db search identity body-params)})}}]]] + (ptv-handler/routes ctx)]] {:data {:coercion reitit.coercion.spec/coercion diff --git a/webapp/src/clj/lipas/backend/ptv.clj b/webapp/src/clj/lipas/backend/ptv.clj index 48033285f..d063e51d4 100644 --- a/webapp/src/clj/lipas/backend/ptv.clj +++ b/webapp/src/clj/lipas/backend/ptv.clj @@ -1,8 +1,7 @@ (ns lipas.backend.ptv - (:require - [cheshire.core :as json] - [clj-http.client :as client] - [lipas.data.types :as types])) + (:require [cheshire.core :as json] + [clj-http.client :as client] + [lipas.data.types :as types])) ;; Exploring PTV prod data @@ -17,8 +16,8 @@ :query-params {:uri class-uri :page page}}) - :body - (json/decode keyword))) + :body + (json/decode keyword))) (defn get-services-channels-by-type [type page] @@ -26,8 +25,8 @@ {:headers headers :query-params {:page page}}) - :body - (json/decode keyword))) + :body + (json/decode keyword))) (comment @@ -40,10 +39,4 @@ "http://uri.suomi.fi/codelist/ptv/ptvserclass2/code/P27.1"] (def p1 (get-services-by-class "http://uri.suomi.fi/codelist/ptv/ptvserclass2/code/P27.2" 1)) - (def p2 (get-services-by-class "http://uri.suomi.fi/codelist/ptv/ptvserclass2/code/P27.2" 2)) - - - - - - ) + (def p2 (get-services-by-class "http://uri.suomi.fi/codelist/ptv/ptvserclass2/code/P27.2" 2))) diff --git a/webapp/src/clj/lipas/ai/core.clj b/webapp/src/clj/lipas/backend/ptv/ai.clj similarity index 99% rename from webapp/src/clj/lipas/ai/core.clj rename to webapp/src/clj/lipas/backend/ptv/ai.clj index 6d4ba1d21..237351167 100644 --- a/webapp/src/clj/lipas/ai/core.clj +++ b/webapp/src/clj/lipas/backend/ptv/ai.clj @@ -1,4 +1,4 @@ -(ns lipas.ai.core +(ns lipas.backend.ptv.ai (:require [cheshire.core :as json] [clj-http.client :as client] [clojure.walk :as walk] @@ -167,5 +167,4 @@ Provide answers in English, Finnish, and Swedish. Different language versions ca (comment (get-models openai-config) - (complete openai-config ptv-system-instruction "Why volcanoes erupt?") - ) + (complete openai-config ptv-system-instruction "Why volcanoes erupt?")) diff --git a/webapp/src/clj/lipas/backend/ptv/core.clj b/webapp/src/clj/lipas/backend/ptv/core.clj new file mode 100644 index 000000000..3caa4def9 --- /dev/null +++ b/webapp/src/clj/lipas/backend/ptv/core.clj @@ -0,0 +1,109 @@ +(ns lipas.backend.ptv.core + (:require [clojure.java.jdbc :as jdbc] + [lipas.backend.core :as core] + [lipas.backend.db.db :as db] + [lipas.backend.gis :as gis] + [lipas.backend.ptv.ai :as ai] + [lipas.backend.ptv.integration :as ptv] + [lipas.backend.search :as search] + [lipas.data.ptv :as ptv-data] + [lipas.data.types :as types] + [lipas.utils :as utils])) + +(defn get-ptv-integration-candidates + [search criteria] + (ptv/get-eligible-sites search criteria)) + +(defn generate-ptv-descriptions + [{:keys [client indices] :as _search} + {:keys [lipas-id]}] + (let [idx (get-in indices [:sports-site :search]) + doc (-> (search/fetch-document client idx lipas-id) :body :_source)] + (-> (ai/generate-ptv-descriptions doc) + :message + :content))) + +(defn make-overview + [sites] + {:city-name (->> sites first :search-meta :location :city :name) + :service-name (->> sites first :search-meta :type :sub-category :name) + :sports-facilities (for [site sites] + {:type (-> site :search-meta :type :name :fi)})}) + +(defn generate-ptv-service-descriptions + [search + {:keys [_id sub-category-id city-codes]}] + (let [type-codes (->> (types/by-sub-category sub-category-id) + (map :type-code)) + sites (ptv/get-eligible-sites search {:type-codes type-codes + :city-codes city-codes + :owners ["city" "city-main-owner"]}) + doc (make-overview sites)] + (-> (ai/generate-ptv-service-descriptions doc) + :message + :content))) + +(defn upsert-ptv-service! + [{:keys [id source-id] :as m}] + {:pre [(some? source-id)]} + (let [config nil + data (ptv-data/->ptv-service (merge config m))] + (if id + (ptv/update-service config id data) + (ptv/create-service config data)))) + +(defn fetch-ptv-services + [{:keys [org-id] :as _m}] + {:pre [(some? org-id)]} + (ptv/get-org-services {} org-id)) + +(def persisted-ptv-keys [:languages + :summary + :description + :last-sync + :org-id + :sync-enabled + :service-integration + :descriptions-integration + :service-channel-integration + :service-ids + :service-channel-ids]) + +(defn upsert-ptv-service-location! + [db search user {:keys [org ptv-meta sports-site] :as _m}] + (assert (:lipas-id sports-site)) + (let [site (db/get-sports-site db (:lipas-id sports-site)) + _ (assert (some? site) + (str "Sports site " (:lipas-id sports-site) " not found in DB")) + ;; FIXME: + config {:org-id (get-in ptv/test-config [:creds :org-id])} + id (first (get-in site [:ptv :service-channel-ids])) + site (update site :ptv merge ptv-meta) + data (ptv-data/->ptv-service-location org gis/wgs84->tm35fin-no-wrap (core/enrich site)) + ptv-resp (if id + (ptv/update-service-location config id data) + (ptv/create-service-location config data)) + now (utils/timestamp)] + + (core/save-sports-site! db search user + (-> site + (assoc :event-date now) + (assoc :ptv (-> ptv-meta + (select-keys persisted-ptv-keys) + (assoc :last-sync now))))) + + ptv-resp)) + +(defn save-ptv-integration-definitions + "Saves ptv definitions under key :ptv. Does not notify webhooks, + integrations or analysis queues since they're not likely interested + in this." + [db search user lipas-id->ptv-meta] + (jdbc/with-db-transaction [tx db] + (doseq [[lipas-id ptv] lipas-id->ptv-meta] + ;; TODO take when-let -> let and add assert + (when-let [site (-> (core/get-sports-site tx lipas-id) + (assoc :event-date (utils/timestamp)) + (assoc :ptv ptv))] + (core/upsert-sports-site! tx user site) + (core/index! search site :sync))))) diff --git a/webapp/src/clj/lipas/backend/ptv/handler.clj b/webapp/src/clj/lipas/backend/ptv/handler.clj new file mode 100644 index 000000000..9c9daea95 --- /dev/null +++ b/webapp/src/clj/lipas/backend/ptv/handler.clj @@ -0,0 +1,72 @@ +(ns lipas.backend.ptv.handler + (:require [lipas.backend.ptv.core :as ptv-core])) + +(defn routes [{:keys [db search] :as _ctx}] + [["/actions/get-ptv-integration-candidates" + {:post + {:no-doc false + :require-privilege :ptv/manage + :handler + (fn [{:keys [body-params]}] + {:status 200 + :body (ptv-core/get-ptv-integration-candidates search body-params)})}}] + + ["/actions/generate-ptv-descriptions" + {:post + {:no-doc false + :require-privilege :ptv/manage + :parameters {:body map?} + :handler + (fn [{:keys [body-params]}] + {:status 200 + :body (ptv-core/generate-ptv-descriptions search body-params)})}}] + + ["/actions/generate-ptv-service-descriptions" + {:post + {:no-doc false + :require-privilege :ptv/manage + :parameters {:body map?} + :handler + (fn [{:keys [body-params]}] + {:status 200 + :body (ptv-core/generate-ptv-service-descriptions search body-params)})}}] + + ["/actions/save-ptv-service" + {:post + {:no-doc false + :require-privilege :ptv/manage + :parameters {:body map?} + :handler + (fn [{:keys [body-params]}] + {:status 200 + :body (ptv-core/upsert-ptv-service! body-params)})}}] + + ["/actions/fetch-ptv-services" + {:post + {:no-doc false + :require-privilege :ptv/manage + :parameters {:body map?} + :handler + (fn [{:keys [body-params]}] + {:status 200 + :body (ptv-core/fetch-ptv-services body-params)})}}] + + ["/actions/save-ptv-service-location" + {:post + {:no-doc false + :require-privilege :ptv/manage + :parameters {:body map?} + :handler + (fn [{:keys [body-params identity]}] + {:status 200 + :body (ptv-core/upsert-ptv-service-location! db search identity body-params)})}}] + + ["/actions/save-ptv-meta" + {:post + {:no-doc false + :require-privilege :ptv/manage + :parameters {:body map?} + :handler + (fn [{:keys [body-params identity]}] + {:status 200 + :body (ptv-core/save-ptv-integration-definitions db search identity body-params)})}}]]) diff --git a/webapp/src/clj/lipas/backend/ptv/integration.clj b/webapp/src/clj/lipas/backend/ptv/integration.clj new file mode 100644 index 000000000..369f05b33 --- /dev/null +++ b/webapp/src/clj/lipas/backend/ptv/integration.clj @@ -0,0 +1,266 @@ +(ns lipas.backend.ptv.integration + (:require [buddy.core.codecs.base64 :as b64] + [cheshire.core :as json] + [clj-http.client :as client] + [clojure.string :as str] + [lipas.backend.config :as config] + [lipas.backend.search :as search] + [lipas.data.ptv :as ptv-data] + [lipas.utils :as utils] + [taoensso.timbre :as log])) + +(defn http [req] + (try + (let [req (assoc req + :accept :json + :as :json) + req (if (:form-params req) + (assoc req :content-type :json) + req) + resp (client/request req)] + resp) + (catch clojure.lang.ExceptionInfo e + (let [d (ex-data e)] + (throw (ex-info (format "HTTP Error: %s %s" (:status d) (:body d)) + {:resp d} + nil)))))) + +;; Test creds are OK to "leak" to VCS since they're public anyway +(def test-config + (utils/deep-merge + (get config/default-config :ptv) + {:api-url "https://api.palvelutietovaranto.trn.suomi.fi/api" + :token-url "https://palvelutietovaranto.trn.suomi.fi/api/auth/api-login" + :service-url "https://api.palvelutietovaranto.trn.suomi.fi/api/v11/Service" + :service-location-url "https://api.palvelutietovaranto.trn.suomi.fi/api/v11/ServiceChannel/ServiceLocation" + :creds + {:main-user + {:username "paakayttaja41.testi@testi.fi" + :password "Paatestaaja41-1041*"} + :maintainer + {:username "" + :password ""} + :api + ;; org 10 + #_{:username "API17@testi.fi" + :password "APIinterfaceUser17-1017*"} + ;; org 6 + #_{:username "API9@testi.fi" + :password "APIinterfaceUser9-1009*"} + ;; org 9 + {:username "API15@testi.fi" + :password "APIinterfaceUser15-1015*"}}})) + +#_(def test-config + {:api-url "https://api.palvelutietovaranto.trn.suomi.fi/api" + :token-url "https://palvelutietovaranto.trn.suomi.fi/api/auth/api-login" + :service-url "https://api.palvelutietovaranto.trn.suomi.fi/api/v11/Service" + :service-location-url "https://api.palvelutietovaranto.trn.suomi.fi/api/v11/ServiceChannel/ServiceLocation" + :creds + {:main-user + {:username "paakayttaja35.testi@testi.fi" + :password "Paatestaaja35-1035*"} + :maintainer + {:username "yllapitaja35.testi@testi.fi" + :password "Yllapitajatestaaja35-1035*"} + :api + {:username "API14@testi.fi" + :password "APIinterfaceUser14-1014*"}}}) + +;; Org-id => {:token ... :payload ...} +;; TODO: Move this to IG component state? +(def current-token (atom {})) + +(defn unix-time [] + (/ (System/currentTimeMillis) 1000)) + +(defn expired? + [{:keys [exp]}] + (< exp (long (unix-time)))) + +(defn test-env? + [url] + (str/includes? url ".trn.suomi.fi")) + +(defn authenticate + "If API account is connected to multiple organisations, user should + define Palveluhallinta organisation ID by using apiUserOrganisation parameter. + + If parameter is not given, then token return authentication (token) + for active organization (can be check from Palveluhallinta UI). + + In test-env token seems to be valid for 24h." + [{:keys [token-url username password org-id]}] + (let [token-key (if (test-env? token-url) :ptvToken :serviceToken) ; wtf + req {:url token-url + :method :post + :form-params (merge {:username username + :password password} + (when org-id + {:apiUserOrganisation org-id}))}] + (-> (http req) + :body + token-key))) + +(defn parse-payload + [token] + (-> token (str/split #"\.") second b64/decode (String.) (json/decode keyword))) + +(defn get-token + [org-id] + ;; NOTE: deref + swap + (let [x (get @current-token org-id)] + (if (or (not x) (expired? (:payload x))) + (let [new-token (authenticate {:token-url (:token-url test-config) + :username (get-in test-config [:creds :api :username]) + :password (get-in test-config [:creds :api :password]) + :org-id org-id}) + x {:token new-token + :payload (parse-payload new-token)}] + (log/infof "Create token %s => %s" org-id new-token) + (swap! current-token assoc org-id x) + (:token x)) + (:token x)))) + +;; Need to proxy this with auth because otherwise the API doesn't +;; return :sourceId (wtf) +(defn get-org-services + [{:keys [service-url token] + :or {service-url (:service-url test-config)}} + org-id] + (let [token (or token (get-token org-id)) + params {:url (str service-url "/list/organization") + :method :get + :headers {:Authorization (str "bearer " token)} + :query-params {:organizationId org-id}}] + (-> (http params) + :body))) + +(defn get-org-service-channels + [{:keys [api-url token] + :or {api-url (:api-url test-config)}} + org-id] + (let [token (or token (get-token org-id)) + params {:url (str api-url "/v11/ServiceChannel/organization/" org-id) + :method :get + :headers {:Authorization (str "bearer " token)}}] + (-> (http params) + :body))) + +(defn create-service + [{:keys [service-url token] + :or {service-url (:service-url test-config)} + :as _config} + {:keys [org-id] :as service}] + (let [token (or token (get-token org-id)) + params {:url service-url + :method :post + :headers {:Authorization (str "bearer " token)} + :form-params service}] + (log/infof "Create PTV service %s" service) + (-> (http params) + :body))) + +(defn get-service + [{:keys [service-url token org-id] + :or {service-url (:service-url test-config)}} + service-id] + (let [token (or token (get-token org-id)) + params {:url (str service-url "/" service-id) + :method :get + :headers {:Authorization (str "bearer " token)}}] + (-> (http params) + :body))) + +(defn update-service + [{:keys [service-url token] + :or {service-url (:service-url test-config)}} + service-id + {:keys [org-id] :as data}] + (log/info "Update PTV service with id " service-id "and data" data) + (let [token (or token (get-token org-id)) + params {:url (str service-url "/" service-id) + :method :put + :headers {:Authorization (str "bearer " token)} + :form-params data}] + (-> (http params) + :body))) + +(defn create-service-location + [{:keys [service-location-url token] + :or {service-location-url (:service-location-url test-config)}} + service-location] + (let [org-id (-> service-location :organization :id) + token (or token (get-token org-id)) + params {:url service-location-url + :method :post + :headers {:Authorization (str "bearer " token)} + :form-params service-location}] + (log/info "Create PTV service location" service-location) + (-> (http params) + :body))) + +(defn update-service-location + [{:keys [service-location-url token] + :or {service-location-url (:service-location-url test-config)}} + service-location-id + data] + (let [org-id (-> data :organization :id) + token (or token (get-token org-id)) + params {:url (str service-location-url "/" service-location-id) + :method :put + :headers {:Authorization (str "bearer " token)} + :form-params data}] + (log/infof "req %s" params) + (-> (http params) + :body))) + +(defn get-eligible-sites + [{:keys [indices client] :as _search} + {:keys [city-codes type-codes owners] :as _criteria}] + (let [idx-name (get-in indices [:sports-site :search]) + params {:size 5000 + :track_total_hits 50000 + :_source {:excludes ["location.geometries.*" + "search-meta.location.geometries.*" + "search-meta.location.simple-geoms.*"]} + :query + {:bool + {:must + (remove nil? + [{:terms {:status.keyword ["active" "out-of-service-temporarily"]}} + (when city-codes + {:terms {:location.city.city-code city-codes}}) + (when owners + {:terms {:owner owners}}) + (when type-codes + {:terms {:type.type-code type-codes}})])}}}] + ;; TODO: Remove 7000 - huoltorakennukset + (-> (search/search client idx-name params) + :body + :hits + :hits + (->> (map :_source))))) + +(comment + (get-org-services {} ptv-data/liminka-org-id-test) + + ;; Delete all org services + (doseq [x (:itemList (get-org-services {} ptv-data/liminka-org-id-test))] + (update-service {:org-id ptv-data/liminka-org-id-test} + (:id x) + {:publishingStatus "Deleted"})) + + (get-service {} + (-> (get-org-services {} ptv-data/liminka-org-id-test) + :itemList + first + :id)) + + (get-org-service-channels {} ptv-data/liminka-org-id-test) + + ;; Delete all org service locations + (doseq [x (:itemList (get-org-service-channels {} ptv-data/liminka-org-id-test))] + (update-service-location {:org-id ptv-data/liminka-org-id-test} (:id x) {:publishingStatus "Deleted"})) + + (update-service-location {:org-id ptv-data/liminka-org-id-test} "fc768bb4-268c-4054-9b88-9ecc9a943452" {:publishingStatus "Deleted"})) diff --git a/webapp/src/clj/lipas/integration/ptv/core.clj b/webapp/src/clj/lipas/integration/ptv/core.clj deleted file mode 100644 index 72853cd3a..000000000 --- a/webapp/src/clj/lipas/integration/ptv/core.clj +++ /dev/null @@ -1,212 +0,0 @@ -(ns lipas.integration.ptv.core - (:require - [buddy.core.codecs.base64 :as b64] - [cheshire.core :as json] - [clj-http.client :as client] - [clojure.string :as str] - [lipas.backend.config :as config] - [lipas.backend.search :as search] - [lipas.data.ptv :as ptv-data] - [lipas.utils :as utils] - [taoensso.timbre :as log])) - -;; Test creds are OK to "leak" to VCS since they're public anyway -(def test-config - (utils/deep-merge - (get config/default-config :ptv) - {:api-url "https://api.palvelutietovaranto.trn.suomi.fi/api" - :token-url "https://palvelutietovaranto.trn.suomi.fi/api/auth/api-login" - :service-url "https://api.palvelutietovaranto.trn.suomi.fi/api/v11/Service" - :service-location-url "https://api.palvelutietovaranto.trn.suomi.fi/api/v11/ServiceChannel/ServiceLocation" - :creds - {:main-user - {:username "paakayttaja41.testi@testi.fi" - :password "Paatestaaja41-1041*"} - :maintainer - {:username "" - :password ""} - :api - #_{:username "API17@testi.fi" - :password "APIinterfaceUser17-1017*"} - {:username "API9@testi.fi" - :password "APIinterfaceUser9-1009*"}}})) - -#_(def test-config - {:api-url "https://api.palvelutietovaranto.trn.suomi.fi/api" - :token-url "https://palvelutietovaranto.trn.suomi.fi/api/auth/api-login" - :service-url "https://api.palvelutietovaranto.trn.suomi.fi/api/v11/Service" - :service-location-url "https://api.palvelutietovaranto.trn.suomi.fi/api/v11/ServiceChannel/ServiceLocation" - :creds - {:main-user - {:username "paakayttaja35.testi@testi.fi" - :password "Paatestaaja35-1035*"} - :maintainer - {:username "yllapitaja35.testi@testi.fi" - :password "Yllapitajatestaaja35-1035*"} - :api - {:username "API14@testi.fi" - :password "APIinterfaceUser14-1014*"}}}) - -;; Org-id => {:token ... :payload ...} -;; TODO: Move this to IG component state? -(defonce current-token (atom {})) - -(defn unix-time [] - (/ (System/currentTimeMillis) 1000)) - -(defn expired? - [{:keys [exp]}] - (< exp (long (unix-time)))) - -(defn test-env? - [url] - (str/includes? url ".trn.suomi.fi")) - -(defn authenticate - "If API account is connected to multiple organisations, user should - define Palveluhallinta organisation ID by using apiUserOrganisation parameter. - - If parameter is not given, then token return authentication (token) - for active organization (can be check from Palveluhallinta UI). - - In test-env token seems to be valid for 24h." - [{:keys [token-url username password org-id]}] - (let [token-key (if (test-env? token-url) :ptvToken :serviceToken) ; wtf - params {:headers {:Content-Type "application/json"} - :body (json/encode - (merge {:username username :password password} - (when org-id - {:apiUserOrganisation org-id})))}] - (-> (client/post token-url params) - :body - (json/decode keyword) - token-key))) - -(defn parse-payload - [token] - (-> token (str/split #"\.") second b64/decode (String.) (json/decode keyword))) - -(defn get-token - [org-id] - ;; NOTE: deref + swap - (let [x (get @current-token org-id)] - (if (or (not x) (expired? (:payload x))) - (let [new-token (authenticate {:token-url (:token-url test-config) - :username (get-in test-config [:creds :api :username]) - :password (get-in test-config [:creds :api :password]) - :org-id org-id})] - (:token (swap! current-token assoc org-id {:token new-token - :payload (parse-payload new-token)}))) - (:token x)))) - -(def ->ptv-service ptv-data/->ptv-service) -(def ->ptv-service-location ptv-data/->ptv-service-location) - -;; Need to proxy this with auth because otherwise the API doesn't -;; return :sourceId (wtf) -(defn get-org-services - [{:keys [service-url token] - :or {service-url (:service-url test-config)}} - org-id] - (let [token (or token (get-token org-id)) - params {:headers {:Content-Type "application/json" - :Authorization (str "bearer " token)} - :query-params {:organizationId org-id}}] - (-> (client/get (str service-url "/list/organization") params) - :body - (json/decode keyword)))) - -(defn get-org-service-channels - [{:keys [api-url token] - :or {api-url (:api-url test-config)}} - org-id] - (let [token (or token (get-token org-id)) - params {:headers {:Content-Type "application/json" - :Authorization (str "bearer " token)}}] - (-> (client/get (str api-url "/v11/ServiceChannel/organization/" org-id) params) - :body - (json/decode keyword)))) - -(defn create-service - [{:keys [org-id service-url token] - :or {service-url (:service-url test-config)} - :as _config} - service] - (let [token (or token (get-token org-id)) - params {:headers {:Content-Type "application/json" - :Authorization (str "bearer " token)} - :body (json/encode service)}] - (log/info "Create PTV service" service) - (-> (client/post service-url params) - :body - (json/decode keyword)))) - -(defn update-service - [{:keys [service-url token org-id] - :or {service-url (:service-url test-config)}} - service-id - data] - (log/info "Update PTV service with id " service-id "and data" data) - (let [token (or token (get-token org-id)) - params {:headers {:Content-Type "application/json" - :Authorization (str "bearer " token)} - :body (json/encode data)}] - (-> (client/put (str service-url "/" service-id) params) - :body - (json/decode keyword)))) - -(defn create-service-location - [{:keys [service-location-url token org-id] - :or {service-location-url (:service-location-url test-config)}} - service-location] - (let [token (or token (get-token org-id)) - params {:headers {:Content-Type "application/json" - :Authorization (str "bearer " token)} - :body (json/encode service-location)}] - (log/info "Create PTV service location" service-location) - (-> (client/post service-location-url params) - :body - (json/decode keyword)))) - -(defn update-service-location - [{:keys [service-location-url token org-id] - :or {service-location-url (:service-location-url test-config)}} - service-location-id - data] - (let [token (or token (get-token org-id)) - params {:headers {:Content-Type "application/json" - :Authorization (str "bearer " token)} - :body (json/encode data)}] - (-> (client/put (str service-location-url "/" service-location-id) params) - :body - (json/decode keyword)))) - -(defn get-eligible-sites - [{:keys [indices client] :as _search} - {:keys [city-codes type-codes owners] :as _criteria}] - (let [idx-name (get-in indices [:sports-site :search]) - params {:size 5000 - :track_total_hits 50000 - :_source {:excludes ["location.geometries.*" - "search-meta.location.geometries.*" - "search-meta.location.simple-geoms.*"]} - :query - {:bool - {:must - (remove nil? - [{:terms {:status.keyword ["active" "out-of-service-temporarily"]}} - (when city-codes - {:terms {:location.city.city-code city-codes}}) - (when owners - {:terms {:owner owners}}) - (when type-codes - {:terms {:type.type-code type-codes}})])}}}] - (-> (search/search client idx-name params) - :body - :hits - :hits - (->> (map :_source))))) - -(comment - (get-org-services {} ptv-data/liminka-org-id-test) - (get-org-service-channels {} ptv-data/liminka-org-id-test)) diff --git a/webapp/src/cljs/lipas/ui/map/projection.cljs b/webapp/src/cljs/lipas/ui/map/projection.cljs index 19de91b69..f89f34f18 100644 --- a/webapp/src/cljs/lipas/ui/map/projection.cljs +++ b/webapp/src/cljs/lipas/ui/map/projection.cljs @@ -1,5 +1,5 @@ (ns lipas.ui.map.projection - " Loading this namespace causes side-effects to global OpenLayers + "Loading this namespace causes side-effects to global OpenLayers object (js/ol)." (:require ["ol/extent" :as extent] ["ol/proj" :as proj] From c832c4bdd45a24b2a92e546df8c5027ea32cdca1 Mon Sep 17 00:00:00 2001 From: Juho Teperi Date: Tue, 5 Nov 2024 15:28:43 +0200 Subject: [PATCH 38/68] Fix PTV UI autocompletes --- .../lipas/ui/components/autocompletes.cljs | 2 +- webapp/src/cljs/lipas/ui/ptv/views.cljs | 110 ++++++++++-------- 2 files changed, 62 insertions(+), 50 deletions(-) diff --git a/webapp/src/cljs/lipas/ui/components/autocompletes.cljs b/webapp/src/cljs/lipas/ui/components/autocompletes.cljs index 2aaac255e..46b05965d 100644 --- a/webapp/src/cljs/lipas/ui/components/autocompletes.cljs +++ b/webapp/src/cljs/lipas/ui/components/autocompletes.cljs @@ -91,7 +91,7 @@ x)) (defui autocomplete2 - "Helper for version if autocomplete where: + "Helper for version of autocomplete where: :options should be a cljs sequential collection with {:value ... :label ...}" [{:keys [options input-props label] :as props}] diff --git a/webapp/src/cljs/lipas/ui/ptv/views.cljs b/webapp/src/cljs/lipas/ui/ptv/views.cljs index fdf8a7eae..b9a1317f0 100644 --- a/webapp/src/cljs/lipas/ui/ptv/views.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/views.cljs @@ -3,11 +3,14 @@ [goog.string.format] [lipas.data.ptv :as ptv-data] [lipas.ui.components :as lui] + [lipas.ui.components.autocompletes :refer [autocomplete2]] [lipas.ui.mui :as mui] [lipas.ui.ptv.events :as events] [lipas.ui.ptv.subs :as subs] + [lipas.ui.uix.hooks :refer [use-subscribe]] [lipas.ui.utils :refer [<== ==>]] - [reagent.core :as r])) + [reagent.core :as r] + [uix.core :as uix :refer [$ defui]])) ;; Memo ;; - preset service structure with descriptions @@ -48,35 +51,44 @@ :value selected-org :on-change #(==> [::events/select-org %])}])) -(defn services-selector +(defui services-selector [{:keys [value on-change label value-fn] :or {value-fn identity label ""}}] - (let [items (<== [::subs/services])] - [lui/autocomplete - {:items items - :multi? true - :label label - :label-fn :label - :value-fn value-fn - :value value - :on-change on-change}])) - -(defn service-channel-selector + (let [items (use-subscribe [::subs/services]) + options (uix/use-memo (fn [] + (map (fn [x] + {:value (value-fn x) + :label (:label x)}) + items)) + [items value-fn])] + ($ autocomplete2 + {:options options + :multiple true + :label label + :value (to-array value) + :on-change (fn [_e v] + (on-change (:value v)))}))) + +(defui service-channel-selector [{:keys [value on-change label value-fn] :or {value-fn identity label ""}}] - (let [items (<== [::subs/service-channels-list])] - [lui/autocomplete - {:items items - :multi? false - :label label - :label-fn :name - :value-fn value-fn - :value (first value) - :on-change (fn [v] - (println v) - (on-change [v]))}])) + (let [items (use-subscribe [::subs/service-channels-list]) + options (uix/use-memo (fn [] + (map (fn [x] + {:value (value-fn x) + :label (:name x)}) + items)) + [items value-fn])] + ($ autocomplete2 + {:options options + :multiple false + :label label + :value (first value) + :on-change (fn [_e v] + (println v) + (on-change [(:value v)]))}))) (defn info-text [s] @@ -247,11 +259,11 @@ (tr :ptv.integration.service/lipas-managed-helper)) (when (= "manual" (:service-integration site)) - [services-selector - {:value (:service-ids site) - :on-change #(==> [::events/select-services site %]) - :value-fn :service-id - :label (tr :ptv.actions/select-service)}])]] + ($ services-selector + {:value (:service-ids site) + :on-change #(==> [::events/select-services site %]) + :value-fn :service-id + :label (tr :ptv.actions/select-service)}))]] ;; Service channels [mui/grid {:item true :xs 12 :lg 4} @@ -279,11 +291,11 @@ (tr :ptv.integration.service-channel/lipas-managed-helper)) (when (= "manual" (:service-channel-integration site)) - [service-channel-selector - {:value (:service-channel-ids site) - :value-fn :id - :on-change #(==> [::events/select-service-channels site %]) - :label (tr :ptv.actions/select-service-channel)}])]] + ($ service-channel-selector + {:value (:service-channel-ids site) + :value-fn :id + :on-change #(==> [::events/select-service-channels site %]) + :label (tr :ptv.actions/select-service-channel)}))]] ;; Descriptions (r/with-let [selected-tab (r/atom :fi)] @@ -699,11 +711,11 @@ :label-fn :label :on-change #(==> [::events/set-service-candidate-languages source-id %])}] - [services-selector - {:value (get m :service-ids) - :on-change #(==> [::events/link-candidate-to-existing-service source-id %]) - :value-fn :service-id - :label (tr :ptv/service)}] + ($ services-selector + {:value (get m :service-ids) + :on-change #(==> [::events/link-candidate-to-existing-service source-id %]) + :value-fn :service-id + :label (tr :ptv/service)}) (let [languages (set languages)] [mui/tabs @@ -890,11 +902,11 @@ :on-change #(==> [::events/toggle-sync-enabled site %])}] ;; Services selector - [services-selector - {:value service-ids - :value-fn :service-id - :on-change #(==> [::events/select-services site %]) - :label (tr :ptv/services)}] + ($ services-selector + {:value service-ids + :value-fn :service-id + :on-change #(==> [::events/select-services site %]) + :label (tr :ptv/services)}) ;; Service channel selector @@ -926,11 +938,11 @@ [(:service-channel-id name-conflict)]])} (tr :ptv.wizard/attach-to-conflicting-service-channel)]) - [service-channel-selector - {:value service-channel-ids - :value-fn :service-channel-id - :on-change #(==> [::events/select-service-channels site %]) - :label (tr :ptv/service-channel)}]] + ($ service-channel-selector + {:value service-channel-ids + :value-fn :service-channel-id + :on-change #(==> [::events/select-service-channels site %]) + :label (tr :ptv/service-channel)})] [mui/tabs {:value @selected-tab From cf61a3536624bace8f963300f549f87280ca62ac Mon Sep 17 00:00:00 2001 From: Juho Teperi Date: Tue, 5 Nov 2024 16:00:04 +0200 Subject: [PATCH 39/68] Make ptv wizard view faster --- webapp/src/cljs/lipas/ui/ptv/subs.cljs | 2 + webapp/src/cljs/lipas/ui/ptv/views.cljs | 265 ++++++++++++++---------- 2 files changed, 155 insertions(+), 112 deletions(-) diff --git a/webapp/src/cljs/lipas/ui/ptv/subs.cljs b/webapp/src/cljs/lipas/ui/ptv/subs.cljs index cbef5fbd3..68e557811 100644 --- a/webapp/src/cljs/lipas/ui/ptv/subs.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/subs.cljs @@ -248,6 +248,8 @@ {:service-channel-id (:id service-channel)}))) service-channels))) +;; FIXME: Break this into parts +;; Each sports-site should subscribe to its own part of data. (rf/reg-sub ::sports-sites :<- [::ptv] :<- [::selected-org-id] diff --git a/webapp/src/cljs/lipas/ui/ptv/views.cljs b/webapp/src/cljs/lipas/ui/ptv/views.cljs index b9a1317f0..1c374f215 100644 --- a/webapp/src/cljs/lipas/ui/ptv/views.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/views.cljs @@ -10,7 +10,12 @@ [lipas.ui.uix.hooks :refer [use-subscribe]] [lipas.ui.utils :refer [<== ==>]] [reagent.core :as r] - [uix.core :as uix :refer [$ defui]])) + [uix.core :as uix :refer [$ defui]] + ["@mui/material/Accordion$default" :as Accordion] + ["@mui/material/AccordionSummary$default" :as AccordionSummary] + ["@mui/material/Icon$default" :as Icon] + ["@mui/material/Typography$default" :as Typography] + ["@mui/material/AccordionDetails$default" :as AccordionDetails])) ;; Memo ;; - preset service structure with descriptions @@ -745,6 +750,114 @@ :label (tr :ptv/description) :value (get-in m [:description @selected-tab])}]]]))]]]]]))) +(defui service-location-details + [{:keys [tr site lipas-id sync-enabled name-conflict service-ids selected-tab set-selected-tab service-channel-ids]}] + ($ AccordionDetails + {} + (r/as-element + [mui/stack {:spacing 2} + + [lui/switch + {:label (tr :ptv.actions/export-disclaimer) + :value sync-enabled + :on-change #(==> [::events/toggle-sync-enabled site %])}] + + ;; Services selector + ($ services-selector + {:value service-ids + :value-fn :service-id + :on-change #(==> [::events/select-services site %]) + :label (tr :ptv/services)}) + + ;; Service channel selector + + [:span (when name-conflict {:style + {:border "1px solid rgb(237, 108, 2)" + :padding "1em"}}) + + (when name-conflict + [mui/stack + [lui/icon-text + {:icon "warning" + :icon-color "warning" + :text (tr :ptv.wizard/service-channel-name-conflict (:name site))}] + + [mui/typography + {:style {:padding-left "1em" :margin-bottom "0"} + :variant "body2"} + (tr :ptv.name-conflict/do-one-of-these)] + + [:ul + [:li (tr :ptv.name-conflict/opt1)] + [:li (tr :ptv.name-conflict/opt2)] + [:li (tr :ptv.name-conflict/opt3)] + #_[:li (tr :ptv.name-conflict/opt4)]]]) + + (when name-conflict + [mui/button + {:on-click #(==> [::events/select-service-channels {:lipas-id lipas-id} + [(:service-channel-id name-conflict)]])} + (tr :ptv.wizard/attach-to-conflicting-service-channel)]) + + ($ service-channel-selector + {:value service-channel-ids + :value-fn :service-channel-id + :on-change #(==> [::events/select-service-channels site %]) + :label (tr :ptv/service-channel)})] + + [mui/tabs + {:value selected-tab + :on-change #(set-selected-tab (keyword %2))} + [mui/tab {:value "fi" :label "FI"}] + [mui/tab {:value "se" :label "SE"}] + [mui/tab {:value "en" :label "EN"}]] + + ;; Summary + [lui/text-field + {:multiline true + :read-only? (not= "manual" (:descriptions-integration site)) + :variant "outlined" + :on-change #(==> [::events/set-summary site selected-tab %]) + :label (tr :ptv/summary) + :value (get-in site [:summary selected-tab])}] + + ;; Description + [lui/text-field + {:variant "outlined" + :read-only? (not= "manual" (:descriptions-integration site)) + :rows 5 + :multiline true + :on-change #(==> [::events/set-description site selected-tab %]) + :label (tr :ptv/description) + :value (get-in site [:description selected-tab])}]]))) + +(defui service-location + [{:keys [site sync-enabled name-conflict valid] + :as props}] + ($ Accordion + {:defaultExpanded false + :disableGutters true + :square true + ;; Much faster this way, only render the accordion content for open sites + :slotProps #js {:transition #js {:unmountOnExit true}} + :sx #js {:mb 2 + :backgroundColor (when (false? sync-enabled) + mui/gray3)}} + ($ AccordionSummary + {:expandIcon ($ Icon "expand_more")} + ($ Typography + {:sx #js {:mr 1.5}} + (cond + name-conflict ($ Icon {:color "warning"} "warning") + valid ($ Icon {:color "success"} "done") + :else ($ Icon {:color "disabled"} "done"))) + ($ Typography + {:sx #js {:color "inherit" + :variant "button"}} + (:name site))) + + ($ service-location-details props))) + (defn integrate-service-locations [] (let [tr (<== [:lipas.ui.subs/translator]) @@ -753,12 +866,15 @@ sports-sites-count (<== [::subs/sports-sites-count]) sports-sites-filter (<== [::subs/sports-sites-filter]) - {:keys [in-progress? - processed-lipas-ids - processed-count - total-count - processed-percent - halt?] :as m} (<== [::subs/batch-descriptions-generation-progress])] + [selected-tab set-selected-tab] (uix/use-state :fi) + + {:keys [in-progress? + processed-lipas-ids + processed-count + total-count + processed-percent + halt?] :as m} + (<== [::subs/batch-descriptions-generation-progress])] [lui/expansion-panel {:label (str "2. " (tr :ptv.wizard/integrate-service-locations)) @@ -853,12 +969,12 @@ :on-click #(==> [::events/create-all-ptv-service-locations sports-sites])} (tr :ptv.wizard/export-service-locations-to-ptv)] - (let [{:keys [in-progress? - processed-lipas-ids - processed-count - total-count - processed-percent - halt?] :as m} + (let [{:keys [in-progress? + processed-lipas-ids + processed-count + total-count + processed-percent + halt?] :as m} (<== [::subs/service-location-creation-progress])] (when in-progress? @@ -869,106 +985,31 @@ (when halt? "Something went wrong, ask engineer."))]] -;; Results - - (r/with-let [selected-tab (r/atom :fi)] - [mui/grid {:item true :xs 12 :lg 8} - [mui/stack {:spacing 4} - - [mui/typography {:variant "h6"} - (tr :ptv/sports-sites)] - - [mui/typography {:variant "subtitle1" :style {:margin-top "0px"}} - (str sports-sites-count " kpl")] - - (doall - (for [{:keys [lipas-id valid name-conflict sync-enabled service-ids service-channel-ids service-name] :as site} sports-sites] - ^{:key lipas-id} - [lui/expansion-panel - {:label (:name site) - :style (merge {:margin-top "1em"} - (when (false? sync-enabled) {:background-color mui/gray3})) - :label-icon - (cond - name-conflict [mui/icon {:color "warning"} "warning"] - valid [mui/icon {:color "success"} "done"] - :else [mui/icon {:color "disabled"} "done"])} - - [mui/stack {:spacing 2} - - [lui/switch - {:label (tr :ptv.actions/export-disclaimer) - :value sync-enabled - :on-change #(==> [::events/toggle-sync-enabled site %])}] - - ;; Services selector - ($ services-selector - {:value service-ids - :value-fn :service-id - :on-change #(==> [::events/select-services site %]) - :label (tr :ptv/services)}) - - ;; Service channel selector - - [:span (when name-conflict {:style - {:border "1px solid rgb(237, 108, 2)" - :padding "1em"}}) - - (when name-conflict - [mui/stack - [lui/icon-text - {:icon "warning" - :icon-color "warning" - :text (tr :ptv.wizard/service-channel-name-conflict (:name site))}] - - [mui/typography - {:style {:padding-left "1em" :margin-bottom "0"} - :variant "body2"} - (tr :ptv.name-conflict/do-one-of-these)] - - [:ul - [:li (tr :ptv.name-conflict/opt1)] - [:li (tr :ptv.name-conflict/opt2)] - [:li (tr :ptv.name-conflict/opt3)] - #_[:li (tr :ptv.name-conflict/opt4)]]]) - - (when name-conflict - [mui/button - {:on-click #(==> [::events/select-service-channels {:lipas-id lipas-id} - [(:service-channel-id name-conflict)]])} - (tr :ptv.wizard/attach-to-conflicting-service-channel)]) - - ($ service-channel-selector - {:value service-channel-ids - :value-fn :service-channel-id - :on-change #(==> [::events/select-service-channels site %]) - :label (tr :ptv/service-channel)})] - - [mui/tabs - {:value @selected-tab - :on-change #(reset! selected-tab (keyword %2))} - [mui/tab {:value "fi" :label "FI"}] - [mui/tab {:value "se" :label "SE"}] - [mui/tab {:value "en" :label "EN"}]] + ;; Results - ;; Summary - [lui/text-field - {:multiline true - :read-only? (not= "manual" (:descriptions-integration site)) - :variant "outlined" - :on-change #(==> [::events/set-summary site @selected-tab %]) - :label (tr :ptv/summary) - :value (get-in site [:summary @selected-tab])}] + [mui/grid {:item true :xs 12 :lg 8} + [mui/stack {:spacing 4} - ;; Description - [lui/text-field - {:variant "outlined" - :read-only? (not= "manual" (:descriptions-integration site)) - :rows 5 - :multiline true - :on-change #(==> [::events/set-description site @selected-tab %]) - :label (tr :ptv/description) - :value (get-in site [:description @selected-tab])}]]]))]])]])) + [mui/typography {:variant "h6"} + (tr :ptv/sports-sites)] + + [mui/typography {:variant "subtitle1" :style {:margin-top "0px"}} + (str sports-sites-count " kpl")]] + + [mui/stack + (for [{:keys [lipas-id valid name-conflict sync-enabled service-ids service-channel-ids service-name] :as site} sports-sites] + ($ service-location + {:key lipas-id + :tr tr + :site site + :lipas-id lipas-id + :name-conflict name-conflict + :sync-enabled sync-enabled + :valid valid + :service-ids service-ids + :selected-tab selected-tab + :set-selected-tab set-selected-tab + :service-channel-ids service-channel-ids}))]]]])) (defn tools [] @@ -1065,7 +1106,7 @@ [] [mui/paper [create-services] - [integrate-service-locations]]) + [:f> integrate-service-locations]]) (defn dialog [{:keys [tr]}] From 01159e93d6f4957ad0e56dced8909f05128be4de Mon Sep 17 00:00:00 2001 From: Juho Teperi Date: Wed, 6 Nov 2024 14:49:33 +0200 Subject: [PATCH 40/68] Fix storing created ptv id to Lipas DB - Store created ServiceLocation ID to DB directly in the BE (previously sent to UI and them MAYBE stored to DB at some later time, if user did some operations in right order) - Return same data to UI for autocomplete listing for created ServiceLocations, as the list endpoint returns - Retry http request if token expired (or something) --- webapp/src/clj/lipas/backend/ptv/core.clj | 38 +++++-- .../src/clj/lipas/backend/ptv/integration.clj | 105 ++++++++++-------- webapp/src/cljc/lipas/data/ptv.cljc | 3 +- webapp/src/cljs/lipas/ui/ptv/events.cljs | 59 +++++----- 4 files changed, 119 insertions(+), 86 deletions(-) diff --git a/webapp/src/clj/lipas/backend/ptv/core.clj b/webapp/src/clj/lipas/backend/ptv/core.clj index 3caa4def9..1291b7ed1 100644 --- a/webapp/src/clj/lipas/backend/ptv/core.clj +++ b/webapp/src/clj/lipas/backend/ptv/core.clj @@ -8,7 +8,8 @@ [lipas.backend.search :as search] [lipas.data.ptv :as ptv-data] [lipas.data.types :as types] - [lipas.utils :as utils])) + [lipas.utils :as utils] + [taoensso.timbre :as log])) (defn get-ptv-integration-candidates [search criteria] @@ -75,24 +76,43 @@ (let [site (db/get-sports-site db (:lipas-id sports-site)) _ (assert (some? site) (str "Sports site " (:lipas-id sports-site) " not found in DB")) - ;; FIXME: - config {:org-id (get-in ptv/test-config [:creds :org-id])} - id (first (get-in site [:ptv :service-channel-ids])) + ;; NOTE: Is this available always? Where is ptv-meta originally intitialized? + config {:org-id (:org-id ptv-meta)} + ;; This is the service-channel-id in Lipas DB (which won't exist for new service-locations) + ;; id (first (get-in site [:ptv :service-channel-ids])) + ;; This is the ID from UI, possibly updated/set with "Liitä tähän palvelupaikkaan" + ;; We probably want to use this always? + id (-> sports-site :ptv :service-channel-ids first) + ;; _ (log/infof "FOO: %s %s" id (-> sports-site :ptv :service-channel-ids)) site (update site :ptv merge ptv-meta) data (ptv-data/->ptv-service-location org gis/wgs84->tm35fin-no-wrap (core/enrich site)) ptv-resp (if id (ptv/update-service-location config id data) (ptv/create-service-location config data)) - now (utils/timestamp)] + now (utils/timestamp) + to-persist (-> ptv-meta + (select-keys persisted-ptv-keys) + (assoc :last-sync now + ;; Take the created ID from ptv response and store to Lipas DB right away. + ;; TODO: Is there a case where this could be multiple ids? + :service-channel-ids (set [(:id ptv-resp)])))] + + (log/infof "Upserted (updated: %s) service-location %s: %s" (boolean id) data to-persist) (core/save-sports-site! db search user (-> site (assoc :event-date now) - (assoc :ptv (-> ptv-meta - (select-keys persisted-ptv-keys) - (assoc :last-sync now))))) + (assoc :ptv to-persist))) - ptv-resp)) + {;; Return the updated :ptv meta for sports-site, to for the app-db + :ptv-meta to-persist + ;; Return :id :name, same as the list endpoint that is used in the UI to show the Palvelupaikka autocomplete + :ptv-resp {:id (:id ptv-resp) + :name (some (fn [x] + (when (and (= "Name" (:type x)) + (= "fi" (:language x))) + (:value x))) + (:serviceChannelNames ptv-resp))}})) (defn save-ptv-integration-definitions "Saves ptv definitions under key :ptv. Does not notify webhooks, diff --git a/webapp/src/clj/lipas/backend/ptv/integration.clj b/webapp/src/clj/lipas/backend/ptv/integration.clj index 369f05b33..4f7cf237c 100644 --- a/webapp/src/clj/lipas/backend/ptv/integration.clj +++ b/webapp/src/clj/lipas/backend/ptv/integration.clj @@ -9,22 +9,6 @@ [lipas.utils :as utils] [taoensso.timbre :as log])) -(defn http [req] - (try - (let [req (assoc req - :accept :json - :as :json) - req (if (:form-params req) - (assoc req :content-type :json) - req) - resp (client/request req)] - resp) - (catch clojure.lang.ExceptionInfo e - (let [d (ex-data e)] - (throw (ex-info (format "HTTP Error: %s %s" (:status d) (:body d)) - {:resp d} - nil)))))) - ;; Test creds are OK to "leak" to VCS since they're public anyway (def test-config (utils/deep-merge @@ -35,11 +19,14 @@ :service-location-url "https://api.palvelutietovaranto.trn.suomi.fi/api/v11/ServiceChannel/ServiceLocation" :creds {:main-user + ;; unused? {:username "paakayttaja41.testi@testi.fi" :password "Paatestaaja41-1041*"} :maintainer + ;; unused? {:username "" :password ""} + ;; FIXME: The current test env needs different credentials per org :api ;; org 10 #_{:username "API17@testi.fi" @@ -94,11 +81,14 @@ (let [token-key (if (test-env? token-url) :ptvToken :serviceToken) ; wtf req {:url token-url :method :post + :as :json + :accept :json + :content-type :json :form-params (merge {:username username :password password} (when org-id {:apiUserOrganisation org-id}))}] - (-> (http req) + (-> (client/request req) :body token-key))) @@ -122,94 +112,117 @@ (:token x)) (:token x)))) +(defn http + ([req] (http req false)) + ([req retried?] + (let [token (get-token (:auth-org-id req)) + req* (-> req + (dissoc :auth-org-id) + (assoc :accept :json + :as :json) + (assoc-in [:headers :Authorization] (str "bearer " token))) + req* (if (:form-params req*) + (assoc req* :content-type :json) + req*)] + (try + (client/request req*) + (catch clojure.lang.ExceptionInfo e + (let [d (ex-data e)] + ;; NOTE: Looks like tokens from yesterday aren't valid the next day even if they haven't "expired" yet? + (if (and (not retried?) + (= 401 (:status d)) + (= "Bearer error=\"invalid_token\", error_description=\"The access token is not valid.\"" + (get (:headers d) "rWW-Authenticate"))) + (do + (log/infof "Invalid token, trying to get a new token and retry") + (swap! current-token dissoc (:auth-org-id req)) + (http req true)) + (throw (ex-info (format "HTTP Error: %s %s" (:status d) (:body d)) + {:resp d + :req req*} + nil))))))))) + ;; Need to proxy this with auth because otherwise the API doesn't ;; return :sourceId (wtf) (defn get-org-services - [{:keys [service-url token] + [{:keys [service-url] :or {service-url (:service-url test-config)}} org-id] - (let [token (or token (get-token org-id)) - params {:url (str service-url "/list/organization") + (let [params {:url (str service-url "/list/organization") + :auth-org-id org-id :method :get - :headers {:Authorization (str "bearer " token)} :query-params {:organizationId org-id}}] (-> (http params) :body))) (defn get-org-service-channels - [{:keys [api-url token] + [{:keys [api-url] :or {api-url (:api-url test-config)}} org-id] - (let [token (or token (get-token org-id)) - params {:url (str api-url "/v11/ServiceChannel/organization/" org-id) - :method :get - :headers {:Authorization (str "bearer " token)}}] + (let [params {:url (str api-url "/v11/ServiceChannel/organization/" org-id) + :auth-org-id org-id + :method :get}] (-> (http params) :body))) (defn create-service - [{:keys [service-url token] + [{:keys [service-url] :or {service-url (:service-url test-config)} :as _config} {:keys [org-id] :as service}] - (let [token (or token (get-token org-id)) - params {:url service-url + (let [params {:url service-url + :auth-org-id org-id :method :post - :headers {:Authorization (str "bearer " token)} :form-params service}] (log/infof "Create PTV service %s" service) (-> (http params) :body))) (defn get-service - [{:keys [service-url token org-id] + [{:keys [service-url org-id] :or {service-url (:service-url test-config)}} service-id] - (let [token (or token (get-token org-id)) - params {:url (str service-url "/" service-id) - :method :get - :headers {:Authorization (str "bearer " token)}}] + (let [params {:url (str service-url "/" service-id) + :auth-org-id org-id + :method :get}] (-> (http params) :body))) (defn update-service - [{:keys [service-url token] + [{:keys [service-url] :or {service-url (:service-url test-config)}} service-id {:keys [org-id] :as data}] (log/info "Update PTV service with id " service-id "and data" data) - (let [token (or token (get-token org-id)) - params {:url (str service-url "/" service-id) + (let [params {:url (str service-url "/" service-id) + :auth-org-id org-id :method :put - :headers {:Authorization (str "bearer " token)} :form-params data}] (-> (http params) :body))) (defn create-service-location - [{:keys [service-location-url token] + [{:keys [service-location-url] :or {service-location-url (:service-location-url test-config)}} service-location] - (let [org-id (-> service-location :organization :id) - token (or token (get-token org-id)) + (let [org-id (-> service-location :organizationId) params {:url service-location-url + :auth-org-id org-id :method :post - :headers {:Authorization (str "bearer " token)} :form-params service-location}] (log/info "Create PTV service location" service-location) (-> (http params) :body))) (defn update-service-location - [{:keys [service-location-url token] + [{:keys [service-location-url] :or {service-location-url (:service-location-url test-config)}} service-location-id data] (let [org-id (-> data :organization :id) - token (or token (get-token org-id)) params {:url (str service-location-url "/" service-location-id) + :auth-org-id org-id :method :put - :headers {:Authorization (str "bearer " token)} :form-params data}] (log/infof "req %s" params) (-> (http params) diff --git a/webapp/src/cljc/lipas/data/ptv.cljc b/webapp/src/cljc/lipas/data/ptv.cljc index 0d377aa55..c6cf080b2 100644 --- a/webapp/src/cljc/lipas/data/ptv.cljc +++ b/webapp/src/cljc/lipas/data/ptv.cljc @@ -159,7 +159,8 @@ (prn location) {:organizationId (:org-id ptv) - :sourceId (str "lipas-" (:org-id ptv) "-" lipas-id) + ;; FIXME: PTV doesn't allow a new ServiceLocation with a same sourceId as a Deleted one + :sourceId (str "lipas3-" (:org-id ptv) "-" lipas-id) :serviceChannelNames (keep identity (let [fallback (get-in sports-site [:name])] [(when (contains? languages "fi") diff --git a/webapp/src/cljs/lipas/ui/ptv/events.cljs b/webapp/src/cljs/lipas/ui/ptv/events.cljs index 312945c80..8b699de4e 100644 --- a/webapp/src/cljs/lipas/ui/ptv/events.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/events.cljs @@ -577,14 +577,12 @@ :on-failure [::create-ptv-service-location-failure lipas-id failure-fx]}]]}))) (rf/reg-event-fx ::create-ptv-service-location-success - (fn [{:keys [db]} [_ lipas-id extra-fx resp]] + (fn [{:keys [db]} [_ lipas-id extra-fx {:keys [ptv-resp ptv-meta]}]] (let [org-id (get-in db [:ptv :selected-org :id])] {:db (-> db (assoc-in [:ptv :loading-from-lipas :service-channels] false) - (assoc-in [:ptv :org org-id :data :service-channels (:id resp)] resp) - (update-in [:ptv :org org-id :data :sports-sites lipas-id] - update-in [:ptv :service-channel-ids] (fn [ids] - (set (conj ids (:id resp)))))) + (assoc-in [:ptv :org org-id :data :service-channels (:id ptv-resp)] ptv-resp) + (assoc-in [:ptv :org org-id :data :sports-sites lipas-id :ptv] ptv-meta)) :fx extra-fx}))) (rf/reg-event-fx ::create-ptv-service-location-failure @@ -649,31 +647,32 @@ (rf/reg-event-fx ::save-ptv-meta (fn [{:keys [db]} [_ sports-sites]] - (let [token (-> db :user :login :token) - ks [:languages - :summary - :description - :last-sync - :org-id - :sync-enabled - :service-integration - :descriptions-integration - :service-channel-integration - :service-ids - :service-channel-ids]] - {:db (assoc-in db [:ptv :save-in-progress] true) - :fx [[:http-xhrio - {:method :post - :headers {:Authorization (str "Token " token)} - :uri (str (:backend-url db) "/actions/save-ptv-meta") - :params (reduce (fn [m site] - (assoc m (:lipas-id site) (select-keys site ks))) - {} - sports-sites) - :format (ajax/transit-request-format) - :response-format (ajax/transit-response-format) - :on-success [::save-ptv-meta-success] - :on-failure [::save-ptv-meta-failure]}]]}))) + (when (seq sports-sites) + (let [token (-> db :user :login :token) + ks [:languages + :summary + :description + :last-sync + :org-id + :sync-enabled + :service-integration + :descriptions-integration + :service-channel-integration + :service-ids + :service-channel-ids]] + {:db (assoc-in db [:ptv :save-in-progress] true) + :fx [[:http-xhrio + {:method :post + :headers {:Authorization (str "Token " token)} + :uri (str (:backend-url db) "/actions/save-ptv-meta") + :params (reduce (fn [m site] + (assoc m (:lipas-id site) (select-keys site ks))) + {} + sports-sites) + :format (ajax/transit-request-format) + :response-format (ajax/transit-response-format) + :on-success [::save-ptv-meta-success] + :on-failure [::save-ptv-meta-failure]}]]})))) (rf/reg-event-fx ::save-ptv-meta-success (fn [{:keys [db]} _] From 5d40c8f9eeafbd3f79f2c02d546a58ec8ba230fd Mon Sep 17 00:00:00 2001 From: Juho Teperi Date: Wed, 6 Nov 2024 14:52:59 +0200 Subject: [PATCH 41/68] Note --- webapp/src/clj/lipas/backend/ptv/integration.clj | 3 +++ webapp/src/cljs/lipas/ui/ptv/events.cljs | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/webapp/src/clj/lipas/backend/ptv/integration.clj b/webapp/src/clj/lipas/backend/ptv/integration.clj index 4f7cf237c..7b5a90bc9 100644 --- a/webapp/src/clj/lipas/backend/ptv/integration.clj +++ b/webapp/src/clj/lipas/backend/ptv/integration.clj @@ -159,6 +159,9 @@ [{:keys [api-url] :or {api-url (:api-url test-config)}} org-id] + ;; TODO: Solve paginations, if multiple pages, lazy seq and make multiple requests? + ;; Or should we handle pagination from FE? + ;; 500 should be fine in one response, what if we have 2000-5000 for some city/org? (let [params {:url (str api-url "/v11/ServiceChannel/organization/" org-id) :auth-org-id org-id :method :get}] diff --git a/webapp/src/cljs/lipas/ui/ptv/events.cljs b/webapp/src/cljs/lipas/ui/ptv/events.cljs index 8b699de4e..05f371b3d 100644 --- a/webapp/src/cljs/lipas/ui/ptv/events.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/events.cljs @@ -9,6 +9,7 @@ (def ptv-root-url-prod "https://api.palvelutietovaranto.suomi.fi") +;; FIXME: Remove, proxy all through BE (def ptv-root-url-test "https://api.palvelutietovaranto.trn.suomi.fi") @@ -86,6 +87,7 @@ (fn [{:keys [db]} [_ org]] (when org {:db (assoc-in db [:ptv :loading-from-ptv :org] true) + ;; FIXME: Load through BE :fx [[:http-xhrio {:method :get :uri (str ptv-root-url-test "/api/v11/Organization/" (:id org)) @@ -146,6 +148,7 @@ (fn [{:keys [db]} [_ org]] (when org {:db (assoc-in db [:ptv :loading-from-ptv :service-channels] true) + ;; FIXME: Load through BE :fx [[:http-xhrio {:method :get :uri (str ptv-root-url-test @@ -177,6 +180,7 @@ (fn [{:keys [db]} [_ org]] (when org {:db (assoc-in db [:ptv :loading-from-ptv :service-collections] true) + ;; FIXME: Load through BE :fx [[:http-xhrio {:method :get :uri (str ptv-root-url-test From 85325d7c4c3b62fa5245b88294e0798fcc97815a Mon Sep 17 00:00:00 2001 From: Juho Teperi Date: Wed, 6 Nov 2024 15:10:49 +0200 Subject: [PATCH 42/68] Don't reuse AI generated PTV summary/description as AI prompt data --- webapp/src/clj/lipas/backend/ptv/ai.clj | 10 +++++++--- webapp/src/cljs/lipas/ui/ptv/views.cljs | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/webapp/src/clj/lipas/backend/ptv/ai.clj b/webapp/src/clj/lipas/backend/ptv/ai.clj index 237351167..1dd73a1c5 100644 --- a/webapp/src/clj/lipas/backend/ptv/ai.clj +++ b/webapp/src/clj/lipas/backend/ptv/ai.clj @@ -133,9 +133,13 @@ Provide answers in English, Finnish, and Swedish. Different language versions ca [sports-site] ;; Might include (some) of the UTP data now? ;; Could be a good thing, but might make the prompt data too large? - (walk/postwalk #(if (map? %) - (dissoc % :geoms :geometries :simple-geoms :images :videos :id :fids :event-date) - %) + (walk/postwalk (fn [x] + (if (map? x) + (dissoc x :geoms :geometries :simple-geoms :images :videos :id :fids :event-date + ;; This includes the already generated summary/description, important that that isn't + ;; passed back into the AI. + :ptv) + x)) sports-site)) (defn generate-ptv-descriptions diff --git a/webapp/src/cljs/lipas/ui/ptv/views.cljs b/webapp/src/cljs/lipas/ui/ptv/views.cljs index 1c374f215..e30a5f37e 100644 --- a/webapp/src/cljs/lipas/ui/ptv/views.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/views.cljs @@ -344,7 +344,7 @@ (when (= "lipas-managed-ptv-fields" (:descriptions-integration site)) [mui/button {:disabled loading? - :on-click #(==> [::events/generate-descriptions (:lipas-id site)])} + :on-click #(==> [::events/generate-descriptions (:lipas-id site) [] []])} (tr :ptv.actions/generate-with-ai)]) (when loading? From 71d5d60bb6e118f5f80fcf39dfcf1e8f5ac2e148 Mon Sep 17 00:00:00 2001 From: Juho Teperi Date: Wed, 6 Nov 2024 16:27:33 +0200 Subject: [PATCH 43/68] Include Lipas archived sites in PTV candidates - Set PTV publishing status based on Lipas status - Store PTV publishing status under :ptv meta so we can detect if Lipas deleted was already deleted in PTV also --- webapp/src/clj/lipas/backend/core.clj | 8 ++++++++ webapp/src/clj/lipas/backend/ptv/core.clj | 6 +++++- webapp/src/clj/lipas/backend/ptv/integration.clj | 4 +++- webapp/src/cljc/lipas/data/ptv.cljc | 7 +++++-- webapp/src/cljs/lipas/ui/ptv/views.cljs | 10 +++++++++- 5 files changed, 30 insertions(+), 5 deletions(-) diff --git a/webapp/src/clj/lipas/backend/core.clj b/webapp/src/clj/lipas/backend/core.clj index 2ae269a3b..dc2071955 100644 --- a/webapp/src/clj/lipas/backend/core.clj +++ b/webapp/src/clj/lipas/backend/core.clj @@ -522,6 +522,14 @@ (add-to-webhook-queue! tx {:lipas-ids [(:lipas-id resp)]})) + ;; FIXME: This is called from ptv-integration to store :ptv metadata. That should maybe + ;; call upsert-sports-site! instead so it doesn't trigger indexing and other stuff? + (when (and (#{"out-of-service-permanently" + "incorrect-data"} + (:status resp)) + (:ptv resp)) + (log/infof "Sports-site was archived, shold be removed from PTV?")) + resp)))) ;;; Cities ;;; diff --git a/webapp/src/clj/lipas/backend/ptv/core.clj b/webapp/src/clj/lipas/backend/ptv/core.clj index 1291b7ed1..95e81a0f2 100644 --- a/webapp/src/clj/lipas/backend/ptv/core.clj +++ b/webapp/src/clj/lipas/backend/ptv/core.clj @@ -85,7 +85,9 @@ id (-> sports-site :ptv :service-channel-ids first) ;; _ (log/infof "FOO: %s %s" id (-> sports-site :ptv :service-channel-ids)) site (update site :ptv merge ptv-meta) + _ (log/infof "Site data: %s" site) data (ptv-data/->ptv-service-location org gis/wgs84->tm35fin-no-wrap (core/enrich site)) + _ (log/infof "Created data: %s" data) ptv-resp (if id (ptv/update-service-location config id data) (ptv/create-service-location config data)) @@ -93,11 +95,13 @@ to-persist (-> ptv-meta (select-keys persisted-ptv-keys) (assoc :last-sync now + ;; Store the PTV status so we can ignore Lipas archived places that we already archived in PTV. + :publishing-status (:publishingStatus ptv-resp) ;; Take the created ID from ptv response and store to Lipas DB right away. ;; TODO: Is there a case where this could be multiple ids? :service-channel-ids (set [(:id ptv-resp)])))] - (log/infof "Upserted (updated: %s) service-location %s: %s" (boolean id) data to-persist) + (log/infof "Upserted (Lipas status: %s, updated: %s) service-location %s: %s" (:status site) (boolean id) data to-persist) (core/save-sports-site! db search user (-> site diff --git a/webapp/src/clj/lipas/backend/ptv/integration.clj b/webapp/src/clj/lipas/backend/ptv/integration.clj index 7b5a90bc9..7a8414029 100644 --- a/webapp/src/clj/lipas/backend/ptv/integration.clj +++ b/webapp/src/clj/lipas/backend/ptv/integration.clj @@ -244,7 +244,9 @@ {:bool {:must (remove nil? - [{:terms {:status.keyword ["active" "out-of-service-temporarily"]}} + [;; Include all statuses - this is also used to remove the sites from PTV + ; {:terms {:status.keyword ["active" + ; "out-of-service-temporarily"]}} (when city-codes {:terms {:location.city.city-code city-codes}}) (when owners diff --git a/webapp/src/cljc/lipas/data/ptv.cljc b/webapp/src/cljc/lipas/data/ptv.cljc index c6cf080b2..5197f409b 100644 --- a/webapp/src/cljc/lipas/data/ptv.cljc +++ b/webapp/src/cljc/lipas/data/ptv.cljc @@ -144,7 +144,7 @@ (defn ->ptv-service-location [org coord-transform-fn - {:keys [ptv lipas-id location search-meta] :as sports-site}] + {:keys [status ptv lipas-id location search-meta] :as sports-site}] (let [languages (-> ptv (get :languages default-langs) (->> (map lipas-lang->ptv-lang)) @@ -216,7 +216,10 @@ :latitude lat :longitude lon})}] - :publishingStatus "Published" ; Draft | Published + :publishingStatus (case status + ("incorrect-data" "out-of-service-permanently") "Deleted" + "Published") + ; Draft | Published ;; Link services by serviceId :services (-> sports-site :ptv :service-ids) diff --git a/webapp/src/cljs/lipas/ui/ptv/views.cljs b/webapp/src/cljs/lipas/ui/ptv/views.cljs index e30a5f37e..c7cb36ece 100644 --- a/webapp/src/cljs/lipas/ui/ptv/views.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/views.cljs @@ -376,7 +376,13 @@ :multiline true :on-change #(==> [::events/set-description site @selected-tab %]) :label "Kuvaus" - :value (get-in site [:description @selected-tab])}]]]))])) + :value (get-in site [:description @selected-tab])}] + + [mui/button {:disabled loading? + :on-click #(==> [::events/create-ptv-service-location (:lipas-id site) [] []])} + "Vie PTV"] + + ]]))])) (defn table [] (r/with-let [expanded-rows (r/atom {})] @@ -847,6 +853,7 @@ {:expandIcon ($ Icon "expand_more")} ($ Typography {:sx #js {:mr 1.5}} + ;; TODO: Should also show if already saved to ptv or not? (cond name-conflict ($ Icon {:color "warning"} "warning") valid ($ Icon {:color "success"} "done") @@ -1118,6 +1125,7 @@ [lui/dialog {:open? open? + ;; FIXME: This isn't implemented, what should this do? :on-save #(==> [::events/save sites]) :save-enabled? true :save-label (tr :actions/save) From 6b6b7d10b33582db87be3f8beaacd6a46f02b702 Mon Sep 17 00:00:00 2001 From: Juho Teperi Date: Fri, 8 Nov 2024 12:26:07 +0200 Subject: [PATCH 44/68] wip --- webapp/package-lock.json | 27 +++++ webapp/package.json | 1 + webapp/src/clj/lipas/backend/ptv/core.clj | 39 +++---- webapp/src/clj/lipas/backend/ptv/handler.clj | 48 ++++++-- .../src/clj/lipas/backend/ptv/integration.clj | 2 +- webapp/src/cljs/lipas/ui/map/views.cljs | 37 ++++-- webapp/src/cljs/lipas/ui/ptv/events.cljs | 26 ++--- webapp/src/cljs/lipas/ui/ptv/site_view.cljs | 82 +++++++++++++ webapp/src/cljs/lipas/ui/ptv/subs.cljs | 21 ++-- webapp/src/cljs/lipas/ui/ptv/views.cljs | 110 +++++++++++------- 10 files changed, 290 insertions(+), 103 deletions(-) create mode 100644 webapp/src/cljs/lipas/ui/ptv/site_view.cljs diff --git a/webapp/package-lock.json b/webapp/package-lock.json index fc3518800..62b0a97fc 100644 --- a/webapp/package-lock.json +++ b/webapp/package-lock.json @@ -13,6 +13,7 @@ "@emotion/styled": "^11.11.5", "@hello-pangea/dnd": "^16.6.0", "@mapbox/togeojson": "^0.16.0", + "@mui/icons-material": "^5.16.7", "@mui/material": "^5.15.19", "@turf/area": "^6.5.0", "@turf/bbox": "^6.0.1", @@ -474,6 +475,32 @@ "url": "https://opencollective.com/mui-org" } }, + "node_modules/@mui/icons-material": { + "version": "5.16.7", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.16.7.tgz", + "integrity": "sha512-UrGwDJCXEszbDI7yV047BYU5A28eGJ79keTCP4cc74WyncuVrnurlmIRxaHL8YK+LI1Kzq+/JM52IAkNnv4u+Q==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.23.9" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@mui/material": "^5.0.0", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@mui/material": { "version": "5.16.7", "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.16.7.tgz", diff --git a/webapp/package.json b/webapp/package.json index a6b3adf3f..fcc0f5399 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -19,6 +19,7 @@ "@emotion/styled": "^11.11.5", "@hello-pangea/dnd": "^16.6.0", "@mapbox/togeojson": "^0.16.0", + "@mui/icons-material": "^5.16.7", "@mui/material": "^5.15.19", "@turf/area": "^6.5.0", "@turf/bbox": "^6.0.1", diff --git a/webapp/src/clj/lipas/backend/ptv/core.clj b/webapp/src/clj/lipas/backend/ptv/core.clj index 95e81a0f2..26a40305f 100644 --- a/webapp/src/clj/lipas/backend/ptv/core.clj +++ b/webapp/src/clj/lipas/backend/ptv/core.clj @@ -71,13 +71,10 @@ :service-channel-ids]) (defn upsert-ptv-service-location! - [db search user {:keys [org ptv-meta sports-site] :as _m}] - (assert (:lipas-id sports-site)) - (let [site (db/get-sports-site db (:lipas-id sports-site)) - _ (assert (some? site) - (str "Sports site " (:lipas-id sports-site) " not found in DB")) - ;; NOTE: Is this available always? Where is ptv-meta originally intitialized? - config {:org-id (:org-id ptv-meta)} + [db search user {:keys [org lipas-id ptv-meta sports-site] :as _m}] + (let [site (db/get-sports-site db lipas-id) + _ (assert (some? site) (str "Sports site " lipas-id " not found in DB")) + config {} ;; This is the service-channel-id in Lipas DB (which won't exist for new service-locations) ;; id (first (get-in site [:ptv :service-channel-ids])) ;; This is the ID from UI, possibly updated/set with "Liitä tähän palvelupaikkaan" @@ -85,31 +82,33 @@ id (-> sports-site :ptv :service-channel-ids first) ;; _ (log/infof "FOO: %s %s" id (-> sports-site :ptv :service-channel-ids)) site (update site :ptv merge ptv-meta) - _ (log/infof "Site data: %s" site) + ;; _ (log/infof "Site data: %s" site) data (ptv-data/->ptv-service-location org gis/wgs84->tm35fin-no-wrap (core/enrich site)) - _ (log/infof "Created data: %s" data) + ;; _ (log/infof "Created data: %s" data) ptv-resp (if id (ptv/update-service-location config id data) (ptv/create-service-location config data)) + ;; Use the same TS for ptv last-sync and site event-date now (utils/timestamp) - to-persist (-> ptv-meta - (select-keys persisted-ptv-keys) - (assoc :last-sync now - ;; Store the PTV status so we can ignore Lipas archived places that we already archived in PTV. - :publishing-status (:publishingStatus ptv-resp) - ;; Take the created ID from ptv response and store to Lipas DB right away. - ;; TODO: Is there a case where this could be multiple ids? - :service-channel-ids (set [(:id ptv-resp)])))] + ;; Store the new PTV info to Lipas DB + new-ptv-data (-> ptv-meta + (select-keys persisted-ptv-keys) + (assoc :last-sync now + ;; Store the PTV status so we can ignore Lipas archived places that we already archived in PTV. + :publishing-status (:publishingStatus ptv-resp) + ;; Take the created ID from ptv response and store to Lipas DB right away. + ;; TODO: Is there a case where this could be multiple ids? + :service-channel-ids (set [(:id ptv-resp)])))] - (log/infof "Upserted (Lipas status: %s, updated: %s) service-location %s: %s" (:status site) (boolean id) data to-persist) + (log/infof "Upserted (Lipas status: %s, updated: %s) service-location %s: %s" (:status site) (boolean id) data new-ptv-data) (core/save-sports-site! db search user (-> site (assoc :event-date now) - (assoc :ptv to-persist))) + (assoc :ptv new-ptv-data))) {;; Return the updated :ptv meta for sports-site, to for the app-db - :ptv-meta to-persist + :ptv-meta new-ptv-data ;; Return :id :name, same as the list endpoint that is used in the UI to show the Palvelupaikka autocomplete :ptv-resp {:id (:id ptv-resp) :name (some (fn [x] diff --git a/webapp/src/clj/lipas/backend/ptv/handler.clj b/webapp/src/clj/lipas/backend/ptv/handler.clj index 9c9daea95..ad4156484 100644 --- a/webapp/src/clj/lipas/backend/ptv/handler.clj +++ b/webapp/src/clj/lipas/backend/ptv/handler.clj @@ -1,8 +1,40 @@ (ns lipas.backend.ptv.handler - (:require [lipas.backend.ptv.core :as ptv-core])) + (:require [lipas.backend.ptv.core :as ptv-core] + [reitit.coercion.malli])) + +(defn localized-string-schema [string-props] + [:map + {:closed true} + [:fi [:string string-props]] + [:se [:string string-props]] + [:en [:string string-props]]]) + +(def integration-enum + [:enum "lipas-managed"]) + +(def ptv-meta + [:map + ;; TODO: one or many? + [:service-channel-id :string] + [:service-channel-integration integration-enum] + [:sync-enabled :boolean] + [:service-integration integration-enum] + [:summary (localized-string-schema {:max 150})] + [:description (localized-string-schema {})]]) + +(def create-ptv-service-location + [:map + {:closed true} + [:org :string] + [:lipas-id :string] + [:ptv ptv-meta]]) (defn routes [{:keys [db search] :as _ctx}] - [["/actions/get-ptv-integration-candidates" + ["" + {:coercion reitit.coercion.malli/coercion + :tags ["ptv"]} + + ["/actions/get-ptv-integration-candidates" {:post {:no-doc false :require-privilege :ptv/manage @@ -15,7 +47,7 @@ {:post {:no-doc false :require-privilege :ptv/manage - :parameters {:body map?} + :parameters {:body [:any]} :handler (fn [{:keys [body-params]}] {:status 200 @@ -25,7 +57,7 @@ {:post {:no-doc false :require-privilege :ptv/manage - :parameters {:body map?} + :parameters {:body [:any]} :handler (fn [{:keys [body-params]}] {:status 200 @@ -35,7 +67,7 @@ {:post {:no-doc false :require-privilege :ptv/manage - :parameters {:body map?} + :parameters {:body [:any]} :handler (fn [{:keys [body-params]}] {:status 200 @@ -45,7 +77,7 @@ {:post {:no-doc false :require-privilege :ptv/manage - :parameters {:body map?} + :parameters {:body [:any]} :handler (fn [{:keys [body-params]}] {:status 200 @@ -55,7 +87,7 @@ {:post {:no-doc false :require-privilege :ptv/manage - :parameters {:body map?} + :parameters {:body create-ptv-service-location} :handler (fn [{:keys [body-params identity]}] {:status 200 @@ -65,7 +97,7 @@ {:post {:no-doc false :require-privilege :ptv/manage - :parameters {:body map?} + :parameters {:body [:any]} :handler (fn [{:keys [body-params identity]}] {:status 200 diff --git a/webapp/src/clj/lipas/backend/ptv/integration.clj b/webapp/src/clj/lipas/backend/ptv/integration.clj index 7a8414029..ed8b4777c 100644 --- a/webapp/src/clj/lipas/backend/ptv/integration.clj +++ b/webapp/src/clj/lipas/backend/ptv/integration.clj @@ -132,7 +132,7 @@ (if (and (not retried?) (= 401 (:status d)) (= "Bearer error=\"invalid_token\", error_description=\"The access token is not valid.\"" - (get (:headers d) "rWW-Authenticate"))) + (get (:headers d) "WWW-Authenticate"))) (do (log/infof "Invalid token, trying to get a new token and retry") (swap! current-token dissoc (:auth-org-id req)) diff --git a/webapp/src/cljs/lipas/ui/map/views.cljs b/webapp/src/cljs/lipas/ui/map/views.cljs index 4b2fb6872..82550ce22 100644 --- a/webapp/src/cljs/lipas/ui/map/views.cljs +++ b/webapp/src/cljs/lipas/ui/map/views.cljs @@ -11,7 +11,7 @@ ["mdi-material-ui/MapSearchOutline$default" :as MapSearchOutline] ["react" :as react] [clojure.spec.alpha :as s] - [clojure.string :as string] + [clojure.string :as str] [lipas.data.activities :as activities-data] [lipas.data.sports-sites :as ss] [lipas.roles :as roles] @@ -26,6 +26,7 @@ [lipas.ui.map.subs :as subs] [lipas.ui.mui :as mui] [lipas.ui.navbar :as nav] + [lipas.ui.ptv.site-view :as ptv-site] [lipas.ui.ptv.views :as ptv] [lipas.ui.reminders.views :as reminders] [lipas.ui.reports.views :as reports] @@ -39,8 +40,7 @@ [lipas.ui.utils :refer [<== ==>] :as utils] [re-frame.core :as rf] [reagent.core :as r] - [uix.core :as uix] - [uix.core :refer [$ defui]])) + [uix.core :as uix :refer [$ defui]])) ;; TODO: Juho later This pattern makes development inconvenient as ;; the component might crash and shadow-cljs reloads don't update it. @@ -276,11 +276,11 @@ "my_location"]]]) (defn filter-by-term [term table-data] - (let [lower-case-term (string/lower-case term)] - (filter #(or (string/includes? (string/lower-case (% :name)) lower-case-term) - (string/includes? (string/lower-case (% :geometry-type)) lower-case-term) - (string/includes? (string/lower-case (% :description)) lower-case-term) - (string/includes? (string/lower-case (string/join (% :tags))) lower-case-term)) + (let [lower-case-term (str/lower-case term)] + (filter #(or (str/includes? (str/lower-case (% :name)) lower-case-term) + (str/includes? (str/lower-case (% :geometry-type)) lower-case-term) + (str/includes? (str/lower-case (% :description)) lower-case-term) + (str/includes? (str/lower-case (str/join (% :tags))) lower-case-term)) table-data))) (defn type-helper-table [{:keys [tr on-select types]}] @@ -533,7 +533,7 @@ [mui/typography (tr :analysis/mode)]] [mui/table-cell (when (seq (:diversity-idx-mode data)) - (string/join "," (:diversity-idx-mode data)))]]]] + (str/join "," (:diversity-idx-mode data)))]]]] ;; No data available [:div {:style {:width "200px" :padding "0.5em 0.5em 0em 0.5em"}} @@ -930,7 +930,12 @@ [mui/tab {:style {:min-width 0} :value 4 - :label (tr :sports-site.elevation-profile/headline)}])] + :label (tr :sports-site.elevation-profile/headline)}]) + + [mui/tab + {:style {:min-width 0} + :value 6 + :label "PTV"}]] (when delete-dialog-open? [sports-sites/delete-dialog @@ -1034,7 +1039,17 @@ :type-code type-code :display-data display-data :edit-data edit-data - :can-edit? edit-activities?}]])] + :can-edit? edit-activities?}]] + + 6 [mui/grid {:item true :xs 12} + ($ ptv-site/site-view + {:tr tr + :lipas-id lipas-id + :type-code type-code + ; :display-data display-data + :edit-data edit-data + :can-edit? can-publish? + })])] ;; "Landing bay" for floating tools [mui/grid {:item true :xs 12 :style {:height "3em"}}] diff --git a/webapp/src/cljs/lipas/ui/ptv/events.cljs b/webapp/src/cljs/lipas/ui/ptv/events.cljs index 05f371b3d..8e25e35e3 100644 --- a/webapp/src/cljs/lipas/ui/ptv/events.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/events.cljs @@ -553,28 +553,20 @@ (rf/reg-event-fx ::create-ptv-service-location (fn [{:keys [db]} [_ lipas-id success-fx failure-fx]] (let [token (-> db :user :login :token) + ;; Or per site? org-id (-> db :ptv :selected-org :id) - site (get-in db [:ptv :org org-id :data :sports-sites lipas-id]) - data (get-in db [:ptv :service-locations-creation :data lipas-id]) - ks [:languages - :summary - :description - :last-sync - :org-id - :sync-enabled - :service-integration - :descriptions-integration - :service-channel-integration - :service-ids - :service-channel-ids]] + ptv-data (get-in db [:ptv :org org-id :data :sports-sites lipas-id :ptv]) + ;; What is this? + ;; data (get-in db [:ptv :service-locations-creation :data lipas-id]) + ] {:db (assoc-in db [:ptv :loading-from-lipas :service-locations] true) :fx [[:http-xhrio {:method :post :headers {:Authorization (str "Token " token)} :uri (str (:backend-url db) "/actions/save-ptv-service-location") - :params {:sports-site site - :ptv-meta data - :org (org-id->params org-id)} + :params {:lipas-id lipas-id + :org (org-id->params org-id) + :ptv ptv-data} :format (ajax/transit-request-format) :response-format (ajax/transit-response-format) :on-success [::create-ptv-service-location-success lipas-id success-fx] @@ -586,6 +578,8 @@ {:db (-> db (assoc-in [:ptv :loading-from-lipas :service-channels] false) (assoc-in [:ptv :org org-id :data :service-channels (:id ptv-resp)] ptv-resp) + ;; Update the lipas TS also, it will be the same TS as PTV last-sync now + (assoc-in [:ptv :org org-id :data :sports-sites lipas-id :event-date] (:last-sync ptv-meta)) (assoc-in [:ptv :org org-id :data :sports-sites lipas-id :ptv] ptv-meta)) :fx extra-fx}))) diff --git a/webapp/src/cljs/lipas/ui/ptv/site_view.cljs b/webapp/src/cljs/lipas/ui/ptv/site_view.cljs new file mode 100644 index 000000000..7556257e4 --- /dev/null +++ b/webapp/src/cljs/lipas/ui/ptv/site_view.cljs @@ -0,0 +1,82 @@ +(ns lipas.ui.ptv.site-view + (:require ["@mui/material/Button$default" :as Button] + ["@mui/material/FormControl$default" :as FormControl] + ["@mui/material/FormLabel$default" :as FormLabel] + ["@mui/material/Stack$default" :as Stack] + ["@mui/material/Tab$default" :as Tab] + ["@mui/material/Tabs$default" :as Tabs] + ["@mui/material/Typography$default" :as Typography] + [goog.string.format] + [lipas.ui.components :as lui] + [lipas.ui.ptv.events :as events] + [lipas.ui.uix.hooks :refer [use-subscribe]] + [lipas.ui.utils :refer [<== ==>]] + [reagent.core :as r] + [uix.core :as uix :refer [$ defui]])) + +(defui site-view [{:keys [_tr lipas-id can-edit? edit-data]}] + (let [[selected-tab set-selected-tab] (uix/use-state "fi") + + editing? (and can-edit? (<== [:lipas.ui.sports-sites.subs/editing? lipas-id])) + read-only? (not editing?) + site (use-subscribe [:lipas.ui.sports-sites.subs/latest-rev lipas-id]) + + loading? false] + (js/console.log site) + (js/console.log edit-data) + ($ Stack + {:direction "column" + :sx #js {:gap 2}} + + ($ FormControl + ($ FormLabel + "Lipas tila") + ($ Typography + (:status site))) + + ($ FormControl + ($ FormLabel + "PTV Tila") + ($ Typography + (:publishing-status (:ptv site)) + (:last-sync (:ptv site)))) + + ($ Tabs + {:value selected-tab + :on-change (fn [_e v] (set-selected-tab v))} + ($ Tab {:value "fi" :label "FI"}) + ($ Tab {:value "se" :label "SE"}) + ($ Tab {:value "en" :label "EN"})) + + ;; Summary + (r/as-element + [lui/text-field + {:disabled loading? + :multiline true + :read-only? (or (not= "manual" (:descriptions-integration site)) + read-only?) + :variant "outlined" + :on-change #(==> [::events/set-summary site selected-tab %]) + :label "Tiivistelmä" + :value (get-in site [:ptv :summary selected-tab])}]) + + ;; Description + (r/as-element + [lui/text-field + {:disabled loading? + :variant "outlined" + :read-only? (or (not= "manual" (:descriptions-integration site)) + read-only?) + :rows 5 + :multiline true + :on-change #(==> [::events/set-description site selected-tab %]) + :label "Kuvaus" + :value (get-in site [:ptv :description selected-tab])}]) + + ($ Button + {:variant "contained" + :color "primary" + :disabled (or (not can-edit?) + loading?) + :on-click #(==> [::events/create-ptv-service-location lipas-id [] []])} + "Vie PTV")))) diff --git a/webapp/src/cljs/lipas/ui/ptv/subs.cljs b/webapp/src/cljs/lipas/ui/ptv/subs.cljs index 68e557811..8672b219b 100644 --- a/webapp/src/cljs/lipas/ui/ptv/subs.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/subs.cljs @@ -284,11 +284,15 @@ (-> site :ptv :description) "ptv-managed" - (tr :ptv.integration.description/ptv-managed-helper))] + (tr :ptv.integration.description/ptv-managed-helper)) + + last-sync (-> site :ptv :last-sync)] {:valid (boolean (and (some-> description :fi count (> 5)) (some-> summary :fi count (> 5)))) :lipas-id (:lipas-id site) :name (:name site) + :event-date (:event-date site) + :event-date-human (some-> (:event-date site) utils/->human-date-time-at-user-tz) :name-conflict (detect-name-conflict site (vals service-channels)) :marketing-name (:marketing-name site) :type (-> site :search-meta :type :name :fi) @@ -303,12 +307,15 @@ :descriptions-integration descriptions-integration :sync-enabled (get-in site [:ptv :sync-enabled] true) - :last-sync (-> site :ptv :last-sync) - :last-sync-human (or (some-> site - :ptv - :last-sync - utils/->human-date-time-at-user-tz) - "Ei koskaan") + :last-sync last-sync + :last-sync-human (or (some-> last-sync utils/->human-date-time-at-user-tz) + "Ei koskaan") + + :sync-status (cond + (not last-sync) :not-synced + (= (:event-date site) last-sync) :ok + :else :out-of-date) + :service-ids (-> site :ptv :service-ids) :service-name (-> services (get service-id) :serviceNames (->> (some #(when (= "fi" (:language %)) (:value %))))) diff --git a/webapp/src/cljs/lipas/ui/ptv/views.cljs b/webapp/src/cljs/lipas/ui/ptv/views.cljs index c7cb36ece..f568b93d6 100644 --- a/webapp/src/cljs/lipas/ui/ptv/views.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/views.cljs @@ -1,5 +1,15 @@ (ns lipas.ui.ptv.views - (:require ["@mui/material/Paper$default" :as Paper] + (:require ["@mui/icons-material/Sync$default" :as Sync] + ["@mui/icons-material/SyncDisabled$default" :as SyncDisabled] + ["@mui/icons-material/SyncProblem$default" :as SyncProblem] + ["@mui/material/Accordion$default" :as Accordion] + ["@mui/material/AccordionDetails$default" :as AccordionDetails] + ["@mui/material/AccordionSummary$default" :as AccordionSummary] + ["@mui/material/Avatar$default" :as Avatar] + ["@mui/material/Icon$default" :as Icon] + ["@mui/material/Paper$default" :as Paper] + ["@mui/material/Stack$default" :as Stack] + ["@mui/material/Typography$default" :as Typography] [goog.string.format] [lipas.data.ptv :as ptv-data] [lipas.ui.components :as lui] @@ -10,12 +20,7 @@ [lipas.ui.uix.hooks :refer [use-subscribe]] [lipas.ui.utils :refer [<== ==>]] [reagent.core :as r] - [uix.core :as uix :refer [$ defui]] - ["@mui/material/Accordion$default" :as Accordion] - ["@mui/material/AccordionSummary$default" :as AccordionSummary] - ["@mui/material/Icon$default" :as Icon] - ["@mui/material/Typography$default" :as Typography] - ["@mui/material/AccordionDetails$default" :as AccordionDetails])) + [uix.core :as uix :refer [$ defui]])) ;; Memo ;; - preset service structure with descriptions @@ -391,6 +396,7 @@ sync-all-enabled? (<== [::subs/sync-all-enabled?]) headers [{:key :expand :label "" :padding "checkbox"} + #_ {:key :selected :label (tr :ptv.actions/export) :padding "checkbox" :action-component @@ -398,6 +404,7 @@ {:value sync-all-enabled? :on-change #(==> [::events/toggle-sync-all %2])}]} #_{:key :auto-sync :label "Vie automaattisesti"} + {:key :event-data :label "Tila"} {:key :last-sync :label "Viety viimeksi"} {:key :name :label (tr :general/name)} {:key :type :label (tr :general/type)} @@ -424,59 +431,82 @@ ;; Body [mui/table-body (doall - (for [{:keys [lipas-id] :as site} (sort-by :type sites)] + (for [{:keys [lipas-id sync-status] :as site} (sort-by :type sites)] [:<> {:key lipas-id} - ;; Summary row - [mui/table-row #_{:on-click (fn [] (swap! expanded-rows update lipas-id not))} + [mui/table-row + {:sx [{} + ]} ;; Expand toggle - [mui/table-cell - [mui/icon-button - {:style {:zIndex 1} - :size "small" - :on-click (fn [] (swap! expanded-rows update lipas-id not))} - [mui/icon - (if (get @expanded-rows lipas-id false) - "keyboard_arrow_up_icon" - "keyboard_arrow_down_icon")]]] + [mui/table-cell + [mui/icon-button + {:style {:zIndex 1} + :size "small" + :on-click (fn [] (swap! expanded-rows update lipas-id not))} + [mui/icon + (if (get @expanded-rows lipas-id false) + "keyboard_arrow_up_icon" + "keyboard_arrow_down_icon")]]] ;; Enable sync - [mui/table-cell - [lui/switch - {:value (:sync-enabled site) - :on-change #(==> [::events/toggle-sync-enabled site %])}]] + #_ + [mui/table-cell + [lui/switch + {:value (:sync-enabled site) + :on-change #(==> [::events/toggle-sync-enabled site %])}]] + + [mui/table-cell + ($ Stack + {:direction "row" + :alignItems "center"} + ($ Avatar + {:sx #js {:bgcolor (if (:sync-enabled site) + (case sync-status + :ok "success.main" + :not-synced "error.main" + :out-of-date "warning.main") + mui/gray3) + :mr 2}} + (if (:sync-enabled site) + (if (= :ok sync-status) + ($ Sync {:color "white"}) + ($ SyncProblem + {:color "white"})) + ($ SyncDisabled {:background "white"}))) + #_ + (:event-date-human site))] ;; Last-sync - [mui/table-cell - (:last-sync-human site)] + [mui/table-cell + (:last-sync-human site)] ;; Name - [mui/table-cell - (:name site)] + [mui/table-cell + (:name site)] ;; Type - [mui/table-cell - (:type site)] + [mui/table-cell + (:type site)] ;; Admin ;;[mui/table-cell] ;; Owner - [mui/table-cell - (:owner site)] + [mui/table-cell + (:owner site)] ;; Service - #_[mui/table-cell - [services-selector]] + #_[mui/table-cell + [services-selector]] ;; Service channell - #_[mui/table-cell - #_[service-channel-selector]] + #_[mui/table-cell + #_[service-channel-selector]] ;; Description - #_[mui/table-cell]] + #_[mui/table-cell]] ;; Details row [mui/table-row @@ -1126,12 +1156,12 @@ [lui/dialog {:open? open? ;; FIXME: This isn't implemented, what should this do? - :on-save #(==> [::events/save sites]) - :save-enabled? true - :save-label (tr :actions/save) + ; :on-save #(==> [::events/save sites]) + ; :save-enabled? true + ; :save-label (tr :actions/save) :title (tr :ptv/tooltip) :max-width "xl" - :cancel-label (tr :actions/cancel) + :cancel-label "Sulje" ;; (tr :actions/cancel) :on-close #(==> [::events/close-dialog])} [mui/stack {:spacing 2} From 634be17cccf66b06a30b7f1facabc72dbc0869ef Mon Sep 17 00:00:00 2001 From: Juho Teperi Date: Mon, 11 Nov 2024 13:35:58 +0200 Subject: [PATCH 45/68] Sync site data to ptv on save --- webapp/src/clj/lipas/backend/core.clj | 21 +- webapp/src/clj/lipas/backend/ptv/core.clj | 84 ++--- webapp/src/clj/lipas/backend/ptv/handler.clj | 2 +- webapp/src/cljc/lipas/data/ptv.cljc | 21 +- webapp/src/cljs/lipas/ui/ptv/controls.cljs | 144 +++++++++ webapp/src/cljs/lipas/ui/ptv/site_view.cljs | 69 ++-- webapp/src/cljs/lipas/ui/ptv/views.cljs | 321 ++++++------------- 7 files changed, 365 insertions(+), 297 deletions(-) create mode 100644 webapp/src/cljs/lipas/ui/ptv/controls.cljs diff --git a/webapp/src/clj/lipas/backend/core.clj b/webapp/src/clj/lipas/backend/core.clj index dc2071955..d09140911 100644 --- a/webapp/src/clj/lipas/backend/core.clj +++ b/webapp/src/clj/lipas/backend/core.clj @@ -522,15 +522,18 @@ (add-to-webhook-queue! tx {:lipas-ids [(:lipas-id resp)]})) - ;; FIXME: This is called from ptv-integration to store :ptv metadata. That should maybe - ;; call upsert-sports-site! instead so it doesn't trigger indexing and other stuff? - (when (and (#{"out-of-service-permanently" - "incorrect-data"} - (:status resp)) - (:ptv resp)) - (log/infof "Sports-site was archived, shold be removed from PTV?")) - - resp)))) + ;; Sync the updated site to ptv if the ptv integration is enabled + (if (and (not draft?) + (:ptv resp) + (:sync-enabled (:ptv resp))) + (let [new-ptv-data ((resolve 'lipas.backend.ptv.core/upsert-ptv-service-location!) + tx user + {:org (:org-id (:ptv resp)) + :lipas-id (:lipas-id resp) + :ptv (:ptv resp)})] + (log/infof "Sports site updated and PTV integration enabled") + (assoc resp :ptv new-ptv-data)) + resp))))) ;;; Cities ;;; diff --git a/webapp/src/clj/lipas/backend/ptv/core.clj b/webapp/src/clj/lipas/backend/ptv/core.clj index 26a40305f..dd5a6f72f 100644 --- a/webapp/src/clj/lipas/backend/ptv/core.clj +++ b/webapp/src/clj/lipas/backend/ptv/core.clj @@ -71,51 +71,51 @@ :service-channel-ids]) (defn upsert-ptv-service-location! - [db search user {:keys [org lipas-id ptv-meta sports-site] :as _m}] - (let [site (db/get-sports-site db lipas-id) - _ (assert (some? site) (str "Sports site " lipas-id " not found in DB")) - config {} - ;; This is the service-channel-id in Lipas DB (which won't exist for new service-locations) - ;; id (first (get-in site [:ptv :service-channel-ids])) - ;; This is the ID from UI, possibly updated/set with "Liitä tähän palvelupaikkaan" - ;; We probably want to use this always? - id (-> sports-site :ptv :service-channel-ids first) - ;; _ (log/infof "FOO: %s %s" id (-> sports-site :ptv :service-channel-ids)) - site (update site :ptv merge ptv-meta) - ;; _ (log/infof "Site data: %s" site) - data (ptv-data/->ptv-service-location org gis/wgs84->tm35fin-no-wrap (core/enrich site)) - ;; _ (log/infof "Created data: %s" data) - ptv-resp (if id - (ptv/update-service-location config id data) - (ptv/create-service-location config data)) - ;; Use the same TS for ptv last-sync and site event-date - now (utils/timestamp) - ;; Store the new PTV info to Lipas DB - new-ptv-data (-> ptv-meta - (select-keys persisted-ptv-keys) - (assoc :last-sync now - ;; Store the PTV status so we can ignore Lipas archived places that we already archived in PTV. - :publishing-status (:publishingStatus ptv-resp) - ;; Take the created ID from ptv response and store to Lipas DB right away. - ;; TODO: Is there a case where this could be multiple ids? - :service-channel-ids (set [(:id ptv-resp)])))] + [db user {:keys [org lipas-id ptv] :as _m}] + (jdbc/with-db-transaction [tx db] + (let [site (db/get-sports-site db lipas-id) + _ (assert (some? site) (str "Sports site " lipas-id " not found in DB")) + config nil + + id (-> ptv :service-channel-ids first) + ;; merge or just replace? + site (update site :ptv merge ptv) + ;; Use the same TS for sourceId, ptv last-sync and site event-date + now (utils/timestamp) + data (ptv-data/->ptv-service-location org gis/wgs84->tm35fin-no-wrap now (core/enrich site)) + ptv-resp (if id + (ptv/update-service-location config id data) + (ptv/create-service-location config data)) + ;; Store the new PTV info to Lipas DB + new-ptv-data (-> ptv + (select-keys persisted-ptv-keys) + (assoc :last-sync now + :source-id (:sourceId ptv-resp) + ;; Store the PTV status so we can ignore Lipas archived places that we already archived in PTV. + :publishing-status (:publishingStatus ptv-resp) + ;; Take the created ID from ptv response and store to Lipas DB right away. + ;; TODO: Is there a case where this could be multiple ids? + :service-channel-ids (set [(:id ptv-resp)])))] - (log/infof "Upserted (Lipas status: %s, updated: %s) service-location %s: %s" (:status site) (boolean id) data new-ptv-data) + (log/infof "Upserted (Lipas status: %s, updated: %s) service-location %s: %s" (:status site) (boolean id) data new-ptv-data) - (core/save-sports-site! db search user - (-> site - (assoc :event-date now) - (assoc :ptv new-ptv-data))) + (core/upsert-sports-site! tx + user + (-> site + (assoc :event-date now) + (assoc :ptv new-ptv-data)) + false) + ;; No need to re-index for search after ptv change - {;; Return the updated :ptv meta for sports-site, to for the app-db - :ptv-meta new-ptv-data - ;; Return :id :name, same as the list endpoint that is used in the UI to show the Palvelupaikka autocomplete - :ptv-resp {:id (:id ptv-resp) - :name (some (fn [x] - (when (and (= "Name" (:type x)) - (= "fi" (:language x))) - (:value x))) - (:serviceChannelNames ptv-resp))}})) + {;; Return the updated :ptv meta for sports-site, to for the app-db + :ptv new-ptv-data + ;; Return :id :name, same as the list endpoint that is used in the UI to show the Palvelupaikka autocomplete + :ptv-resp {:id (:id ptv-resp) + :name (some (fn [x] + (when (and (= "Name" (:type x)) + (= "fi" (:language x))) + (:value x))) + (:serviceChannelNames ptv-resp))}}))) (defn save-ptv-integration-definitions "Saves ptv definitions under key :ptv. Does not notify webhooks, diff --git a/webapp/src/clj/lipas/backend/ptv/handler.clj b/webapp/src/clj/lipas/backend/ptv/handler.clj index ad4156484..9833df6fc 100644 --- a/webapp/src/clj/lipas/backend/ptv/handler.clj +++ b/webapp/src/clj/lipas/backend/ptv/handler.clj @@ -91,7 +91,7 @@ :handler (fn [{:keys [body-params identity]}] {:status 200 - :body (ptv-core/upsert-ptv-service-location! db search identity body-params)})}}] + :body (ptv-core/upsert-ptv-service-location! db identity body-params)})}}] ["/actions/save-ptv-meta" {:post diff --git a/webapp/src/cljc/lipas/data/ptv.cljc b/webapp/src/cljc/lipas/data/ptv.cljc index 5197f409b..2a4272d68 100644 --- a/webapp/src/cljc/lipas/data/ptv.cljc +++ b/webapp/src/cljc/lipas/data/ptv.cljc @@ -1,7 +1,8 @@ (ns lipas.data.ptv - (:require - [lipas.data.types :as types] - [lipas.utils :as utils])) + (:require [clojure.string :as str] + [lipas.data.types :as types] + [lipas.utils :as utils] + [taoensso.timbre :as log])) ;; Utajärven jäähalli ;; https://api.palvelutietovaranto.suomi.fi/api/v11/ServiceChannel/8604a900-be6b-4f9d-8024-a272e07afba3?showHeader=false @@ -144,6 +145,7 @@ (defn ->ptv-service-location [org coord-transform-fn + now {:keys [status ptv lipas-id location search-meta] :as sports-site}] (let [languages (-> ptv (get :languages default-langs) @@ -155,12 +157,17 @@ (println "PTV data") (prn ptv) - (println "Langauges resolved" languages) - (prn location) + ; (println "Languages resolved" languages) + ; (prn location) {:organizationId (:org-id ptv) - ;; FIXME: PTV doesn't allow a new ServiceLocation with a same sourceId as a Deleted one - :sourceId (str "lipas3-" (:org-id ptv) "-" lipas-id) + ;; Keep using existing sourceId for sites that were already initialized in PTV, + ;; generate a new unique ID (with timestamp) for new sites. + :sourceId (or (:sourceId ptv) + (let [ts (str/replace now #":" "-") + x (str "lipas-" (:org-id ptv) "-" lipas-id "-" ts)] + (log/infof "Creating new PTV source-id %s" x) + x)) :serviceChannelNames (keep identity (let [fallback (get-in sports-site [:name])] [(when (contains? languages "fi") diff --git a/webapp/src/cljs/lipas/ui/ptv/controls.cljs b/webapp/src/cljs/lipas/ui/ptv/controls.cljs new file mode 100644 index 000000000..d0cd125a3 --- /dev/null +++ b/webapp/src/cljs/lipas/ui/ptv/controls.cljs @@ -0,0 +1,144 @@ +(ns lipas.ui.ptv.controls + (:require ["@mui/material/FormControl$default" :as FormControl] + ["@mui/material/FormControlLabel$default" :as FormControlLabel] + ["@mui/material/FormLabel$default" :as FormLabel] + ["@mui/material/Radio$default" :as Radio] + ["@mui/material/RadioGroup$default" :as RadioGroup] + ["@mui/material/Tab$default" :as Tab] + ["@mui/material/Tabs$default" :as Tabs] + ["@mui/material/Typography$default" :as Typography] + [lipas.ui.components.autocompletes :refer [autocomplete2]] + [uix.core :as uix :refer [$ defui]])) + +(defui info-text [{:keys [children]}] + ($ Typography + {:variant "body1"} + children)) + +(defui services-selector + [{:keys [options value on-change label value-fn] + :or {value-fn identity + label ""}}] + (let [options* (uix/use-memo (fn [] + (map (fn [x] + {:value (value-fn x) + :label (:label x)}) + options)) + [options value-fn])] + ($ autocomplete2 + {:options options* + :multiple true + :label label + :value (to-array value) + :on-change (fn [_e v] + (on-change (:value v)))}))) + +(defui service-integration [{:keys [tr value on-change service-ids set-service-ids services]}] + ($ :<> + ($ Typography {:variant "h6"} + (tr :ptv/services)) + + ;; Integration type + ($ FormControl + ($ FormLabel (tr :ptv.actions/select-integration)) + ($ RadioGroup + {:on-change (fn [_e v] (on-change v)) + :value value} + ($ FormControlLabel + {:value "lipas-managed" + :label (tr :ptv.integration.service/lipas-managed) + :control ($ Radio)}) + + ($ FormControlLabel + {:value "manual" + :label (tr :ptv.integration/manual) + :control ($ Radio)}))) + + (when (= "lipas-managed" value) + (tr :ptv.integration.service/lipas-managed-helper)) + + (when (= "manual" value) + ($ services-selector + {:options services + :value service-ids + :on-change set-service-ids + :value-fn :service-id + :label (tr :ptv.actions/select-service)})))) + +(defui service-channel-integration [{:keys [tr value on-change]}] + ($ :<> + ($ Typography {:variant "h6"} + (tr :ptv/service-channels)) + + ;; Integration type + ($ FormControl + ($ FormLabel (tr :ptv.actions/select-integration)) + ($ RadioGroup + {:on-change (fn [_e v] (on-change v)) + :value value} + ($ FormControlLabel + {:value "lipas-managed" + :label (tr :ptv.integration.service-channel/lipas-managed) + :control ($ Radio)}) + + ($ FormControlLabel + {:value "manual" + :label (tr :ptv.integration/manual) + :control ($ Radio)}))) + + (case value + "lipas-managed" + ($ info-text (tr :ptv.integration.service-channel/lipas-managed-helper)) + + "manual" + ($ info-text (tr :ptv.integration.service-channel/manual-helper)) + + nil))) + +(defui description-integration [{:keys [tr value on-change]}] + ($ :<> + ($ Typography + {:variant "h6"} + (tr :ptv/descriptions)) + + ;; Integration type + ($ FormControl + ($ FormLabel (tr :ptv.actions/select-integration)) + ($ RadioGroup + {:on-change (fn [_e v] + (on-change v)) + :value value} + ($ FormControlLabel + {:value "lipas-managed-ptv-fields" + :label (tr :ptv.integration.description/lipas-managed-ptv-fields) + :control ($ Radio)}) + + ($ FormControlLabel + {:value "lipas-managed-comment-field" + :label (tr :ptv.integration.description/lipas-managed-comment-field) + :control ($ Radio)}) + + ($ FormControlLabel + {:value "ptv-managed" + :label (tr :ptv.integration.description/ptv-managed) + :control ($ Radio)}))) + + (case value + "lipas-managed-ptv-fields" + ($ Typography (tr :ptv.integration.description/lipas-managed-ptv-fields-helper)) + + "lipas-managed-comment-field" + ($ Typography (tr :ptv.integration.description/lipas-managed-comment-field-helper)) + + "ptv-managed" + ($ Typography (tr :ptv.integration.description/ptv-managed-helper)) + + nil))) + +(defui lang-selector [{:keys [value on-change]}] + ($ Tabs + {:value value + :on-change (fn [_e v] (on-change (keyword v)))} + ($ Tab {:value "fi" :label "FI"}) + ($ Tab {:value "se" :label "SE"}) + ($ Tab {:value "en" :label "EN"}))) diff --git a/webapp/src/cljs/lipas/ui/ptv/site_view.cljs b/webapp/src/cljs/lipas/ui/ptv/site_view.cljs index 7556257e4..12606167b 100644 --- a/webapp/src/cljs/lipas/ui/ptv/site_view.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/site_view.cljs @@ -1,33 +1,40 @@ (ns lipas.ui.ptv.site-view - (:require ["@mui/material/Button$default" :as Button] + (:require ["@mui/material/Alert$default" :as Alert] + ["@mui/material/Button$default" :as Button] ["@mui/material/FormControl$default" :as FormControl] ["@mui/material/FormLabel$default" :as FormLabel] ["@mui/material/Stack$default" :as Stack] - ["@mui/material/Tab$default" :as Tab] - ["@mui/material/Tabs$default" :as Tabs] ["@mui/material/Typography$default" :as Typography] - [goog.string.format] [lipas.ui.components :as lui] + [lipas.ui.ptv.controls :as controls] [lipas.ui.ptv.events :as events] [lipas.ui.uix.hooks :refer [use-subscribe]] - [lipas.ui.utils :refer [<== ==>]] + [re-frame.core :as rf] [reagent.core :as r] [uix.core :as uix :refer [$ defui]])) -(defui site-view [{:keys [_tr lipas-id can-edit? edit-data]}] - (let [[selected-tab set-selected-tab] (uix/use-state "fi") +(defui site-view [{:keys [tr lipas-id can-edit? edit-data]}] + (let [[selected-tab set-selected-tab] (uix/use-state :fi) - editing? (and can-edit? (<== [:lipas.ui.sports-sites.subs/editing? lipas-id])) + editing* (use-subscribe [:lipas.ui.sports-sites.subs/editing? lipas-id]) + editing? (and can-edit? editing*) read-only? (not editing?) - site (use-subscribe [:lipas.ui.sports-sites.subs/latest-rev lipas-id]) + site (use-subscribe [:lipas.ui.sports-sites.subs/latest-rev lipas-id]) + ;; default-settings {} + enabled (boolean (:ptv site)) - loading? false] + loading? false] (js/console.log site) (js/console.log edit-data) ($ Stack {:direction "column" :sx #js {:gap 2}} + (when (not enabled) + ($ Alert + {:severity "warning"} + "PTV integraatio ei käytössä tälle paikalle, käytä PTV käyttöönotto wizardia PTV palvelun alustamiseen.")) + ($ FormControl ($ FormLabel "Lipas tila") @@ -38,15 +45,27 @@ ($ FormLabel "PTV Tila") ($ Typography - (:publishing-status (:ptv site)) + (:publishing-status (:ptv site))) + ($ Typography (:last-sync (:ptv site)))) - ($ Tabs - {:value selected-tab - :on-change (fn [_e v] (set-selected-tab v))} - ($ Tab {:value "fi" :label "FI"}) - ($ Tab {:value "se" :label "SE"}) - ($ Tab {:value "en" :label "EN"})) + #_ + ($ controls/description-integration + {:value (:descriptions-integration (:ptv site)) + :on-change identity + :tr tr}) + + (when (= "lipas-managed-ptv-fields" (:descriptions-integration (:ptv site))) + ($ Button + {:disabled loading? + :variant "outlined" + :on-click (fn [_e] + (rf/dispatch [::events/generate-descriptions (:lipas-id site) [] []]))} + (tr :ptv.actions/generate-with-ai))) + + ($ controls/lang-selector + {:value selected-tab + :on-change set-selected-tab}) ;; Summary (r/as-element @@ -56,9 +75,11 @@ :read-only? (or (not= "manual" (:descriptions-integration site)) read-only?) :variant "outlined" - :on-change #(==> [::events/set-summary site selected-tab %]) + :on-change (fn [v] + (rf/dispatch [:lipas.ui.sports-sites.events/edit-field lipas-id [:ptv :summary selected-tab] v])) :label "Tiivistelmä" - :value (get-in site [:ptv :summary selected-tab])}]) + :value (or (get-in edit-data [:ptv :summary selected-tab]) + (get-in site [:ptv :summary selected-tab]))}]) ;; Description (r/as-element @@ -69,14 +90,18 @@ read-only?) :rows 5 :multiline true - :on-change #(==> [::events/set-description site selected-tab %]) + :on-change (fn [v] + (rf/dispatch [:lipas.ui.sports-sites.events/edit-field lipas-id [:ptv :description selected-tab] v])) :label "Kuvaus" - :value (get-in site [:ptv :description selected-tab])}]) + :value (or (get-in edit-data [:ptv :description selected-tab]) + (get-in site [:ptv :description selected-tab]))}]) + #_ ($ Button {:variant "contained" :color "primary" :disabled (or (not can-edit?) loading?) - :on-click #(==> [::events/create-ptv-service-location lipas-id [] []])} + :on-click (fn [_e] + (rf/dispatch [::events/create-ptv-service-location* lipas-id [] []]))} "Vie PTV")))) diff --git a/webapp/src/cljs/lipas/ui/ptv/views.cljs b/webapp/src/cljs/lipas/ui/ptv/views.cljs index f568b93d6..375392a09 100644 --- a/webapp/src/cljs/lipas/ui/ptv/views.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/views.cljs @@ -15,10 +15,12 @@ [lipas.ui.components :as lui] [lipas.ui.components.autocompletes :refer [autocomplete2]] [lipas.ui.mui :as mui] + [lipas.ui.ptv.controls :as controls] [lipas.ui.ptv.events :as events] [lipas.ui.ptv.subs :as subs] [lipas.ui.uix.hooks :refer [use-subscribe]] [lipas.ui.utils :refer [<== ==>]] + [re-frame.core :as rf] [reagent.core :as r] [uix.core :as uix :refer [$ defui]])) @@ -61,25 +63,6 @@ :value selected-org :on-change #(==> [::events/select-org %])}])) -(defui services-selector - [{:keys [value on-change label value-fn] - :or {value-fn identity - label ""}}] - (let [items (use-subscribe [::subs/services]) - options (uix/use-memo (fn [] - (map (fn [x] - {:value (value-fn x) - :label (:label x)}) - items)) - [items value-fn])] - ($ autocomplete2 - {:options options - :multiple true - :label label - :value (to-array value) - :on-change (fn [_e v] - (on-change (:value v)))}))) - (defui service-channel-selector [{:keys [value on-change label value-fn] :or {value-fn identity @@ -174,66 +157,18 @@ ;; Service channel [mui/grid {:item true :xs 12 :lg 4} [mui/stack {:spacing 2} - [mui/typography {:variant "h6"} - (tr :ptv/service-channels)] - - ;; Integration type - [mui/form-control - [mui/form-label (tr :ptv.actions/select-integration)] - [mui/radio-group - {:on-change #(==> [::events/select-service-channel-integration-default %2]) - :value (:service-channel-integration default-settings)} - [mui/form-control-label - {:value "lipas-managed" - :label (tr :ptv.integration.service-channel/lipas-managed) - :control (r/as-element [mui/radio])}] - - [mui/form-control-label - {:value "manual" - :label (tr :ptv.integration/manual) - :control (r/as-element [mui/radio])}]]] - - (when (= "lipas-managed" (:service-channel-integration default-settings)) - [info-text (tr :ptv.integration.service-channel/lipas-managed-helper)]) - - (when (= "manual" (:service-channel-integration default-settings)) - [info-text (tr :ptv.integration.service-channel/manual-helper)])]] + ($ controls/service-channel-integration + {:tr tr + :value (:service-channel-integration default-settings) + :on-change (fn [v] (rf/dispatch [::events/select-service-channel-integration-default v]))})]] ;; Descriptions [mui/grid {:item true :xs 12 :lg 4} [mui/stack {:spacing 2} - [mui/typography {:variant "h6"} - (tr :ptv/descriptions)] - - ;; Integration type - [mui/form-control - [mui/form-label (tr :ptv.actions/select-integration)] - [mui/radio-group - {:on-change #(==> [::events/select-descriptions-integration-default %2]) - :value (:descriptions-integration default-settings)} - [mui/form-control-label - {:value "lipas-managed-ptv-fields" - :label (tr :ptv.integration.description/lipas-managed-ptv-fields) - :control (r/as-element [mui/radio])}] - - [mui/form-control-label - {:value "lipas-managed-comment-field" - :label (tr :ptv.integration.description/lipas-managed-comment-field) - :control (r/as-element [mui/radio])}] - - [mui/form-control-label - {:value "ptv-managed" - :label (tr :ptv.integration.description/ptv-managed) - :control (r/as-element [mui/radio])}]]] - - (when (= "lipas-managed-ptv-fields" (:descriptions-integration default-settings)) - [info-text (tr :ptv.integration.description/lipas-managed-ptv-fields-helper)]) - - (when (= "lipas-managed-comment-field" (:descriptions-integration default-settings)) - [info-text (tr :ptv.integration.description/lipas-managed-comment-field-helper)]) - - (when (= "ptv-managed" (:descriptions-integration default-settings)) - [info-text (tr :ptv.integration.description/ptv-managed-helper)])]]])) + ($ controls/description-integration + {:tr tr + :value (:descriptions-integration default-settings) + :on-change (fn [v] (rf/dispatch [::events/select-descriptions-integration-default v]))})]]])) (defn form [{:keys [tr site]}] @@ -246,34 +181,12 @@ ;; Service [mui/grid {:item true :xs 12 :lg 4} [mui/stack {:spacing 2} - [mui/typography {:variant "h6"} - (tr :ptv/services)] - - ;; Integration type - [mui/form-control - [mui/form-label (tr :ptv.actions/select-integration)] - [mui/radio-group - {:on-change #(==> [::events/select-service-integration site %2]) - :value (:service-integration site)} - [mui/form-control-label - {:value "lipas-managed" - :label (tr :ptv.integration.service/lipas-managed) - :control (r/as-element [mui/radio])}] - - [mui/form-control-label - {:value "manual" - :label (tr :ptv.integration/manual) - :control (r/as-element [mui/radio])}]]] - - (when (= "lipas-managed" (:service-integration site)) - (tr :ptv.integration.service/lipas-managed-helper)) - - (when (= "manual" (:service-integration site)) - ($ services-selector - {:value (:service-ids site) - :on-change #(==> [::events/select-services site %]) - :value-fn :service-id - :label (tr :ptv.actions/select-service)}))]] + ($ controls/service-integration + {:tr tr + :value (:service-integration site) + :on-change (fn [v] (==> [::events/select-service-integration site v])) + :service-ids (:service-ids site) + :set-service-ids (fn [ids] (rf/dispatch [::events/select-services site ids]))})]] ;; Service channels [mui/grid {:item true :xs 12 :lg 4} @@ -313,39 +226,10 @@ [mui/grid {:item true :xs 12 :lg 4} [mui/stack {:spacing 2} - [mui/typography {:variant "h6"} - (tr :ptv/descriptions)] - - ;; Integration type - [mui/form-control - [mui/form-label (tr :ptv.actions/select-integration)] - [mui/radio-group - {:on-change #(==> [::events/select-descriptions-integration site %2]) - :value (:descriptions-integration site)} - - [mui/form-control-label - {:value "lipas-managed-ptv-fields" - :label (tr :ptv.integration.description/lipas-managed-ptv-fields) - :control (r/as-element [mui/radio])}] - - [mui/form-control-label - {:value "lipas-managed-comment-field" - :label (tr :ptv.integration.description/lipas-managed-comment-field) - :control (r/as-element [mui/radio])}] - - [mui/form-control-label - {:value "ptv-managed" - :label (tr :ptv.integration.description/ptv-managed) - :control (r/as-element [mui/radio])}]]] - - (when (= "lipas-managed-ptv-fields" (:descriptions-integration site)) - (tr :ptv.integration.description/lipas-managed-ptv-fields-helper)) - - (when (= "lipas-managed-comment-field" (:descriptions-integration site)) - (tr :ptv.integration.description/lipas-managed-comment-field-helper)) - - (when (= "ptv-managed" (:descriptions-integration site)) - (tr :ptv.integration.description/ptv-managed-helper)) + ($ controls/description-integration + {:tr tr + :value (:descriptions-integration site) + :on-change (fn [v] (rf/dispatch [::events/select-descriptions-integration site v]))}) (when (= "lipas-managed-ptv-fields" (:descriptions-integration site)) [mui/button {:disabled loading? @@ -650,7 +534,9 @@ halt? processed-percent total-count - processed-count]} (<== [::subs/service-descriptions-generation-progress])] + processed-count]} (<== [::subs/service-descriptions-generation-progress]) + + services @(rf/subscribe [::subs/services])] [lui/expansion-panel {:label (str "1. " (tr :ptv.tools.generate-services/headline)) @@ -752,8 +638,9 @@ :label-fn :label :on-change #(==> [::events/set-service-candidate-languages source-id %])}] - ($ services-selector - {:value (get m :service-ids) + ($ controls/services-selector + {:options services + :value (get m :service-ids) :on-change #(==> [::events/link-candidate-to-existing-service source-id %]) :value-fn :service-id :label (tr :ptv/service)}) @@ -788,84 +675,86 @@ (defui service-location-details [{:keys [tr site lipas-id sync-enabled name-conflict service-ids selected-tab set-selected-tab service-channel-ids]}] - ($ AccordionDetails - {} - (r/as-element - [mui/stack {:spacing 2} + (let [services (use-subscribe [::subs/services])] + ($ AccordionDetails + {} + (r/as-element + [mui/stack {:spacing 2} + + [lui/switch + {:label (tr :ptv.actions/export-disclaimer) + :value sync-enabled + :on-change #(==> [::events/toggle-sync-enabled site %])}] + + ;; Services selector + ($ controls/services-selector + {:options services + :value service-ids + :value-fn :service-id + :on-change #(==> [::events/select-services site %]) + :label (tr :ptv/services)}) + + ;; Service channel selector + + [:span (when name-conflict {:style + {:border "1px solid rgb(237, 108, 2)" + :padding "1em"}}) + + (when name-conflict + [mui/stack + [lui/icon-text + {:icon "warning" + :icon-color "warning" + :text (tr :ptv.wizard/service-channel-name-conflict (:name site))}] + + [mui/typography + {:style {:padding-left "1em" :margin-bottom "0"} + :variant "body2"} + (tr :ptv.name-conflict/do-one-of-these)] + + [:ul + [:li (tr :ptv.name-conflict/opt1)] + [:li (tr :ptv.name-conflict/opt2)] + [:li (tr :ptv.name-conflict/opt3)] + #_[:li (tr :ptv.name-conflict/opt4)]]]) + + (when name-conflict + [mui/button + {:on-click #(==> [::events/select-service-channels {:lipas-id lipas-id} + [(:service-channel-id name-conflict)]])} + (tr :ptv.wizard/attach-to-conflicting-service-channel)]) + + ($ service-channel-selector + {:value service-channel-ids + :value-fn :service-channel-id + :on-change #(==> [::events/select-service-channels site %]) + :label (tr :ptv/service-channel)})] + + [mui/tabs + {:value selected-tab + :on-change #(set-selected-tab (keyword %2))} + [mui/tab {:value "fi" :label "FI"}] + [mui/tab {:value "se" :label "SE"}] + [mui/tab {:value "en" :label "EN"}]] - [lui/switch - {:label (tr :ptv.actions/export-disclaimer) - :value sync-enabled - :on-change #(==> [::events/toggle-sync-enabled site %])}] - - ;; Services selector - ($ services-selector - {:value service-ids - :value-fn :service-id - :on-change #(==> [::events/select-services site %]) - :label (tr :ptv/services)}) - - ;; Service channel selector - - [:span (when name-conflict {:style - {:border "1px solid rgb(237, 108, 2)" - :padding "1em"}}) - - (when name-conflict - [mui/stack - [lui/icon-text - {:icon "warning" - :icon-color "warning" - :text (tr :ptv.wizard/service-channel-name-conflict (:name site))}] - - [mui/typography - {:style {:padding-left "1em" :margin-bottom "0"} - :variant "body2"} - (tr :ptv.name-conflict/do-one-of-these)] - - [:ul - [:li (tr :ptv.name-conflict/opt1)] - [:li (tr :ptv.name-conflict/opt2)] - [:li (tr :ptv.name-conflict/opt3)] - #_[:li (tr :ptv.name-conflict/opt4)]]]) - - (when name-conflict - [mui/button - {:on-click #(==> [::events/select-service-channels {:lipas-id lipas-id} - [(:service-channel-id name-conflict)]])} - (tr :ptv.wizard/attach-to-conflicting-service-channel)]) - - ($ service-channel-selector - {:value service-channel-ids - :value-fn :service-channel-id - :on-change #(==> [::events/select-service-channels site %]) - :label (tr :ptv/service-channel)})] - - [mui/tabs - {:value selected-tab - :on-change #(set-selected-tab (keyword %2))} - [mui/tab {:value "fi" :label "FI"}] - [mui/tab {:value "se" :label "SE"}] - [mui/tab {:value "en" :label "EN"}]] - - ;; Summary - [lui/text-field - {:multiline true - :read-only? (not= "manual" (:descriptions-integration site)) - :variant "outlined" - :on-change #(==> [::events/set-summary site selected-tab %]) - :label (tr :ptv/summary) - :value (get-in site [:summary selected-tab])}] - - ;; Description - [lui/text-field - {:variant "outlined" - :read-only? (not= "manual" (:descriptions-integration site)) - :rows 5 - :multiline true - :on-change #(==> [::events/set-description site selected-tab %]) - :label (tr :ptv/description) - :value (get-in site [:description selected-tab])}]]))) + ;; Summary + [lui/text-field + {:multiline true + :read-only? (not= "manual" (:descriptions-integration site)) + :variant "outlined" + :on-change #(==> [::events/set-summary site selected-tab %]) + :label (tr :ptv/summary) + :value (get-in site [:summary selected-tab])}] + + ;; Description + [lui/text-field + {:variant "outlined" + :read-only? (not= "manual" (:descriptions-integration site)) + :rows 5 + :multiline true + :on-change #(==> [::events/set-description site selected-tab %]) + :label (tr :ptv/description) + :value (get-in site [:description selected-tab])}]])))) (defui service-location [{:keys [site sync-enabled name-conflict valid] From 7f561e59d3d76d41a775cf4e3bf10669bd682b26 Mon Sep 17 00:00:00 2001 From: Juho Teperi Date: Tue, 12 Nov 2024 11:36:03 +0200 Subject: [PATCH 46/68] Working ptv tab read-only toggle etc --- webapp/src/clj/lipas/backend/ptv/core.clj | 6 ++-- webapp/src/clj/lipas/backend/ptv/handler.clj | 33 +++++++++----------- webapp/src/cljs/lipas/ui/ptv/site_view.cljs | 15 +++++---- webapp/src/cljs/lipas/ui/ptv/views.cljs | 8 ++--- 4 files changed, 30 insertions(+), 32 deletions(-) diff --git a/webapp/src/clj/lipas/backend/ptv/core.clj b/webapp/src/clj/lipas/backend/ptv/core.clj index dd5a6f72f..3e5eb1455 100644 --- a/webapp/src/clj/lipas/backend/ptv/core.clj +++ b/webapp/src/clj/lipas/backend/ptv/core.clj @@ -17,9 +17,11 @@ (defn generate-ptv-descriptions [{:keys [client indices] :as _search} - {:keys [lipas-id]}] + lipas-id] (let [idx (get-in indices [:sports-site :search]) - doc (-> (search/fetch-document client idx lipas-id) :body :_source)] + doc (-> (search/fetch-document client idx lipas-id) + :body + :_source)] (-> (ai/generate-ptv-descriptions doc) :message :content))) diff --git a/webapp/src/clj/lipas/backend/ptv/handler.clj b/webapp/src/clj/lipas/backend/ptv/handler.clj index 9833df6fc..cf14c25a8 100644 --- a/webapp/src/clj/lipas/backend/ptv/handler.clj +++ b/webapp/src/clj/lipas/backend/ptv/handler.clj @@ -32,12 +32,12 @@ (defn routes [{:keys [db search] :as _ctx}] ["" {:coercion reitit.coercion.malli/coercion - :tags ["ptv"]} + :tags ["ptv"] + :no-doc false} ["/actions/get-ptv-integration-candidates" {:post - {:no-doc false - :require-privilege :ptv/manage + {:require-privilege :ptv/manage :handler (fn [{:keys [body-params]}] {:status 200 @@ -45,18 +45,19 @@ ["/actions/generate-ptv-descriptions" {:post - {:no-doc false - :require-privilege :ptv/manage - :parameters {:body [:any]} + {:require-privilege :ptv/manage + :parameters {:body [:map + [:lipas-id :string]]} :handler - (fn [{:keys [body-params]}] + (fn [req] {:status 200 - :body (ptv-core/generate-ptv-descriptions search body-params)})}}] + :body (ptv-core/generate-ptv-descriptions + search + (-> req :parameters :body :lipas-id))})}}] ["/actions/generate-ptv-service-descriptions" {:post - {:no-doc false - :require-privilege :ptv/manage + {:require-privilege :ptv/manage :parameters {:body [:any]} :handler (fn [{:keys [body-params]}] @@ -65,8 +66,7 @@ ["/actions/save-ptv-service" {:post - {:no-doc false - :require-privilege :ptv/manage + {:require-privilege :ptv/manage :parameters {:body [:any]} :handler (fn [{:keys [body-params]}] @@ -75,8 +75,7 @@ ["/actions/fetch-ptv-services" {:post - {:no-doc false - :require-privilege :ptv/manage + {:require-privilege :ptv/manage :parameters {:body [:any]} :handler (fn [{:keys [body-params]}] @@ -85,8 +84,7 @@ ["/actions/save-ptv-service-location" {:post - {:no-doc false - :require-privilege :ptv/manage + {:require-privilege :ptv/manage :parameters {:body create-ptv-service-location} :handler (fn [{:keys [body-params identity]}] @@ -95,8 +93,7 @@ ["/actions/save-ptv-meta" {:post - {:no-doc false - :require-privilege :ptv/manage + {:require-privilege :ptv/manage :parameters {:body [:any]} :handler (fn [{:keys [body-params identity]}] diff --git a/webapp/src/cljs/lipas/ui/ptv/site_view.cljs b/webapp/src/cljs/lipas/ui/ptv/site_view.cljs index 12606167b..1681bbe0a 100644 --- a/webapp/src/cljs/lipas/ui/ptv/site_view.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/site_view.cljs @@ -22,10 +22,9 @@ site (use-subscribe [:lipas.ui.sports-sites.subs/latest-rev lipas-id]) ;; default-settings {} enabled (boolean (:ptv site)) + descriptions-enabled (not= "manual" (:descriptions-integration (:ptv site))) loading? false] - (js/console.log site) - (js/console.log edit-data) ($ Stack {:direction "column" :sx #js {:gap 2}} @@ -70,10 +69,10 @@ ;; Summary (r/as-element [lui/text-field - {:disabled loading? - :multiline true - :read-only? (or (not= "manual" (:descriptions-integration site)) + {:disabled (or loading? + (not descriptions-enabled) read-only?) + :multiline true :variant "outlined" :on-change (fn [v] (rf/dispatch [:lipas.ui.sports-sites.events/edit-field lipas-id [:ptv :summary selected-tab] v])) @@ -84,10 +83,10 @@ ;; Description (r/as-element [lui/text-field - {:disabled loading? - :variant "outlined" - :read-only? (or (not= "manual" (:descriptions-integration site)) + {:disabled (or loading? + (not descriptions-enabled) read-only?) + :variant "outlined" :rows 5 :multiline true :on-change (fn [v] diff --git a/webapp/src/cljs/lipas/ui/ptv/views.cljs b/webapp/src/cljs/lipas/ui/ptv/views.cljs index 375392a09..503d9c521 100644 --- a/webapp/src/cljs/lipas/ui/ptv/views.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/views.cljs @@ -248,9 +248,9 @@ ;; Summary [lui/text-field - {:disabled loading? + {:disabled (or loading? + (not= "manual" (:descriptions-integration site))) :multiline true - :read-only? (not= "manual" (:descriptions-integration site)) :variant "outlined" :on-change #(==> [::events/set-summary site @selected-tab %]) :label "Tiivistelmä" @@ -258,9 +258,9 @@ ;; Description [lui/text-field - {:disabled loading? + {:disabled (or loading? + (not= "manual" (:descriptions-integration site))) :variant "outlined" - :read-only? (not= "manual" (:descriptions-integration site)) :rows 5 :multiline true :on-change #(==> [::events/set-description site @selected-tab %]) From e78f771446142668b7abfdaab37295ed8d820494 Mon Sep 17 00:00:00 2001 From: Juho Teperi Date: Tue, 12 Nov 2024 11:58:06 +0200 Subject: [PATCH 47/68] Move test utils --- webapp/src/cljs/lipas/ui/ptv/site_view.cljs | 2 +- .../test/clj/lipas/backend/handler_test.clj | 275 ++++-------------- webapp/test/clj/lipas/test_utils.clj | 167 ++++++++++- 3 files changed, 228 insertions(+), 216 deletions(-) diff --git a/webapp/src/cljs/lipas/ui/ptv/site_view.cljs b/webapp/src/cljs/lipas/ui/ptv/site_view.cljs index 1681bbe0a..6e61ec4a4 100644 --- a/webapp/src/cljs/lipas/ui/ptv/site_view.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/site_view.cljs @@ -16,7 +16,7 @@ (defui site-view [{:keys [tr lipas-id can-edit? edit-data]}] (let [[selected-tab set-selected-tab] (uix/use-state :fi) - editing* (use-subscribe [:lipas.ui.sports-sites.subs/editing? lipas-id]) + editing* (boolean (use-subscribe [:lipas.ui.sports-sites.subs/editing? lipas-id])) editing? (and can-edit? editing*) read-only? (not editing?) site (use-subscribe [:lipas.ui.sports-sites.subs/latest-rev lipas-id]) diff --git a/webapp/test/clj/lipas/backend/handler_test.clj b/webapp/test/clj/lipas/backend/handler_test.clj index 14a64e204..3b6024bb0 100644 --- a/webapp/test/clj/lipas/backend/handler_test.clj +++ b/webapp/test/clj/lipas/backend/handler_test.clj @@ -1,176 +1,27 @@ (ns lipas.backend.handler-test - (:require [cheshire.core :as j] - [clojure.java.jdbc :as jdbc] - [clojure.spec.alpha :as s] + (:require [clojure.spec.alpha :as s] [clojure.spec.gen.alpha :as gen] - [clojure.string :as str] [clojure.test :refer [deftest is use-fixtures] :as t] - [cognitect.transit :as transit] [dk.ative.docjure.spreadsheet :as excel] - [lipas.backend.analysis.diversity :as diversity] - [lipas.backend.config :as config] [lipas.backend.core :as core] - [lipas.backend.email :as email] [lipas.backend.jwt :as jwt] - [lipas.backend.search :as search] - [lipas.backend.system :as system] [lipas.data.loi :as loi] [lipas.schema.core] [lipas.seed :as seed] - [lipas.test-utils :as tu] + [lipas.test-utils :refer [->transit <-transit <-json ->json app search db] :as tu] [lipas.utils :as utils] - [migratus.core :as migratus] - [ring.mock.request :as mock]) - (:import [java.io ByteArrayOutputStream] - java.util.Base64)) - -;;; Setup ;;; - -(def <-json #(j/parse-string (slurp %) true)) -(def ->json j/generate-string) - -(defn ->transit [x] - (let [out (ByteArrayOutputStream. 4096) - writer (transit/writer out :json)] - (transit/write writer x) - (.toString out))) - -(defn <-transit [in] - (let [reader (transit/reader in :json)] - (transit/read reader))) - -(defn ->base64 - "Encodes a string as base64." - [s] - (.encodeToString (Base64/getEncoder) (.getBytes s))) - -(defn auth-header - "Adds Authorization header to the request - with base64 encoded \"Basic user:pass\" value." - [req user passwd] - (mock/header req "Authorization" (str "Basic " (->base64 (str user ":" passwd))))) - -(defn token-header - [req token] - (mock/header req "Authorization" (str "Token " token))) - -(defn- test-suffix [s] (str s "_test")) - -(def config (-> config/default-config - (select-keys [:db :app :search :mailchimp :aws]) - (assoc-in [:app :emailer] (email/->TestEmailer)) - (update-in [:db :dbname] test-suffix) - (assoc-in [:db :dev] true) ;; No connection pool - (update-in [:search :indices :sports-site :search] test-suffix) - (update-in [:search :indices :sports-site :analytics] test-suffix) - (update-in [:search :indices :report :subsidies] test-suffix) - (update-in [:search :indices :report :city-stats] test-suffix) - (update-in [:search :indices :analysis :schools] test-suffix) - (update-in [:search :indices :analysis :population] test-suffix) - (update-in [:search :indices :analysis :population-high-def] test-suffix) - (update-in [:search :indices :analysis :diversity] test-suffix) - (update-in [:search :indices :lois :search] test-suffix))) - -(defn init-db! [] - (let [migratus-opts {:store :database - :migration-dir "migrations" - :db (:db config)}] - (try - (jdbc/db-do-commands (-> config :db (assoc :dbname "")) - false - [(str "CREATE DATABASE " (-> config :db :dbname))]) - (catch Exception e - (when-not (= "ERROR: database \"lipas_test\" already exists" - (-> e .getCause .getMessage)) - (throw e)))) - - (jdbc/db-do-commands (:db config) - false - [(str "CREATE EXTENSION IF NOT EXISTS postgis") - (str "CREATE EXTENSION IF NOT EXISTS postgis_topology") - (str "CREATE EXTENSION IF NOT EXISTS citext") - (str "CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\"")]) - - (migratus/init migratus-opts) - (migratus/migrate migratus-opts))) - -(def tables - ["account" - "analysis_queue" - "city" - "elevation_queue" - "email_out_queue" - "integration_log" - "integration_out_queue" - "reminder" - "sports_site" - "subsidy"]) - -(defn prune-db! [] - (jdbc/execute! (:db config) [(str "TRUNCATE " - (str/join "," tables) - " RESTART IDENTITY CASCADE")])) - -(println "Starting test-system!") -(def system (system/start-system! (config/->system-config config))) - -(def db (:lipas/db system)) -(def app (:lipas/app system)) -(def search (:lipas/search system)) - -(defn prune-es! [] - (let [client (:client search) - mappings {(-> search :indices :sports-site :search) (:sports-sites search/mappings) - (-> search :indices :analysis :diversity) diversity/mappings - (-> search :indices :lois :search) (:lois search/mappings)}] - - (doseq [idx-name (-> search :indices vals (->> (mapcat vals)))] - (try - (search/delete-index! client idx-name) - (catch Exception ex - (when (not= "index_not_found_exception" - (-> ex ex-data :body :error :root_cause first :type)) - (throw ex)))) - (when-let [mapping (mappings idx-name)] - (search/create-index! client idx-name mapping))))) - -(comment - (init-db!) - (prune-es!) - (prune-db!) - (ex-data *e) - ) - -(defn gen-user - ([] - (gen-user {:db? false :admin? false :status "active"})) - ([{:keys [db? admin? status] - :or {admin? false status "active"}}] - (let [user (-> (gen/generate (s/gen :lipas/user)) - (assoc :password (str (gensym)) :status status) - ;; Ensure :permissions is a map always, generate doesn't always add the key because it it is optional in - ;; the :lipas/user spec but required e.g. update-user-permissions endpoint. - (update :permissions (fn [permissions] - (cond-> (or permissions {}) - ;; generated result might include admin role, remove if the flag is false - (not admin?) (update :roles (fn [roles] - (into [] (remove (fn [x] (= :admin (:role x))) roles)))) - admin? (update :roles (fnil conj []) {:role :admin})))))] - (if db? - (do - (core/add-user! db user) - (assoc user :id (:id (core/get-user db (:email user))))) - user)))) - -(defn gen-loi! [] - (-> (gen/generate (s/gen :lipas.loi/document)) - (assoc :status "active") - (assoc :id (str (java.util.UUID/randomUUID))))) + [ring.mock.request :as mock])) ;;; Fixtures ;;; -(use-fixtures :once (fn [f] (init-db!) (f))) -(use-fixtures :each (fn [f] (prune-db!) (prune-es!) (f))) +(use-fixtures :once (fn [f] + (tu/init-db!) + (f))) + +(use-fixtures :each (fn [f] + (tu/prune-db!) + (tu/prune-es!) + (f))) ;;; The tests ;;; @@ -179,7 +30,7 @@ (deftest search-loi-by-type (let [loi-type "fishing-pier" loi-category "outdoor-recreation-facilities" - loi (-> (gen-loi!) + loi (-> (tu/gen-loi!) (assoc :loi-type loi-type) (assoc :loi-category loi-category)) _ (core/index-loi! search loi :sync) @@ -199,7 +50,7 @@ (deftest search-loi-by-category (let [loi-category "outdoor-recreation-facilities" - loi (-> (gen-loi!) + loi (-> (tu/gen-loi!) (assoc :loi-category loi-category)) _ (core/index-loi! search loi :sync) resp (app (-> (mock/request :get (str "/api/lois/category/" loi-category)) @@ -208,7 +59,7 @@ (is (= loi-category (:loi-category response-loi))))) (deftest get-loi-by-id - (let [{:keys [id] :as loi} (gen-loi!) + (let [{:keys [id] :as loi} (tu/gen-loi!) _ (core/index-loi! search loi :sync) resp (app (-> (mock/request :get (str "/api/lois/" id)) (mock/content-type "application/json"))) @@ -217,7 +68,7 @@ (deftest search-loi-by-invalid-category (let [loi-category "kekkonen-666-category" - loi (-> (gen-loi!) + loi (-> (tu/gen-loi!) (assoc :loi-category loi-category)) _ (core/index-loi! search loi :sync) response (app (-> (mock/request :get (str "/api/lois/category/" loi-category)) @@ -321,14 +172,14 @@ ) (deftest register-user-test - (let [user (gen-user) + (let [user (tu/gen-user) resp (app (-> (mock/request :post "/api/actions/register") (mock/content-type "application/json") (mock/body (->json user))))] (is (= 201 (:status resp))))) (deftest register-user-conflict-test - (let [user (gen-user {:db? true}) + (let [user (tu/gen-user {:db? true}) resp (app (-> (mock/request :post "/api/actions/register") (mock/content-type "application/json") (mock/body (->json user)))) @@ -339,25 +190,25 @@ (deftest login-failure-test (let [resp (app (-> (mock/request :post "/api/actions/login") (mock/content-type "application/json") - (auth-header "this" "fails")))] + (tu/auth-header "this" "fails")))] (is (= (:status resp) 401)))) (deftest login-test - (let [user (gen-user {:db? true}) + (let [user (tu/gen-user {:db? true}) resp (app (-> (mock/request :post "/api/actions/login") (mock/content-type "application/json") - (auth-header (:username user) (:password user)))) + (tu/auth-header (:username user) (:password user)))) body (<-json (:body resp))] (is (= 200 (:status resp))) (is (= (:email user) (:email body))))) (deftest refresh-login-test - (let [user (gen-user {:db? true}) + (let [user (tu/gen-user {:db? true}) token1 (jwt/create-token user :terse? true) _ (Thread/sleep 1000) ; to see effect between timestamps resp (app (-> (mock/request :get "/api/actions/refresh-login") (mock/content-type "application/json") - (token-header token1))) + (tu/token-header token1))) body (<-json (:body resp)) token2 (:token body) @@ -369,7 +220,7 @@ ;; TODO how to test side-effects? (sending email) (deftest request-password-reset-test - (let [user (gen-user {:db? true}) + (let [user (tu/gen-user {:db? true}) resp (app (-> (mock/request :post "/api/actions/request-password-reset") (mock/content-type "application/json") (mock/body (->json (select-keys user [:email])))))] @@ -384,27 +235,27 @@ (is (= "email-not-found" (:type body))))) (deftest reset-password-test - (let [user (gen-user {:db? true}) + (let [user (tu/gen-user {:db? true}) token (jwt/create-token user :terse? true) resp (app (-> (mock/request :post "/api/actions/reset-password") (mock/content-type "application/json") (mock/body (->json {:password "blablaba"})) - (token-header token)))] + (tu/token-header token)))] (is (= 200 (:status resp))))) (deftest reset-password-expired-token-test - (let [user (gen-user {:db? true}) + (let [user (tu/gen-user {:db? true}) token (jwt/create-token user :terse? true :valid-seconds 0) _ (Thread/sleep 100) ; make sure token expires resp (app (-> (mock/request :post "/api/actions/reset-password") (mock/content-type "application/json") (mock/body (->json {:password "blablaba"})) - (token-header token)))] + (tu/token-header token)))] (is (= 401 (:status resp))))) (deftest send-magic-link-requires-admin-test - (let [admin (gen-user {:db? true :admin? false}) - user (-> (gen-user {:db? false}) + (let [admin (tu/gen-user {:db? true :admin? false}) + user (-> (tu/gen-user {:db? false}) (dissoc :password :id)) token (jwt/create-token admin) resp (app (-> (mock/request :post "/api/actions/send-magic-link") @@ -412,15 +263,15 @@ (mock/body (->json {:user user :login-url "https://localhost" :variant "lipas"})) - (token-header token)))] + (tu/token-header token)))] (is (= 403 (:status resp))))) (deftest update-user-permissions-test ;; Updating permissions has side-effect of publshing drafts the user ;; has done earlier to sites where permissions are now being ;; granted - (let [admin (gen-user {:db? true :admin? true}) - user (gen-user {:db? true}) + (let [admin (tu/gen-user {:db? true :admin? true}) + user (tu/gen-user {:db? true}) ;; Add 'draft' which is expected to get publshed as side-effect event-date (utils/timestamp) @@ -438,7 +289,7 @@ (mock/body (->json {:id (:id user) :permissions perms :login-url "https://localhost"})) - (token-header token))) + (tu/token-header token))) site-log (->> (core/get-sports-site-history db 123) (utils/index-by :event-date))] @@ -449,7 +300,7 @@ (is (= "active" (:status (get site-log event-date)))))) (deftest update-user-permissions-requires-admin-test - (let [user (gen-user {:db? true :admin? false}) + (let [user (tu/gen-user {:db? true :admin? false}) token (jwt/create-token user) resp (app (-> (mock/request :post "/api/actions/update-user-permissions") (mock/content-type "application/json") @@ -457,46 +308,46 @@ (select-keys [:id :permissions]) (assoc :login-url "https://localhost") ->json)) - (token-header token)))] + (tu/token-header token)))] (is (= 403 (:status resp))))) (deftest update-user-data-test - (let [user (gen-user {:db? true}) + (let [user (tu/gen-user {:db? true}) token (jwt/create-token user :terse? true) user-data (gen/generate (s/gen :lipas.user/user-data)) resp (app (-> (mock/request :post "/api/actions/update-user-data") (mock/content-type "application/json") (mock/body (->json user-data)) - (token-header token))) + (tu/token-header token))) user-data2 (-> resp :body <-json)] (is (= 200 (:status resp))) (is (= user-data user-data2)))) (deftest update-user-status-test - (let [admin (gen-user {:db? true :admin? true}) - user (gen-user {:db? true :status "active"}) + (let [admin (tu/gen-user {:db? true :admin? true}) + user (tu/gen-user {:db? true :status "active"}) token (jwt/create-token admin) resp (app (-> (mock/request :post "/api/actions/update-user-status") (mock/content-type "application/json") (mock/body (->json {:id (:id user) :status "archived"})) - (token-header token))) + (tu/token-header token))) user2 (-> resp :body <-json)] (is (= 200 (:status resp))) (is (= "archived" (:status user2))))) (deftest update-user-status-requires-admin-test - (let [admin (gen-user {:db? true :admin? false}) - user (gen-user {:db? true :status "active"}) + (let [admin (tu/gen-user {:db? true :admin? false}) + user (tu/gen-user {:db? true :status "active"}) token (jwt/create-token admin) resp (app (-> (mock/request :post "/api/actions/update-user-status") (mock/content-type "application/json") (mock/body (->json {:id (:id user) :status "archived"})) - (token-header token)))] + (tu/token-header token)))] (is (= 403 (:status resp))))) (deftest send-magic-link-test - (let [admin (gen-user {:db? true :admin? true}) - user (-> (gen-user {:db? false}) + (let [admin (tu/gen-user {:db? true :admin? true}) + user (-> (tu/gen-user {:db? false}) (dissoc :password :id)) token (jwt/create-token admin) resp (app (-> (mock/request :post "/api/actions/send-magic-link") @@ -504,11 +355,11 @@ (mock/body (->json {:user user :login-url "https://localhost" :variant "lipas"})) - (token-header token)))] + (tu/token-header token)))] (is (= 200 (:status resp))))) (deftest order-magic-link-test - (let [user (gen-user {:db? true}) + (let [user (tu/gen-user {:db? true}) resp (app (-> (mock/request :post "/api/actions/order-magic-link") (mock/content-type "application/json") (mock/body (->json {:email (:email user) @@ -525,7 +376,7 @@ (is (= 400 (:status resp))))) (deftest upsert-sports-site-draft-test - (let [user (gen-user {:db? true}) + (let [user (tu/gen-user {:db? true}) token (jwt/create-token user) site (-> (tu/gen-sports-site) (assoc :status "active") @@ -533,11 +384,11 @@ resp (app (-> (mock/request :post "/api/sports-sites?draft=true") (mock/content-type "application/json") (mock/body (->json site)) - (token-header token)))] + (tu/token-header token)))] (is (= 201 (:status resp))))) (deftest upsert-invalid-sports-site-test - (let [user (gen-user {:db? true}) + (let [user (tu/gen-user {:db? true}) token (jwt/create-token user) site (-> (tu/gen-sports-site) (assoc :status "kebab") @@ -545,11 +396,11 @@ resp (app (-> (mock/request :post "/api/sports-sites?draft=true") (mock/content-type "application/json") (mock/body (->json site)) - (token-header token)))] + (tu/token-header token)))] (is (= 400 (:status resp))))) (deftest upsert-sports-site-no-permissions-test - (let [user (gen-user) + (let [user (tu/gen-user) _ (as-> user $ (dissoc $ :permissions) (core/add-user! db $)) @@ -560,11 +411,11 @@ resp (app (-> (mock/request :post "/api/sports-sites") (mock/content-type "application/json") (mock/body (->json site)) - (token-header token)))] + (tu/token-header token)))] (is (= 403 (:status resp))))) (deftest get-sports-sites-by-type-code-test - (let [user (gen-user {:db? true :admin? true}) + (let [user (tu/gen-user {:db? true :admin? true}) site (-> (tu/gen-sports-site) (assoc-in [:type :type-code] 3110) (assoc :status "active")) @@ -576,7 +427,7 @@ (is (s/valid? :lipas/sports-sites body)))) (deftest get-sports-sites-by-type-code-localized-test - (let [user (gen-user {:db? true :admin? true}) + (let [user (tu/gen-user {:db? true :admin? true}) site (-> (tu/gen-sports-site) (assoc-in [:type :type-code] 3110) (assoc-in [:admin] "state") @@ -593,7 +444,7 @@ :admin))))) (deftest get-sports-site-test - (let [user (gen-user {:db? true :admin? true}) + (let [user (tu/gen-user {:db? true :admin? true}) rev1 (-> (tu/gen-sports-site) (assoc :status "active")) _ (core/upsert-sports-site!* db user rev1) @@ -611,7 +462,7 @@ (is (= 404 (:status resp))))) (deftest get-sports-site-history-test - (let [user (gen-user {:db? true :admin? true}) + (let [user (tu/gen-user {:db? true :admin? true}) rev1 (-> (tu/gen-sports-site) (assoc :status "active")) rev2 (-> rev1 @@ -684,7 +535,7 @@ (deftest calculate-stats-test (let [_ (seed/seed-city-data! db search) - user (gen-user {:db? true :admin? true}) + user (tu/gen-user {:db? true :admin? true}) site (-> (tu/gen-sports-site) (assoc :status "active") (assoc-in [:location :city :city-code] 275) @@ -707,30 +558,30 @@ (is (= 200 (:status resp))))) (deftest add-reminder-test - (let [user (gen-user {:db? true}) + (let [user (tu/gen-user {:db? true}) token (jwt/create-token user :terse? true) reminder (gen/generate (s/gen :lipas/new-reminder)) resp (app (-> (mock/request :post "/api/actions/add-reminder") (mock/content-type "application/json") (mock/body (->json reminder)) - (token-header token))) + (tu/token-header token))) body (-> resp :body <-json)] (is (= 200 (:status resp))) (is (= "pending" (:status body))))) (deftest update-reminder-status-test - (let [user (gen-user {:db? true}) + (let [user (tu/gen-user {:db? true}) token (jwt/create-token user :terse? true) reminder (gen/generate (s/gen :lipas/new-reminder)) resp1 (app (-> (mock/request :post "/api/actions/add-reminder") (mock/content-type "application/json") (mock/body (->json reminder)) - (token-header token))) + (tu/token-header token))) id (-> resp1 :body <-json :id) resp2 (app (-> (mock/request :post "/api/actions/update-reminder-status") (mock/content-type "application/json") (mock/body (->json {:id id :status "canceled"})) - (token-header token)))] + (tu/token-header token)))] (is (= 200 (:status resp1))) (is (= 200 (:status resp2))))) diff --git a/webapp/test/clj/lipas/test_utils.clj b/webapp/test/clj/lipas/test_utils.clj index 29cf6aa1e..f42f89087 100644 --- a/webapp/test/clj/lipas/test_utils.clj +++ b/webapp/test/clj/lipas/test_utils.clj @@ -1,10 +1,171 @@ (ns lipas.test-utils - (:require - [clojure.spec.alpha :as s] - [clojure.spec.gen.alpha :as gen])) + (:require [cheshire.core :as j] + [clojure.java.jdbc :as jdbc] + [clojure.spec.alpha :as s] + [clojure.spec.gen.alpha :as gen] + [clojure.string :as str] + [cognitect.transit :as transit] + [lipas.backend.analysis.diversity :as diversity] + [lipas.backend.config :as config] + [lipas.backend.core :as core] + [lipas.backend.email :as email] + [lipas.backend.search :as search] + [lipas.backend.system :as sy] + [lipas.schema.core] + [migratus.core :as migratus] + [ring.mock.request :as mock]) + (:import [java.io ByteArrayOutputStream] + java.util.Base64)) (defn gen-sports-site [] (try (gen/generate (s/gen :lipas/sports-site)) (catch Throwable _t (gen-sports-site)))) + +(def <-json #(j/parse-string (slurp %) true)) +(def ->json j/generate-string) + +(defn ->transit [x] + (let [out (ByteArrayOutputStream. 4096) + writer (transit/writer out :json)] + (transit/write writer x) + (.toString out))) + +(defn <-transit [in] + (let [reader (transit/reader in :json)] + (transit/read reader))) + +(defn ->base64 + "Encodes a string as base64." + [s] + (.encodeToString (Base64/getEncoder) (.getBytes s))) + +(defn auth-header + "Adds Authorization header to the request + with base64 encoded \"Basic user:pass\" value." + [req user passwd] + (mock/header req "Authorization" (str "Basic " (->base64 (str user ":" passwd))))) + +(defn token-header + [req token] + (mock/header req "Authorization" (str "Token " token))) + +(defn- test-suffix [s] (str s "_test")) + +(def config (-> config/default-config + (select-keys [:db :app :search :mailchimp :aws]) + (assoc-in [:app :emailer] (email/->TestEmailer)) + (update-in [:db :dbname] test-suffix) + (assoc-in [:db :dev] true) ;; No connection pool + (update-in [:search :indices :sports-site :search] test-suffix) + (update-in [:search :indices :sports-site :analytics] test-suffix) + (update-in [:search :indices :report :subsidies] test-suffix) + (update-in [:search :indices :report :city-stats] test-suffix) + (update-in [:search :indices :analysis :schools] test-suffix) + (update-in [:search :indices :analysis :population] test-suffix) + (update-in [:search :indices :analysis :population-high-def] test-suffix) + (update-in [:search :indices :analysis :diversity] test-suffix) + (update-in [:search :indices :lois :search] test-suffix))) + +(defn init-db! [] + (let [migratus-opts {:store :database + :migration-dir "migrations" + :db (:db config)}] + (try + (jdbc/db-do-commands (-> config :db (assoc :dbname "")) + false + [(str "CREATE DATABASE " (-> config :db :dbname))]) + (catch Exception e + (when-not (= "ERROR: database \"lipas_test\" already exists" + (-> e .getCause .getMessage)) + (throw e)))) + + (jdbc/db-do-commands (:db config) + false + [(str "CREATE EXTENSION IF NOT EXISTS postgis") + (str "CREATE EXTENSION IF NOT EXISTS postgis_topology") + (str "CREATE EXTENSION IF NOT EXISTS citext") + (str "CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\"")]) + + (migratus/init migratus-opts) + (migratus/migrate migratus-opts))) + +(def tables + ["account" + "analysis_queue" + "city" + "elevation_queue" + "email_out_queue" + "integration_log" + "integration_out_queue" + "reminder" + "sports_site" + "subsidy"]) + +(defn prune-db! [] + (jdbc/execute! (:db config) [(str "TRUNCATE " + (str/join "," tables) + " RESTART IDENTITY CASCADE")])) + +;; Likely all test system components are stateless, so maybe ok to start without ever halting this. +;; But take steps to also stop the system before starting it again on each reload of this ns. +(defonce system nil) + +(alter-var-root #'system (fn [x] + (when x + (sy/stop-system! x)) + (sy/start-system! (config/->system-config config)))) + +;; These need to be redefined after each alter-var-root. +(def db (:lipas/db system)) +(def app (:lipas/app system)) +(def search (:lipas/search system)) + +(defn prune-es! [] + (let [client (:client search) + mappings {(-> search :indices :sports-site :search) (:sports-sites search/mappings) + (-> search :indices :analysis :diversity) diversity/mappings + (-> search :indices :lois :search) (:lois search/mappings)}] + + (doseq [idx-name (-> search :indices vals (->> (mapcat vals)))] + (try + (search/delete-index! client idx-name) + (catch Exception ex + (when (not= "index_not_found_exception" + (-> ex ex-data :body :error :root_cause first :type)) + (throw ex)))) + (when-let [mapping (mappings idx-name)] + (search/create-index! client idx-name mapping))))) + +(comment + (init-db!) + (prune-es!) + (prune-db!) + (ex-data *e)) + +(defn gen-user + ([] + (gen-user {:db? false :admin? false :status "active"})) + ([{:keys [db? admin? status] + :or {admin? false status "active"}}] + (let [user (-> (gen/generate (s/gen :lipas/user)) + (assoc :password (str (gensym)) :status status) + ;; Ensure :permissions is a map always, generate doesn't always add the key because it it is optional in + ;; the :lipas/user spec but required e.g. update-user-permissions endpoint. + (update :permissions (fn [permissions] + (cond-> (or permissions {}) + ;; generated result might include admin role, remove if the flag is false + (not admin?) (update :roles (fn [roles] + (into [] (remove (fn [x] (= :admin (:role x))) roles)))) + admin? (update :roles (fnil conj []) {:role :admin})))))] + (if db? + (do + (core/add-user! db user) + (assoc user :id (:id (core/get-user db (:email user))))) + user)))) + +(defn gen-loi! [] + (-> (gen/generate (s/gen :lipas.loi/document)) + (assoc :status "active") + (assoc :id (str (java.util.UUID/randomUUID))))) From 4035d6d5df6731774757ecf9875d5d7522943968 Mon Sep 17 00:00:00 2001 From: Juho Teperi Date: Tue, 12 Nov 2024 14:03:02 +0200 Subject: [PATCH 48/68] Add tests for ptv integration --- webapp/src/clj/lipas/backend/core.clj | 10 +- webapp/src/clj/lipas/backend/ptv/core.clj | 7 +- webapp/src/clj/lipas/backend/ptv/handler.clj | 17 ++- webapp/src/cljc/lipas/data/ptv.cljc | 116 ++++++++++++++++- webapp/src/cljs/lipas/ui/ptv/events.cljs | 24 ++-- webapp/src/cljs/lipas/ui/ptv/subs.cljs | 129 ++----------------- webapp/test/clj/lipas/backend/ptv_test.clj | 126 ++++++++++++++++++ 7 files changed, 290 insertions(+), 139 deletions(-) create mode 100644 webapp/test/clj/lipas/backend/ptv_test.clj diff --git a/webapp/src/clj/lipas/backend/core.clj b/webapp/src/clj/lipas/backend/core.clj index d09140911..069a6478c 100644 --- a/webapp/src/clj/lipas/backend/core.clj +++ b/webapp/src/clj/lipas/backend/core.clj @@ -526,11 +526,11 @@ (if (and (not draft?) (:ptv resp) (:sync-enabled (:ptv resp))) - (let [new-ptv-data ((resolve 'lipas.backend.ptv.core/upsert-ptv-service-location!) - tx user - {:org (:org-id (:ptv resp)) - :lipas-id (:lipas-id resp) - :ptv (:ptv resp)})] + (let [new-ptv-data (:ptv ((resolve 'lipas.backend.ptv.core/upsert-ptv-service-location!) + tx user + {:org (:org-id (:ptv resp)) + :lipas-id (:lipas-id resp) + :ptv (:ptv resp)}))] (log/infof "Sports site updated and PTV integration enabled") (assoc resp :ptv new-ptv-data)) resp))))) diff --git a/webapp/src/clj/lipas/backend/ptv/core.clj b/webapp/src/clj/lipas/backend/ptv/core.clj index 3e5eb1455..21da7f98a 100644 --- a/webapp/src/clj/lipas/backend/ptv/core.clj +++ b/webapp/src/clj/lipas/backend/ptv/core.clj @@ -56,10 +56,13 @@ (ptv/create-service config data)))) (defn fetch-ptv-services - [{:keys [org-id] :as _m}] - {:pre [(some? org-id)]} + [org-id] (ptv/get-org-services {} org-id)) +(defn fetch-ptv-service-channels + [org-id] + (ptv/get-org-service-channels {} org-id)) + (def persisted-ptv-keys [:languages :summary :description diff --git a/webapp/src/clj/lipas/backend/ptv/handler.clj b/webapp/src/clj/lipas/backend/ptv/handler.clj index cf14c25a8..b23609ab4 100644 --- a/webapp/src/clj/lipas/backend/ptv/handler.clj +++ b/webapp/src/clj/lipas/backend/ptv/handler.clj @@ -76,11 +76,22 @@ ["/actions/fetch-ptv-services" {:post {:require-privilege :ptv/manage - :parameters {:body [:any]} + :parameters {:body [:map + [:org-id :string]]} :handler - (fn [{:keys [body-params]}] + (fn [req] + {:status 200 + :body (ptv-core/fetch-ptv-services (-> req :parameters :body :org-id))})}}] + + ["/actions/fetch-ptv-service-channels" + {:post + {:require-privilege :ptv/manage + :parameters {:body [:map + [:org-id :string]]} + :handler + (fn [req] {:status 200 - :body (ptv-core/fetch-ptv-services body-params)})}}] + :body (ptv-core/fetch-ptv-service-channels (-> req :parameters :body :org-id))})}}] ["/actions/save-ptv-service-location" {:post diff --git a/webapp/src/cljc/lipas/data/ptv.cljc b/webapp/src/cljc/lipas/data/ptv.cljc index 2a4272d68..a294a75f4 100644 --- a/webapp/src/cljc/lipas/data/ptv.cljc +++ b/webapp/src/cljc/lipas/data/ptv.cljc @@ -318,8 +318,122 @@ :service-channel-ids #{"ssid-1"}}))) - (->ptv-service-location nil (constantly [123 456]) uta-jh-with-ptv-meta) + (->ptv-service-location nil (constantly [123 456]) nil uta-jh-with-ptv-meta) ) + +(defn ->service-source-id + [org-id sub-category-id] + (str "lipas-" org-id "-" sub-category-id)) + +(defn resolve-missing-services + "Infer services (sub-categories) that need to be created in PTV and + attached to sports-sites." + [org-id services _types sports-sites] + (let [source-ids (->> services vals (keep :sourceId) set)] + (->> sports-sites + (filter (fn [{:keys [ptv]}] (empty? (:service-ids ptv)))) + (map (fn [site] {:source-id (->service-source-id org-id (:sub-category-id site)) + :sub-category (-> site :sub-category) + :sub-category-id (-> site :sub-category-id)})) + distinct + (remove (fn [m] (contains? source-ids (:source-id m))))))) + +(defn parse-summary + "Returns first line-delimited paragraph." + [s] + (when (string? s) + (first (str/split s #"\r?\n")))) + +(defn resolve-service-channel-name + "Sometimes these seem to have the name under undocumented :name + property and sometimes under documented :serviceChannelNames + array. Wtf." + [service-channel] + (or (:name service-channel) + (some (fn [m] + (when (= "fi" (:language m)) + (:value m))) + (:serviceChannelNames service-channel)))) + +(defn detect-name-conflict + [sports-site service-channels] + (let [s1 (some-> sports-site :name str/trim str/lower-case) + attached-channels (-> sports-site :ptv :service-channel-ids set)] + (some (fn [service-channel] + (let [ssname (resolve-service-channel-name service-channel) + s2 (some-> ssname str/trim str/lower-case)] + (when (and + (not (contains? attached-channels (:id service-channel))) + (= s1 s2)) + {:service-channel-id (:id service-channel)}))) + service-channels))) + +(defn sports-site->ptv-input [{:keys [tr types org-id org-defaults org-langs]} service-channels services site] + (let [service-id (-> site :ptv :service-ids first) + service-channel-id (-> site :ptv :service-channel-ids first) + descriptions-integration (or (-> site :ptv :descriptions-integration) + (:descriptions-integration org-defaults)) + + summary (case descriptions-integration + "lipas-managed-comment-field" + (-> site :comment parse-summary) + + "lipas-managed-ptv-fields" + (-> site :ptv :summary) + + "ptv-managed" + ;; FIXME: avoid tr here + (tr :ptv.integration.description/ptv-managed-helper)) + description (case descriptions-integration + "lipas-managed-comment-field" + (-> site :comment) + + "lipas-managed-ptv-fields" + (-> site :ptv :description) + + "ptv-managed" + (tr :ptv.integration.description/ptv-managed-helper)) + + last-sync (-> site :ptv :last-sync)] + {:valid (boolean (and (some-> description :fi count (> 5)) + (some-> summary :fi count (> 5)))) + :lipas-id (:lipas-id site) + :name (:name site) + :event-date (:event-date site) + ;; :event-date-human (some-> (:event-date site) utils/->human-date-time-at-user-tz) + :name-conflict (detect-name-conflict site (vals service-channels)) + :marketing-name (:marketing-name site) + :type (-> site :search-meta :type :name :fi) + :sub-category (-> site :search-meta :type :sub-category :name :fi) + :sub-category-id (-> site :type :type-code types :sub-category) + :org-id org-id + :admin (-> site :search-meta :admin :name :fi) + :owner (-> site :search-meta :owner :name :fi) + :summary summary + :description description + :languages (or (-> site :ptv :languages) org-langs) + + :descriptions-integration descriptions-integration + :sync-enabled (get-in site [:ptv :sync-enabled] true) + :last-sync last-sync + ;; :last-sync-human (some-> last-sync utils/->human-date-time-at-user-tz) + + :sync-status (cond + (not last-sync) :not-synced + (= (:event-date site) last-sync) :ok + :else :out-of-date) + + :service-ids (-> site :ptv :service-ids) + :service-name (-> services (get service-id) :serviceNames + (->> (some #(when (= "fi" (:language %)) (:value %))))) + :service-integration (or (-> site :ptv :service-integration) + (:service-integration org-defaults)) + :service-channel-id service-channel-id + :service-channel-ids (-> site :ptv :service-channel-ids) + :service-channel-name (-> (get service-channels service-channel-id) + (resolve-service-channel-name)) + :service-channel-integration (or (-> site :ptv :service-channel-integration) + (:service-channel-integration org-defaults))})) diff --git a/webapp/src/cljs/lipas/ui/ptv/events.cljs b/webapp/src/cljs/lipas/ui/ptv/events.cljs index 8e25e35e3..114410c55 100644 --- a/webapp/src/cljs/lipas/ui/ptv/events.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/events.cljs @@ -147,17 +147,19 @@ (rf/reg-event-fx ::fetch-service-channels (fn [{:keys [db]} [_ org]] (when org - {:db (assoc-in db [:ptv :loading-from-ptv :service-channels] true) - ;; FIXME: Load through BE - :fx [[:http-xhrio - {:method :get - :uri (str ptv-root-url-test - "/api/v11/ServiceChannel/organization/" - (:id org)) - - :response-format (ajax/json-response-format {:keywords? true}) - :on-success [::fetch-service-channels-success (:id org)] - :on-failure [::fetch-service-channels-failure]}]]}))) + (let [token (-> db :user :login :token)] + {:db (assoc-in db [:ptv :loading-from-ptv :service-channels] true) + :fx [[:http-xhrio + {:method :post + :headers {:Authorization (str "Token " token)} + :uri (str (:backend-url db) "/actions/fetch-ptv-service-channels") + :params {:org-id (:id org)} + ; "/api/v11/ServiceChannel/organization/" + ; (:id org) + :format (ajax/transit-request-format) + :response-format (ajax/json-response-format {:keywords? true}) + :on-success [::fetch-service-channels-success (:id org)] + :on-failure [::fetch-service-channels-failure]}]]})))) (rf/reg-event-fx ::fetch-service-channels-success (fn [{:keys [db]} [_ org-id resp]] diff --git a/webapp/src/cljs/lipas/ui/ptv/subs.cljs b/webapp/src/cljs/lipas/ui/ptv/subs.cljs index 8672b219b..eb3127c4d 100644 --- a/webapp/src/cljs/lipas/ui/ptv/subs.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/subs.cljs @@ -1,5 +1,6 @@ (ns lipas.ui.ptv.subs (:require [clojure.string :as str] + [lipas.data.ptv :as ptv-data] [lipas.ui.utils :as utils] [re-frame.core :as rf])) @@ -150,30 +151,13 @@ "lipas-managed" (filter (fn [m] (some-> m :source-id (str/starts-with? "lipas-"))) services) services)))) -(defn ->source-id - [org-id sub-category-id] - (str "lipas-" org-id "-" sub-category-id)) - -(defn resolve-missing-services - "Infer services (sub-categories) that need to be created in PTV and - attached to sports-sites." - [org-id services types sports-sites] - (let [source-ids (->> services vals (keep :sourceId) set)] - (->> sports-sites - (filter (fn [{:keys [ptv]}] (empty? (:service-ids ptv)))) - (map (fn [site] {:source-id (->source-id org-id (:sub-category-id site)) - :sub-category (-> site :sub-category) - :sub-category-id (-> site :sub-category-id)})) - distinct - (remove (fn [m] (contains? source-ids (:source-id m))))))) - (rf/reg-sub ::missing-services :<- [::selected-org-id] :<- [::services-by-id] :<- [::sports-sites] :<- [:lipas.ui.sports-sites.subs/all-types] (fn [[org-id services sports-sites types] _] - (resolve-missing-services org-id services types sports-sites))) + (ptv-data/resolve-missing-services org-id services types sports-sites))) (rf/reg-sub ::service-candidate-descriptions :<- [::selected-org-id] @@ -211,45 +195,13 @@ (fn [channels _] (vals channels))) -(defn resolve-service-channel-name - "Sometimes these seem to have the name under undocumented :name - property and sometimes under documented :serviceChannelNames - array. Wtf." - [service-channel] - (or (:name service-channel) - (some (fn [m] - (when (= "fi" (:language m)) - (:value m))) - (:serviceChannelNames service-channel)))) - (rf/reg-sub ::service-channels-list :<- [::service-channels] (fn [channels _] (for [m channels] {:service-channel-id (:id m) - :name (resolve-service-channel-name m)}))) - -(defn parse-summary - "Returns first line-delimited paragraph." - [s] - (when (string? s) - (first (str/split s #"\r?\n")))) - -(defn detect-name-conflict - [sports-site service-channels] - (let [s1 (some-> sports-site :name str/trim str/lower-case) - attached-channels (-> sports-site :ptv :service-channel-ids set)] - (some (fn [service-channel] - (let [ssname (resolve-service-channel-name service-channel) - s2 (some-> ssname str/trim str/lower-case)] - (when (and - (not (contains? attached-channels (:id service-channel))) - (= s1 s2)) - {:service-channel-id (:id service-channel)}))) - service-channels))) - -;; FIXME: Break this into parts -;; Each sports-site should subscribe to its own part of data. + :name (ptv-data/resolve-service-channel-name m)}))) + (rf/reg-sub ::sports-sites :<- [::ptv] :<- [::selected-org-id] @@ -262,71 +214,14 @@ (fn [[ptv org-id services service-channels org-defaults tr types org-langs] _] (let [lipas-id->site (get-in ptv [:org org-id :data :sports-sites])] (for [site (vals lipas-id->site)] - (let [service-id (-> site :ptv :service-ids first) - service-channel-id (-> site :ptv :service-channel-ids first) - descriptions-integration (or (-> site :ptv :descriptions-integration) - (:descriptions-integration org-defaults)) - - summary (case descriptions-integration - "lipas-managed-comment-field" - (-> site :comment parse-summary) - - "lipas-managed-ptv-fields" - (-> site :ptv :summary) - - "ptv-managed" - (tr :ptv.integration.description/ptv-managed-helper)) - description (case descriptions-integration - "lipas-managed-comment-field" - (-> site :comment) - - "lipas-managed-ptv-fields" - (-> site :ptv :description) - - "ptv-managed" - (tr :ptv.integration.description/ptv-managed-helper)) - - last-sync (-> site :ptv :last-sync)] - {:valid (boolean (and (some-> description :fi count (> 5)) - (some-> summary :fi count (> 5)))) - :lipas-id (:lipas-id site) - :name (:name site) - :event-date (:event-date site) - :event-date-human (some-> (:event-date site) utils/->human-date-time-at-user-tz) - :name-conflict (detect-name-conflict site (vals service-channels)) - :marketing-name (:marketing-name site) - :type (-> site :search-meta :type :name :fi) - :sub-category (-> site :search-meta :type :sub-category :name :fi) - :sub-category-id (-> site :type :type-code types :sub-category) - :org-id org-id - :admin (-> site :search-meta :admin :name :fi) - :owner (-> site :search-meta :owner :name :fi) - :summary summary - :description description - :languages (or (-> site :ptv :languages) org-langs) - - :descriptions-integration descriptions-integration - :sync-enabled (get-in site [:ptv :sync-enabled] true) - :last-sync last-sync - :last-sync-human (or (some-> last-sync utils/->human-date-time-at-user-tz) - "Ei koskaan") - - :sync-status (cond - (not last-sync) :not-synced - (= (:event-date site) last-sync) :ok - :else :out-of-date) - - :service-ids (-> site :ptv :service-ids) - :service-name (-> services (get service-id) :serviceNames - (->> (some #(when (= "fi" (:language %)) (:value %))))) - :service-integration (or (-> site :ptv :service-integration) - (:service-integration org-defaults)) - :service-channel-id service-channel-id - :service-channel-ids (-> site :ptv :service-channel-ids) - :service-channel-name (-> (get service-channels service-channel-id) - (resolve-service-channel-name)) - :service-channel-integration (or (-> site :ptv :service-channel-integration) - (:service-channel-integration org-defaults))}))))) + (ptv-data/sports-site->ptv-input {:org-id org-id + :tr tr + :types types + :org-defaults org-defaults + :org-langs org-langs} + service-channels + services + site))))) (rf/reg-sub ::sports-sites-count :<- [::sports-sites] diff --git a/webapp/test/clj/lipas/backend/ptv_test.clj b/webapp/test/clj/lipas/backend/ptv_test.clj new file mode 100644 index 000000000..ec69e6a7b --- /dev/null +++ b/webapp/test/clj/lipas/backend/ptv_test.clj @@ -0,0 +1,126 @@ +(ns lipas.backend.ptv-test + (:require [clojure.test :refer [deftest is use-fixtures] :as t] + [lipas.backend.core :as core] + [lipas.backend.jwt :as jwt] + [lipas.data.ptv :as ptv-data] + [lipas.data.types :as types] + [lipas.schema.core] + [lipas.test-utils :refer [<-json app db] :as tu] + [lipas.utils :as utils] + [ring.mock.request :as mock])) + +(use-fixtures :once (fn [f] + (tu/init-db!) + (f))) + +(use-fixtures :each (fn [f] + (tu/prune-db!) + (tu/prune-es!) + (f))) + +(deftest ^:ptv ^:integration init-site-ptv + (let [user (tu/gen-user {:db? true :admin? true}) + token (jwt/create-token user) + + rev1 (-> (tu/gen-sports-site) + (assoc :status "active") + ;; need to set up realistic type and location for the ptv integration to work + ;; yleisurheilukenttä + (assoc-in [:type :type-code] 1210) + (assoc-in [:location :postal-code] "91900") + (assoc-in [:location :city :city-code] 425)) + _ (core/upsert-sports-site!* db user rev1) + lipas-id (:lipas-id rev1) + resp (app (-> (mock/request :get (str "/api/sports-sites/" lipas-id)) + (mock/content-type "application/json") + (tu/token-header token))) + body (<-json (:body resp)) + site body + + ;; TODO: Use another id for tests run? + org-id ptv-data/liminka-org-id-test + org-langs ["fi" "se" "en"] + ;; re-frame app-db defaults + types types/all + default-settings {:service-integration "lipas-managed" + :service-channel-integration "lipas-managed" + :descriptions-integration "lipas-managed-ptv-fields" + :integration-interval "manual"} + + sports-sites (->> [body] + (utils/index-by :lipas-id))] + (println sports-sites) + (is (some? lipas-id)) + (is (= 200 (:status resp))) + ;; (is (some? (:ptv body))) + + (let [;; Get list of services already on PTV + resp (app (-> (mock/request :post (str "/api/actions/fetch-ptv-services")) + (mock/json-body {:org-id org-id}) + (tu/token-header token))) + services (->> (<-json (:body resp)) + :itemList + (utils/index-by :id)) + + _ (is (= 200 (:status resp))) + _ (is (> (count services) 1)) + + ;; Get list of service channels already on PTV + resp (app (-> (mock/request :post (str "/api/actions/fetch-ptv-service-channels")) + (mock/json-body {:org-id org-id}) + (tu/token-header token))) + service-channels (->> (<-json (:body resp)) + :itemList + (utils/index-by :id)) + + _ (is (= 200 (:status resp))) + _ (is (> (count service-channels) 1)) + + ;; Initializing a PTV data for a site that wasn't previously synced to ptv works like this: + ;; - summary and description are written or generated + ;; - after that this ptv-input functions should return that the site is valid (this is used in the view component) + ;; - save-ptv-service-location is called BUT this doesn't take the + ;; ptv-input but the lipas-id and ptv-meta as parameters + + ;; TODO: is this ptv-input data useful? Could everything (the view components) just use raw site data directly? + ptv-sites (for [site (vals sports-sites)] + (ptv-data/sports-site->ptv-input {:tr (constantly "FOO") + :types types + :org-id org-id + :org-defaults default-settings + :org-langs org-langs} + service-channels + services + site))] + + (is (= 1 (count ptv-sites))) + + (is (= [] + (ptv-data/resolve-missing-services org-id + services + nil + ptv-sites))) + + ;; Add ptv summary and description to the site, enabling the + ;; ptv integration for the site -> will create Service Location. + (let [updated-site (assoc site :ptv (merge default-settings + {:sync-enabled true + :org-id org-id + :summary {:fi "foobar" + :se "foobar" + :en "foobar"} + :description {:fi "foobar" + :se "foobar" + :en "foobar"}})) + resp (app (-> (mock/request :post (str "/api/sports-sites")) + (mock/json-body updated-site) + (tu/token-header token))) + body (<-json (:body resp))] + ;; Responds with 201 for both creates and updates + (is (= 201 (:status resp))) + (println body) + (is (some? (:last-sync (:ptv body)))) + (is (= "Published" (:publishing-status (:ptv body)))))) + + )) + From 5c85c9d7ad99d5f2ea471d1a84aa4bf746d7f3b5 Mon Sep 17 00:00:00 2001 From: Juho Teperi Date: Tue, 12 Nov 2024 15:05:11 +0200 Subject: [PATCH 49/68] Proper ptv component state and config, proxy all ptv req through the BE --- .env.sample.sh | 8 +- webapp/src/clj/lipas/backend/config.clj | 17 +- webapp/src/clj/lipas/backend/core.clj | 3 + webapp/src/clj/lipas/backend/ptv/core.clj | 34 +-- webapp/src/clj/lipas/backend/ptv/handler.clj | 31 ++- .../src/clj/lipas/backend/ptv/integration.clj | 200 ++++++++---------- webapp/src/clj/lipas/backend/system.clj | 4 +- webapp/src/cljs/lipas/ui/ptv/events.cljs | 27 +-- webapp/test/clj/lipas/test_utils.clj | 2 +- 9 files changed, 162 insertions(+), 164 deletions(-) diff --git a/.env.sample.sh b/.env.sample.sh index a158fd1f4..53f16d910 100755 --- a/.env.sample.sh +++ b/.env.sample.sh @@ -100,11 +100,9 @@ export UTP_WEBHOOK_TOKEN_URL="https://login.microsoftonline.com/bdb27328-5c0b-41 # PTV export PTV_API_URL="https://api.palvelutietovaranto.trn.suomi.fi/api" export PTV_TOKEN_URL="https://palvelutietovaranto.trn.suomi.fi/api/auth/api-login" -export PTV_SERVICE_URL="https://api.palvelutietovaranto.trn.suomi.fi/api/v11/Service" -export PTV_SERVICE_LOCATION_URL="https://api.palvelutietovaranto.trn.suomi.fi/api/v11/ServiceChannel/ServiceLocation" -export PTV_ORG_ID=***FILL_THIS*** -export PTV_API_USERNAME=***FILL_THIS*** -export PTV_API_PASSWORD=***FILL_THIS*** +# Test env requires API credentials per org-id, so handled in the code +# export PTV_API_USERNAME=***FILL_THIS*** +# export PTV_API_PASSWORD=***FILL_THIS*** # Open AI export OPEN_AI_API_KEY=***FILL_THIS*** diff --git a/webapp/src/clj/lipas/backend/config.clj b/webapp/src/clj/lipas/backend/config.clj index 5c67a8884..900e61540 100644 --- a/webapp/src/clj/lipas/backend/config.clj +++ b/webapp/src/clj/lipas/backend/config.clj @@ -58,15 +58,13 @@ :s3-bucket (env! :aws-s3-bucket) :s3-bucket-prefix (env! :aws-s3-bucket-prefix)} :ptv - {:api-url (env! :ptv-api-url) - :token-url (env! :ptv-token-url) - :service-url (env! :ptv-service-url) - :service-location-url (env! :ptv-service-location-url) - :creds - {:org-id (env! :ptv-org-id) - :api - {:username (env! :ptv-api-username) - :password (env! :ptv-api-password)}}} + (let [test-env? (= "test" (:ptv-env e/env "prod"))] + {:env (:ptv-env e/env "prod") + :api-url (env! :ptv-api-url) + :token-url (env! :ptv-token-url) + :creds (when-not test-env? + {:api {:username (env! :ptv-api-username) + :password (env! :ptv-api-password)}})}) :open-ai {:api-key (env! :open-ai-api-key) :project "ptv" @@ -79,6 +77,7 @@ :search (ig/ref :lipas/search) :mailchimp (ig/ref :lipas/mailchimp) :aws (ig/ref :lipas/aws) + :ptv (ig/ref :lipas/ptv) :utp {:cms-api-url (env! :utp-cms-api-url) :cms-api-user (env! :utp-cms-api-user) diff --git a/webapp/src/clj/lipas/backend/core.clj b/webapp/src/clj/lipas/backend/core.clj index 069a6478c..cb1ea5ae8 100644 --- a/webapp/src/clj/lipas/backend/core.clj +++ b/webapp/src/clj/lipas/backend/core.clj @@ -526,6 +526,9 @@ (if (and (not draft?) (:ptv resp) (:sync-enabled (:ptv resp))) + ;; TODO: Currently this will create a new sports-site rev. + ;; Make it instead update the sports-site already created in the tx? + ;; Otherwise each save-sports-site! will create two sports-site revs. (let [new-ptv-data (:ptv ((resolve 'lipas.backend.ptv.core/upsert-ptv-service-location!) tx user {:org (:org-id (:ptv resp)) diff --git a/webapp/src/clj/lipas/backend/ptv/core.clj b/webapp/src/clj/lipas/backend/ptv/core.clj index 21da7f98a..405639829 100644 --- a/webapp/src/clj/lipas/backend/ptv/core.clj +++ b/webapp/src/clj/lipas/backend/ptv/core.clj @@ -47,21 +47,28 @@ :content))) (defn upsert-ptv-service! - [{:keys [id source-id] :as m}] - {:pre [(some? source-id)]} - (let [config nil - data (ptv-data/->ptv-service (merge config m))] + [ptv {:keys [id] :as m}] + ;; FIXME: Does ->ptv-service need something from the component config? + (let [data (ptv-data/->ptv-service m)] (if id - (ptv/update-service config id data) - (ptv/create-service config data)))) + (ptv/update-service ptv id data) + (ptv/create-service ptv data)))) + +(defn fetch-ptv-org + [ptv org-id] + (ptv/get-org ptv org-id)) + +(defn fetch-ptv-service-collections + [ptv org-id] + (ptv/get-org-service-collections ptv org-id)) (defn fetch-ptv-services - [org-id] - (ptv/get-org-services {} org-id)) + [ptv org-id] + (ptv/get-org-services ptv org-id)) (defn fetch-ptv-service-channels - [org-id] - (ptv/get-org-service-channels {} org-id)) + [ptv org-id] + (ptv/get-org-service-channels ptv org-id)) (def persisted-ptv-keys [:languages :summary @@ -76,11 +83,10 @@ :service-channel-ids]) (defn upsert-ptv-service-location! - [db user {:keys [org lipas-id ptv] :as _m}] + [db ptv-component user {:keys [org lipas-id ptv] :as _m}] (jdbc/with-db-transaction [tx db] (let [site (db/get-sports-site db lipas-id) _ (assert (some? site) (str "Sports site " lipas-id " not found in DB")) - config nil id (-> ptv :service-channel-ids first) ;; merge or just replace? @@ -89,8 +95,8 @@ now (utils/timestamp) data (ptv-data/->ptv-service-location org gis/wgs84->tm35fin-no-wrap now (core/enrich site)) ptv-resp (if id - (ptv/update-service-location config id data) - (ptv/create-service-location config data)) + (ptv/update-service-location ptv-component id data) + (ptv/create-service-location ptv-component data)) ;; Store the new PTV info to Lipas DB new-ptv-data (-> ptv (select-keys persisted-ptv-keys) diff --git a/webapp/src/clj/lipas/backend/ptv/handler.clj b/webapp/src/clj/lipas/backend/ptv/handler.clj index b23609ab4..ed398450a 100644 --- a/webapp/src/clj/lipas/backend/ptv/handler.clj +++ b/webapp/src/clj/lipas/backend/ptv/handler.clj @@ -29,7 +29,7 @@ [:lipas-id :string] [:ptv ptv-meta]]) -(defn routes [{:keys [db search] :as _ctx}] +(defn routes [{:keys [db search ptv] :as _ctx}] ["" {:coercion reitit.coercion.malli/coercion :tags ["ptv"] @@ -64,14 +64,35 @@ {:status 200 :body (ptv-core/generate-ptv-service-descriptions search body-params)})}}] + ["/actions/fetch-ptv-org" + {:post + {:require-privilege :ptv/manage + :parameters {:body [:map + [:org-id :string]]} + :handler + (fn [req] + {:status 200 + :body (ptv-core/fetch-ptv-org ptv (-> req :parameters :body :org-id))})}}] + + ["/actions/fetch-ptv-service-collections" + {:post + {:require-privilege :ptv/manage + :parameters {:body [:map + [:org-id :string]]} + :handler + (fn [req] + {:status 200 + :body (ptv-core/fetch-ptv-service-collections ptv (-> req :parameters :body :org-id))})}}] + ["/actions/save-ptv-service" {:post + ;; FIXME: Schema {:require-privilege :ptv/manage :parameters {:body [:any]} :handler (fn [{:keys [body-params]}] {:status 200 - :body (ptv-core/upsert-ptv-service! body-params)})}}] + :body (ptv-core/upsert-ptv-service! ptv body-params)})}}] ["/actions/fetch-ptv-services" {:post @@ -81,7 +102,7 @@ :handler (fn [req] {:status 200 - :body (ptv-core/fetch-ptv-services (-> req :parameters :body :org-id))})}}] + :body (ptv-core/fetch-ptv-services ptv (-> req :parameters :body :org-id))})}}] ["/actions/fetch-ptv-service-channels" {:post @@ -91,7 +112,7 @@ :handler (fn [req] {:status 200 - :body (ptv-core/fetch-ptv-service-channels (-> req :parameters :body :org-id))})}}] + :body (ptv-core/fetch-ptv-service-channels ptv (-> req :parameters :body :org-id))})}}] ["/actions/save-ptv-service-location" {:post @@ -100,7 +121,7 @@ :handler (fn [{:keys [body-params identity]}] {:status 200 - :body (ptv-core/upsert-ptv-service-location! db identity body-params)})}}] + :body (ptv-core/upsert-ptv-service-location! db ptv identity body-params)})}}] ["/actions/save-ptv-meta" {:post diff --git a/webapp/src/clj/lipas/backend/ptv/integration.clj b/webapp/src/clj/lipas/backend/ptv/integration.clj index ed8b4777c..9d67369ec 100644 --- a/webapp/src/clj/lipas/backend/ptv/integration.clj +++ b/webapp/src/clj/lipas/backend/ptv/integration.clj @@ -3,60 +3,36 @@ [cheshire.core :as json] [clj-http.client :as client] [clojure.string :as str] - [lipas.backend.config :as config] [lipas.backend.search :as search] [lipas.data.ptv :as ptv-data] - [lipas.utils :as utils] [taoensso.timbre :as log])) -;; Test creds are OK to "leak" to VCS since they're public anyway -(def test-config - (utils/deep-merge - (get config/default-config :ptv) - {:api-url "https://api.palvelutietovaranto.trn.suomi.fi/api" - :token-url "https://palvelutietovaranto.trn.suomi.fi/api/auth/api-login" - :service-url "https://api.palvelutietovaranto.trn.suomi.fi/api/v11/Service" - :service-location-url "https://api.palvelutietovaranto.trn.suomi.fi/api/v11/ServiceChannel/ServiceLocation" - :creds - {:main-user - ;; unused? - {:username "paakayttaja41.testi@testi.fi" - :password "Paatestaaja41-1041*"} - :maintainer - ;; unused? - {:username "" - :password ""} - ;; FIXME: The current test env needs different credentials per org - :api - ;; org 10 - #_{:username "API17@testi.fi" - :password "APIinterfaceUser17-1017*"} - ;; org 6 - #_{:username "API9@testi.fi" - :password "APIinterfaceUser9-1009*"} - ;; org 9 - {:username "API15@testi.fi" - :password "APIinterfaceUser15-1015*"}}})) - -#_(def test-config - {:api-url "https://api.palvelutietovaranto.trn.suomi.fi/api" - :token-url "https://palvelutietovaranto.trn.suomi.fi/api/auth/api-login" - :service-url "https://api.palvelutietovaranto.trn.suomi.fi/api/v11/Service" - :service-location-url "https://api.palvelutietovaranto.trn.suomi.fi/api/v11/ServiceChannel/ServiceLocation" - :creds - {:main-user - {:username "paakayttaja35.testi@testi.fi" - :password "Paatestaaja35-1035*"} - :maintainer - {:username "yllapitaja35.testi@testi.fi" - :password "Yllapitajatestaaja35-1035*"} - :api - {:username "API14@testi.fi" - :password "APIinterfaceUser14-1014*"}}}) - -;; Org-id => {:token ... :payload ...} -;; TODO: Move this to IG component state? -(def current-token (atom {})) +;; ptv component, :lipas/ptv has the config and :tokens atom for org-id -> auth token storage + +;; In test the credential to create API tokens is dependant on the org-id, +;; so use this fn to hardcode the credentials. +;; These keys are public so can be leaked out... +(defn get-test-credentials [org-id] + (case org-id + ;; org 6 + "3d1759a2-e47a-4947-9a31-cab1c1e2512b" + {:username "API9@testi.fi" + :password "APIinterfaceUser9-1009*"} + + ;; org 9 + "7fdd7f84-e52a-4c17-a59a-d7c2a3095ed5" + {:username "API15@testi.fi" + :password "APIinterfaceUser15-1015*"} + + ;; org 10 + "52e0f6dc-ec1f-48d5-a0a2-7a4d8b657d53" + {:username "API17@testi.fi" + :password "APIinterfaceUser17-1017*"} + + nil)) + +(defn make-url [ptv & parts] + (apply str (:api-url ptv) parts)) (defn unix-time [] (/ (System/currentTimeMillis) 1000)) @@ -97,25 +73,27 @@ (-> token (str/split #"\.") second b64/decode (String.) (json/decode keyword))) (defn get-token - [org-id] + [ptv org-id] ;; NOTE: deref + swap - (let [x (get @current-token org-id)] + (let [x (get @(:tokens ptv) org-id)] (if (or (not x) (expired? (:payload x))) - (let [new-token (authenticate {:token-url (:token-url test-config) - :username (get-in test-config [:creds :api :username]) - :password (get-in test-config [:creds :api :password]) - :org-id org-id}) + (let [new-token (authenticate (merge {:token-url (:token-url ptv) + :username (get-in ptv [:creds :api :username]) + :password (get-in ptv [:creds :api :password]) + :org-id org-id} + (when (= "test" (:env ptv)) + (get-test-credentials org-id)))) x {:token new-token :payload (parse-payload new-token)}] (log/infof "Create token %s => %s" org-id new-token) - (swap! current-token assoc org-id x) + (swap! (:tokens ptv) assoc org-id x) (:token x)) (:token x)))) (defn http - ([req] (http req false)) - ([req retried?] - (let [token (get-token (:auth-org-id req)) + ([ptv auth-org-id req] (http ptv auth-org-id req false)) + ([ptv auth-org-id req retried?] + (let [token (get-token ptv auth-org-id) req* (-> req (dissoc :auth-org-id) (assoc :accept :json @@ -135,100 +113,95 @@ (get (:headers d) "WWW-Authenticate"))) (do (log/infof "Invalid token, trying to get a new token and retry") - (swap! current-token dissoc (:auth-org-id req)) - (http req true)) + (swap! (:tokens ptv) dissoc (:auth-org-id req)) + (http ptv auth-org-id req true)) (throw (ex-info (format "HTTP Error: %s %s" (:status d) (:body d)) {:resp d :req req*} nil))))))))) +(defn get-org + [ptv org-id] + (let [params {:url (make-url ptv "/v11/Organization/" org-id) + :method :get}] + (-> (http ptv org-id params) + :body))) + ;; Need to proxy this with auth because otherwise the API doesn't ;; return :sourceId (wtf) (defn get-org-services - [{:keys [service-url] - :or {service-url (:service-url test-config)}} - org-id] - (let [params {:url (str service-url "/list/organization") - :auth-org-id org-id + [ptv org-id] + (let [params {:url (make-url ptv "/v11/Service/list/organization") :method :get :query-params {:organizationId org-id}}] - (-> (http params) + (-> (http ptv org-id params) + :body))) + +(defn get-org-service-collections + [ptv org-id] + (let [params {:url (make-url ptv "/v11/ServiceCollection/organization") + :method :get + :query-params {:organizationId org-id}}] + (-> (http ptv org-id params) :body))) (defn get-org-service-channels - [{:keys [api-url] - :or {api-url (:api-url test-config)}} - org-id] + [ptv org-id] ;; TODO: Solve paginations, if multiple pages, lazy seq and make multiple requests? ;; Or should we handle pagination from FE? ;; 500 should be fine in one response, what if we have 2000-5000 for some city/org? - (let [params {:url (str api-url "/v11/ServiceChannel/organization/" org-id) - :auth-org-id org-id + (let [params {:url (make-url ptv "/v11/ServiceChannel/organization/" org-id) :method :get}] - (-> (http params) + (-> (http ptv org-id params) :body))) (defn create-service - [{:keys [service-url] - :or {service-url (:service-url test-config)} - :as _config} + [ptv {:keys [org-id] :as service}] - (let [params {:url service-url - :auth-org-id org-id + (let [params {:url (make-url ptv "/v11/Service") :method :post :form-params service}] (log/infof "Create PTV service %s" service) - (-> (http params) + (-> (http ptv org-id params) :body))) (defn get-service - [{:keys [service-url org-id] - :or {service-url (:service-url test-config)}} - service-id] - (let [params {:url (str service-url "/" service-id) - :auth-org-id org-id + [ptv org-id service-id] + (let [params {:url (make-url ptv "/v11/Service/" service-id) :method :get}] - (-> (http params) + (-> (http ptv org-id params) :body))) (defn update-service - [{:keys [service-url] - :or {service-url (:service-url test-config)}} + [ptv service-id {:keys [org-id] :as data}] (log/info "Update PTV service with id " service-id "and data" data) - (let [params {:url (str service-url "/" service-id) - :auth-org-id org-id + (let [params {:url (make-url ptv "/v11/Service/" service-id) :method :put :form-params data}] - (-> (http params) + (-> (http ptv org-id params) :body))) (defn create-service-location - [{:keys [service-location-url] - :or {service-location-url (:service-location-url test-config)}} - service-location] + [ptv service-location] (let [org-id (-> service-location :organizationId) - params {:url service-location-url + params {:url (make-url ptv "/v11/ServiceChannel/ServiceLocation") :auth-org-id org-id :method :post :form-params service-location}] (log/info "Create PTV service location" service-location) - (-> (http params) + (-> (http ptv org-id params) :body))) (defn update-service-location - [{:keys [service-location-url] - :or {service-location-url (:service-location-url test-config)}} - service-location-id - data] + [ptv service-location-id data] (let [org-id (-> data :organization :id) - params {:url (str service-location-url "/" service-location-id) - :auth-org-id org-id + params {:url (make-url ptv "/v11/ServiceChannel/ServiceLocation/" service-location-id) :method :put :form-params data}] (log/infof "req %s" params) - (-> (http params) + (-> (http ptv org-id params) :body))) (defn get-eligible-sites @@ -261,24 +234,31 @@ (->> (map :_source))))) (comment - (get-org-services {} ptv-data/liminka-org-id-test) + (def ptv* (:lipas/ptv integrant.repl.state/system)) + + (get-org-services ptv* ptv-data/liminka-org-id-test) ;; Delete all org services (doseq [x (:itemList (get-org-services {} ptv-data/liminka-org-id-test))] - (update-service {:org-id ptv-data/liminka-org-id-test} + (update-service ptv* (:id x) - {:publishingStatus "Deleted"})) + {:org-id ptv-data/liminka-org-id-test + :publishingStatus "Deleted"})) - (get-service {} + (get-service ptv* + ptv-data/liminka-org-id-test (-> (get-org-services {} ptv-data/liminka-org-id-test) :itemList first :id)) - (get-org-service-channels {} ptv-data/liminka-org-id-test) + (get-org-service-channels ptv* ptv-data/liminka-org-id-test) ;; Delete all org service locations - (doseq [x (:itemList (get-org-service-channels {} ptv-data/liminka-org-id-test))] + (doseq [x (:itemList (get-org-service-channels ptv* ptv-data/liminka-org-id-test))] (update-service-location {:org-id ptv-data/liminka-org-id-test} (:id x) {:publishingStatus "Deleted"})) - (update-service-location {:org-id ptv-data/liminka-org-id-test} "fc768bb4-268c-4054-9b88-9ecc9a943452" {:publishingStatus "Deleted"})) + (update-service-location ptv* + "fc768bb4-268c-4054-9b88-9ecc9a943452" + {:org-id ptv-data/liminka-org-id-test + :publishingStatus "Deleted"})) diff --git a/webapp/src/clj/lipas/backend/system.clj b/webapp/src/clj/lipas/backend/system.clj index 00d96da29..37fa02d79 100644 --- a/webapp/src/clj/lipas/backend/system.clj +++ b/webapp/src/clj/lipas/backend/system.clj @@ -77,8 +77,8 @@ (defmethod ig/halt-key! :lipas/open-ai [_ _m] ) -(defmethod ig/init-key :lipas/ptv [_ _config] - ) +(defmethod ig/init-key :lipas/ptv [_ config] + (assoc config :tokens (atom {}))) (defmethod ig/halt-key! :lipas/ptv [_ _m] ) diff --git a/webapp/src/cljs/lipas/ui/ptv/events.cljs b/webapp/src/cljs/lipas/ui/ptv/events.cljs index 114410c55..2d9430f5c 100644 --- a/webapp/src/cljs/lipas/ui/ptv/events.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/events.cljs @@ -6,13 +6,6 @@ [lipas.ui.utils :as utils] [re-frame.core :as rf])) -(def ptv-root-url-prod - "https://api.palvelutietovaranto.suomi.fi") - -;; FIXME: Remove, proxy all through BE -(def ptv-root-url-test - "https://api.palvelutietovaranto.trn.suomi.fi") - (rf/reg-event-db ::open-dialog (fn [db [_ _]] (assoc-in db [:ptv :dialog :open?] true))) @@ -87,11 +80,12 @@ (fn [{:keys [db]} [_ org]] (when org {:db (assoc-in db [:ptv :loading-from-ptv :org] true) - ;; FIXME: Load through BE :fx [[:http-xhrio - {:method :get - :uri (str ptv-root-url-test "/api/v11/Organization/" (:id org)) - :response-format (ajax/json-response-format {:keywords? true}) + {:method :post + :uri (str (:backend-url db) "/actions/fetch-ptv-org") + :params {:org-id (:id org)} + :format (ajax/transit-request-format) + :response-format (ajax/transit-response-format) :on-success [::fetch-org-success (:id org)] :on-failure [::fetch-org-failure]}]]}))) @@ -154,8 +148,6 @@ :headers {:Authorization (str "Token " token)} :uri (str (:backend-url db) "/actions/fetch-ptv-service-channels") :params {:org-id (:id org)} - ; "/api/v11/ServiceChannel/organization/" - ; (:id org) :format (ajax/transit-request-format) :response-format (ajax/json-response-format {:keywords? true}) :on-success [::fetch-service-channels-success (:id org)] @@ -182,12 +174,11 @@ (fn [{:keys [db]} [_ org]] (when org {:db (assoc-in db [:ptv :loading-from-ptv :service-collections] true) - ;; FIXME: Load through BE :fx [[:http-xhrio - {:method :get - :uri (str ptv-root-url-test - "/api/v11/ServiceCollection/organization" - "?organizationId=" (:id org)) + {:method :post + :uri (str (:backend-url db) "/actions/fetch-ptv-service-collections") + :params {:org-id (:id org)} + :format (ajax/transit-request-format) :response-format (ajax/json-response-format {:keywords? true}) :on-success [::fetch-service-collections-success (:id org)] :on-failure [::fetch-service-collections-failure]}]]}))) diff --git a/webapp/test/clj/lipas/test_utils.clj b/webapp/test/clj/lipas/test_utils.clj index f42f89087..6b2f59195 100644 --- a/webapp/test/clj/lipas/test_utils.clj +++ b/webapp/test/clj/lipas/test_utils.clj @@ -54,7 +54,7 @@ (defn- test-suffix [s] (str s "_test")) (def config (-> config/default-config - (select-keys [:db :app :search :mailchimp :aws]) + (select-keys [:db :app :search :mailchimp :aws :ptv]) (assoc-in [:app :emailer] (email/->TestEmailer)) (update-in [:db :dbname] test-suffix) (assoc-in [:db :dev] true) ;; No connection pool From 83b21af7c54d10f5c885a4657cd1f2cd275f09df Mon Sep 17 00:00:00 2001 From: Juho Teperi Date: Tue, 12 Nov 2024 15:50:36 +0200 Subject: [PATCH 50/68] Generate PTV summary/description from edit form state --- webapp/src/clj/lipas/backend/ptv/core.clj | 7 ++++ webapp/src/clj/lipas/backend/ptv/handler.clj | 14 ++++++- .../src/clj/lipas/backend/ptv/integration.clj | 4 +- webapp/src/cljs/lipas/ui/ptv/events.cljs | 30 ++++++++++++++ webapp/src/cljs/lipas/ui/ptv/site_view.cljs | 41 +++++++++++-------- webapp/test/clj/lipas/backend/ptv_test.clj | 2 + 6 files changed, 76 insertions(+), 22 deletions(-) diff --git a/webapp/src/clj/lipas/backend/ptv/core.clj b/webapp/src/clj/lipas/backend/ptv/core.clj index 405639829..67b8ef6c4 100644 --- a/webapp/src/clj/lipas/backend/ptv/core.clj +++ b/webapp/src/clj/lipas/backend/ptv/core.clj @@ -26,6 +26,13 @@ :message :content))) +(defn generate-ptv-descriptions-from-data + [doc] + (let [doc (core/enrich doc)] + (-> (ai/generate-ptv-descriptions doc) + :message + :content))) + (defn make-overview [sites] {:city-name (->> sites first :search-meta :location :city :name) diff --git a/webapp/src/clj/lipas/backend/ptv/handler.clj b/webapp/src/clj/lipas/backend/ptv/handler.clj index ed398450a..af5689315 100644 --- a/webapp/src/clj/lipas/backend/ptv/handler.clj +++ b/webapp/src/clj/lipas/backend/ptv/handler.clj @@ -1,6 +1,7 @@ (ns lipas.backend.ptv.handler (:require [lipas.backend.ptv.core :as ptv-core] - [reitit.coercion.malli])) + [reitit.coercion.malli] + [reitit.coercion.spec])) (defn localized-string-schema [string-props] [:map @@ -55,6 +56,17 @@ search (-> req :parameters :body :lipas-id))})}}] + ["/actions/generate-ptv-descriptions-from-data" + {:post + {:require-privilege :ptv/manage + :coercion reitit.coercion.spec/coercion + :parameters {:body :lipas/new-or-existing-sports-site} + :handler + (fn [req] + {:status 200 + :body (ptv-core/generate-ptv-descriptions-from-data + (-> req :parameters :body))})}}] + ["/actions/generate-ptv-service-descriptions" {:post {:require-privilege :ptv/manage diff --git a/webapp/src/clj/lipas/backend/ptv/integration.clj b/webapp/src/clj/lipas/backend/ptv/integration.clj index 9d67369ec..d6a2c75ee 100644 --- a/webapp/src/clj/lipas/backend/ptv/integration.clj +++ b/webapp/src/clj/lipas/backend/ptv/integration.clj @@ -217,9 +217,7 @@ {:bool {:must (remove nil? - [;; Include all statuses - this is also used to remove the sites from PTV - ; {:terms {:status.keyword ["active" - ; "out-of-service-temporarily"]}} + [{:terms {:status.keyword ["active" "out-of-service-temporarily"]}} (when city-codes {:terms {:location.city.city-code city-codes}}) (when owners diff --git a/webapp/src/cljs/lipas/ui/ptv/events.cljs b/webapp/src/cljs/lipas/ui/ptv/events.cljs index 2d9430f5c..1fe3c2453 100644 --- a/webapp/src/cljs/lipas/ui/ptv/events.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/events.cljs @@ -306,6 +306,36 @@ :fx (or extra-fx [[:dispatch [:lipas.ui.events/set-active-notification notification]]])}))) +(rf/reg-event-fx ::generate-descriptions-from-data + (fn [{:keys [db]} [_ lipas-id]] + (let [token (-> db :user :login :token) + edit-data (-> db :sports-sites (get lipas-id) :editing)] + {:db (assoc-in db [:ptv :loading-from-lipas :descriptions] true) + :fx [[:http-xhrio + {:method :post + :headers {:Authorization (str "Token " token)} + :uri (str (:backend-url db) "/actions/generate-ptv-descriptions-from-data") + :params (utils/make-saveable edit-data) + :format (ajax/transit-request-format) + :response-format (ajax/transit-response-format) + :on-success [::generate-descriptions-from-data-success lipas-id] + :on-failure [::generate-descriptions-from-data-failure lipas-id]}]]}))) + +(rf/reg-event-fx ::generate-descriptions-from-data-success + (fn [{:keys [db]} [_ lipas-id resp]] + {:db (-> db + (assoc-in [:ptv :loading-from-lipas :descriptions] false) + (update-in [:sports-sites lipas-id :editing :ptv] merge resp))})) + +(rf/reg-event-fx ::generate-descriptions-from-data-failure + (fn [{:keys [db]} [_]] + (let [tr (:translator db) + notification {:message (tr :notifications/get-failed) + :success? false}] + {:db (-> db + (assoc-in [:ptv :loading-from-lipas :descriptions] false)) + :fx [[:dispatch [:lipas.ui.events/set-active-notification notification]]]}))) + (rf/reg-event-db ::toggle-sync-all (fn [db [_ enabled]] (let [org-id (get-in db [:ptv :selected-org :id])] diff --git a/webapp/src/cljs/lipas/ui/ptv/site_view.cljs b/webapp/src/cljs/lipas/ui/ptv/site_view.cljs index 6e61ec4a4..bb3860156 100644 --- a/webapp/src/cljs/lipas/ui/ptv/site_view.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/site_view.cljs @@ -1,6 +1,7 @@ (ns lipas.ui.ptv.site-view (:require ["@mui/material/Alert$default" :as Alert] ["@mui/material/Button$default" :as Button] + ["@mui/material/CircularProgress$default" :as CircularProgress] ["@mui/material/FormControl$default" :as FormControl] ["@mui/material/FormLabel$default" :as FormLabel] ["@mui/material/Stack$default" :as Stack] @@ -8,6 +9,7 @@ [lipas.ui.components :as lui] [lipas.ui.ptv.controls :as controls] [lipas.ui.ptv.events :as events] + [lipas.ui.ptv.subs :as subs] [lipas.ui.uix.hooks :refer [use-subscribe]] [re-frame.core :as rf] [reagent.core :as r] @@ -20,11 +22,12 @@ editing? (and can-edit? editing*) read-only? (not editing?) site (use-subscribe [:lipas.ui.sports-sites.subs/latest-rev lipas-id]) + ;; default-settings {} enabled (boolean (:ptv site)) descriptions-enabled (not= "manual" (:descriptions-integration (:ptv site))) - loading? false] + loading? (use-subscribe [::subs/generating-descriptions?])] ($ Stack {:direction "column" :sx #js {:gap 2}} @@ -55,12 +58,24 @@ :tr tr}) (when (= "lipas-managed-ptv-fields" (:descriptions-integration (:ptv site))) - ($ Button - {:disabled loading? - :variant "outlined" - :on-click (fn [_e] - (rf/dispatch [::events/generate-descriptions (:lipas-id site) [] []]))} - (tr :ptv.actions/generate-with-ai))) + ($ Stack + {:sx #js {:position "relative"}} + ($ Button + {:disabled (or loading? + read-only?) + :variant "outlined" + ;; NOTE: Could use the lipas-id version when not editing? But then we don't have + ;; place to store the results. + :on-click (fn [_e] + (rf/dispatch [::events/generate-descriptions-from-data lipas-id]))} + (tr :ptv.actions/generate-with-ai)) + (when loading? + ($ CircularProgress + {:size 24 + :sx #js {:position "absolute" + :top "50%" + :left "50%" + :mt "-12px"}})))) ($ controls/lang-selector {:value selected-tab @@ -93,14 +108,4 @@ (rf/dispatch [:lipas.ui.sports-sites.events/edit-field lipas-id [:ptv :description selected-tab] v])) :label "Kuvaus" :value (or (get-in edit-data [:ptv :description selected-tab]) - (get-in site [:ptv :description selected-tab]))}]) - - #_ - ($ Button - {:variant "contained" - :color "primary" - :disabled (or (not can-edit?) - loading?) - :on-click (fn [_e] - (rf/dispatch [::events/create-ptv-service-location* lipas-id [] []]))} - "Vie PTV")))) + (get-in site [:ptv :description selected-tab]))}])))) diff --git a/webapp/test/clj/lipas/backend/ptv_test.clj b/webapp/test/clj/lipas/backend/ptv_test.clj index ec69e6a7b..27a3b5336 100644 --- a/webapp/test/clj/lipas/backend/ptv_test.clj +++ b/webapp/test/clj/lipas/backend/ptv_test.clj @@ -106,6 +106,8 @@ (let [updated-site (assoc site :ptv (merge default-settings {:sync-enabled true :org-id org-id + ;; TODO: Need to setup the link to services + :service-ids [] :summary {:fi "foobar" :se "foobar" :en "foobar"} From 44b825542a8b89a126a797e994e40620ae5d26da Mon Sep 17 00:00:00 2001 From: Juho Teperi Date: Tue, 12 Nov 2024 16:09:55 +0200 Subject: [PATCH 51/68] Add feature to translate the ptv summary/description to other languages --- webapp/src/clj/lipas/backend/ptv/ai.clj | 23 +++++++++++++ webapp/src/clj/lipas/backend/ptv/core.clj | 6 ++++ webapp/src/clj/lipas/backend/ptv/handler.clj | 14 ++++++++ webapp/src/cljs/lipas/ui/ptv/events.cljs | 34 ++++++++++++++++++++ webapp/src/cljs/lipas/ui/ptv/site_view.cljs | 10 +++++- 5 files changed, 86 insertions(+), 1 deletion(-) diff --git a/webapp/src/clj/lipas/backend/ptv/ai.clj b/webapp/src/clj/lipas/backend/ptv/ai.clj index 1dd73a1c5..c299e7563 100644 --- a/webapp/src/clj/lipas/backend/ptv/ai.clj +++ b/webapp/src/clj/lipas/backend/ptv/ai.clj @@ -1,6 +1,7 @@ (ns lipas.backend.ptv.ai (:require [cheshire.core :as json] [clj-http.client :as client] + [clojure.string :as str] [clojure.walk :as walk] [lipas.backend.config :as config] [malli.json-schema :as json-schema] @@ -149,6 +150,28 @@ Provide answers in English, Finnish, and Swedish. Different language versions ca ptv-system-instruction-v2 (format generate-utp-descriptions-prompt (json/encode prompt-doc))))) +(def translate-to-other-langs-prompt + "Käännä tämän viestin lopussa olevat tiivistelmä (max 150 merkkiä) ja tekstikuvaus, jotka sopivat + Palvelutietovarannossa palvelupaikan kuvaukseen, kieleltä %s kielille %s. + %s") + +(defn translate-to-other-langs + [{:keys [from to summary description]}] + (complete openai-config + ptv-system-instruction-v2 + (format translate-to-other-langs-prompt + from + (str/join ", " to) + (json/encode {:summary summary + :description description})))) + +(comment + (translate-to-other-langs + {:from "fi" + :to ["en" "se"] + :summary "Limingan yleisurheilupyhättö, monipuolinen ulkoilma-alue." + :description "Limingan yleisurheilupyhättö on monipuolinen ulkoilma-alue, jossa on useita yleisurheilulajeja varten varustettuja kenttiä."})) + (def generate-utp-service-descriptions-prompt "Laadi tämän viestin lopussa olevan JSON-rakenteen kuvaamasta liikuntapaikasta tiivistelmä (max 150 merkkiä) ja pidempi diff --git a/webapp/src/clj/lipas/backend/ptv/core.clj b/webapp/src/clj/lipas/backend/ptv/core.clj index 67b8ef6c4..c678b4371 100644 --- a/webapp/src/clj/lipas/backend/ptv/core.clj +++ b/webapp/src/clj/lipas/backend/ptv/core.clj @@ -33,6 +33,12 @@ :message :content))) +(defn translate-to-other-langs + [doc] + (-> (ai/translate-to-other-langs doc) + :message + :content)) + (defn make-overview [sites] {:city-name (->> sites first :search-meta :location :city :name) diff --git a/webapp/src/clj/lipas/backend/ptv/handler.clj b/webapp/src/clj/lipas/backend/ptv/handler.clj index af5689315..11934ea96 100644 --- a/webapp/src/clj/lipas/backend/ptv/handler.clj +++ b/webapp/src/clj/lipas/backend/ptv/handler.clj @@ -67,6 +67,20 @@ :body (ptv-core/generate-ptv-descriptions-from-data (-> req :parameters :body))})}}] + ["/actions/translate-to-other-langs" + {:post + {:require-privilege :ptv/manage + :parameters {:body [:map + [:from :string] + [:to [:set :string]] + [:summary :string] + [:description :string]]} + :handler + (fn [req] + {:status 200 + :body (ptv-core/translate-to-other-langs + (-> req :parameters :body))})}}] + ["/actions/generate-ptv-service-descriptions" {:post {:require-privilege :ptv/manage diff --git a/webapp/src/cljs/lipas/ui/ptv/events.cljs b/webapp/src/cljs/lipas/ui/ptv/events.cljs index 1fe3c2453..d962c2b54 100644 --- a/webapp/src/cljs/lipas/ui/ptv/events.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/events.cljs @@ -336,6 +336,40 @@ (assoc-in [:ptv :loading-from-lipas :descriptions] false)) :fx [[:dispatch [:lipas.ui.events/set-active-notification notification]]]}))) +(rf/reg-event-fx ::translate-to-other-langs + (fn [{:keys [db]} [_ lipas-id y]] + (let [token (-> db :user :login :token) + edit-data (-> db :sports-sites (get lipas-id) :editing) + ptv (-> edit-data :ptv) + data (assoc y + :summary (-> (:summary ptv) (get (keyword (:from y)))) + :description (-> (:description ptv) (get (keyword (:from y)))))] + {:db (assoc-in db [:ptv :loading-from-lipas :descriptions] true) + :fx [[:http-xhrio + {:method :post + :headers {:Authorization (str "Token " token)} + :uri (str (:backend-url db) "/actions/translate-to-other-langs") + :params data + :format (ajax/transit-request-format) + :response-format (ajax/transit-response-format) + :on-success [::translate-to-other-langs-success lipas-id] + :on-failure [::translate-to-other-langs-failure lipas-id]}]]}))) + +(rf/reg-event-fx ::translate-to-other-langs-success + (fn [{:keys [db]} [_ lipas-id resp]] + {:db (-> db + (assoc-in [:ptv :loading-from-lipas :descriptions] false) + (update-in [:sports-sites lipas-id :editing :ptv] merge resp))})) + +(rf/reg-event-fx ::translate-to-other-langs-failure + (fn [{:keys [db]} [_]] + (let [tr (:translator db) + notification {:message (tr :notifications/get-failed) + :success? false}] + {:db (-> db + (assoc-in [:ptv :loading-from-lipas :descriptions] false)) + :fx [[:dispatch [:lipas.ui.events/set-active-notification notification]]]}))) + (rf/reg-event-db ::toggle-sync-all (fn [db [_ enabled]] (let [org-id (get-in db [:ptv :selected-org :id])] diff --git a/webapp/src/cljs/lipas/ui/ptv/site_view.cljs b/webapp/src/cljs/lipas/ui/ptv/site_view.cljs index bb3860156..9f7651a3a 100644 --- a/webapp/src/cljs/lipas/ui/ptv/site_view.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/site_view.cljs @@ -108,4 +108,12 @@ (rf/dispatch [:lipas.ui.sports-sites.events/edit-field lipas-id [:ptv :description selected-tab] v])) :label "Kuvaus" :value (or (get-in edit-data [:ptv :description selected-tab]) - (get-in site [:ptv :description selected-tab]))}])))) + (get-in site [:ptv :description selected-tab]))}]) + + ($ Button + {:disabled (or loading? + read-only?) + :on-click (fn [_e] + (rf/dispatch [::events/translate-to-other-langs lipas-id {:from (name selected-tab) + :to (disj #{"fi" "en" "se"} (name selected-tab))}]))} + "Käännä muille kielille")))) From 1348283a894357da08a60ccb8e02ad7e1a804c36 Mon Sep 17 00:00:00 2001 From: Juho Teperi Date: Tue, 12 Nov 2024 16:12:50 +0200 Subject: [PATCH 52/68] Keep original text in translate --- webapp/src/clj/lipas/backend/ptv/core.clj | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/webapp/src/clj/lipas/backend/ptv/core.clj b/webapp/src/clj/lipas/backend/ptv/core.clj index c678b4371..6daf6f4d0 100644 --- a/webapp/src/clj/lipas/backend/ptv/core.clj +++ b/webapp/src/clj/lipas/backend/ptv/core.clj @@ -37,7 +37,10 @@ [doc] (-> (ai/translate-to-other-langs doc) :message - :content)) + :content + ;; Ensure the original from texts are kept as-is + (assoc-in [:summary (keyword (:from doc))] (:summary doc)) + (assoc-in [:description (keyword (:from doc))] (:description doc)))) (defn make-overview [sites] From 7c9766c71fb4f9659c736aeefe5f6a083b4c41ce Mon Sep 17 00:00:00 2001 From: Juho Teperi Date: Wed, 13 Nov 2024 17:04:01 +0200 Subject: [PATCH 53/68] Create missing services for ptv location in BE etc. --- webapp/dev/user.clj | 11 ++- webapp/src/clj/lipas/backend/core.clj | 90 ++++++++++--------- webapp/src/clj/lipas/backend/handler.clj | 4 +- webapp/src/clj/lipas/backend/ptv/core.clj | 89 +++++++++++++++++- .../src/clj/lipas/backend/ptv/integration.clj | 31 ++++--- webapp/src/clj/lipas/maintenance.clj | 8 +- webapp/src/cljc/lipas/data/ptv.cljc | 28 +++++- webapp/src/cljs/lipas/ui/ptv/events.cljs | 28 +++--- webapp/test/clj/lipas/backend/ptv_test.clj | 1 + 9 files changed, 209 insertions(+), 81 deletions(-) diff --git a/webapp/dev/user.clj b/webapp/dev/user.clj index 887bbe878..ef02284db 100644 --- a/webapp/dev/user.clj +++ b/webapp/dev/user.clj @@ -36,6 +36,11 @@ (assert-running-system) (:lipas/search (current-system))) +(defn ptv + [] + (assert-running-system) + (:lipas/ptv (current-system))) + (defn reindex-search! [] ((requiring-resolve 'lipas.backend.search-indexer/main) (db) (search) "search")) @@ -70,9 +75,9 @@ (def robot (core/get-user (db) "robot@lipas.fi")) - (maintenance/merge-types (db) (search) robot 4530 4510) - (maintenance/merge-types (db) (search) robot 4520 4510) - (maintenance/merge-types (db) (search) robot 4310 4320) + (maintenance/merge-types (db) (search) (ptv) robot 4530 4510) + (maintenance/merge-types (db) (search) (ptv) robot 4520 4510) + (maintenance/merge-types (db) (search) (ptv) robot 4310 4320) (require '[lipas.data.types :as types]) (require '[lipas.data.types-old :as types-old]) diff --git a/webapp/src/clj/lipas/backend/core.clj b/webapp/src/clj/lipas/backend/core.clj index cb1ea5ae8..56fe22fe2 100644 --- a/webapp/src/clj/lipas/backend/core.clj +++ b/webapp/src/clj/lipas/backend/core.clj @@ -1,35 +1,34 @@ (ns lipas.backend.core - (:require - [buddy.hashers :as hashers] - [cheshire.core :as json] - [clojure.core.async :as async] - [clojure.data.csv :as csv] - [clojure.java.jdbc :as jdbc] - [clojure.string :as str] - [dk.ative.docjure.spreadsheet :as excel] - [lipas.backend.accessibility :as accessibility] - [lipas.backend.analysis.diversity :as diversity] - [lipas.backend.analysis.reachability :as reachability] - [lipas.backend.db.db :as db] - [lipas.backend.elevation :as elevation] - [lipas.backend.email :as email] - [lipas.backend.gis :as gis] - [lipas.backend.jwt :as jwt] - [lipas.backend.newsletter :as newsletter] - [lipas.backend.s3 :as s3] - [lipas.backend.search :as search] - [lipas.data.admins :as admins] - [lipas.data.cities :as cities] - [lipas.data.owners :as owners] - [lipas.data.types :as types] - [lipas.i18n.core :as i18n] - [lipas.integration.utp.cms :as utp-cms] - [lipas.reports :as reports] - [lipas.roles :as roles] - [lipas.utils :as utils] - [taoensso.timbre :as log]) - (:import - [java.io OutputStreamWriter])) + (:require [buddy.hashers :as hashers] + [cheshire.core :as json] + [clojure.core.async :as async] + [clojure.data.csv :as csv] + [clojure.java.jdbc :as jdbc] + [clojure.string :as str] + [dk.ative.docjure.spreadsheet :as excel] + [lipas.backend.accessibility :as accessibility] + [lipas.backend.analysis.diversity :as diversity] + [lipas.backend.analysis.reachability :as reachability] + [lipas.backend.db.db :as db] + [lipas.backend.elevation :as elevation] + [lipas.backend.email :as email] + [lipas.backend.gis :as gis] + [lipas.backend.jwt :as jwt] + [lipas.backend.newsletter :as newsletter] + [lipas.backend.s3 :as s3] + [lipas.backend.search :as search] + [lipas.data.admins :as admins] + [lipas.data.cities :as cities] + [lipas.data.owners :as owners] + [lipas.data.ptv :as ptv-data] + [lipas.data.types :as types] + [lipas.i18n.core :as i18n] + [lipas.integration.utp.cms :as utp-cms] + [lipas.reports :as reports] + [lipas.roles :as roles] + [lipas.utils :as utils] + [taoensso.timbre :as log]) + (:import [java.io OutputStreamWriter])) (def cache "Simple atom cache for things that (hardly) never change." (atom {})) @@ -498,9 +497,9 @@ (defn save-sports-site! "Saves sports-site to db and search and appends it to outbound integrations queue." - ([db search user sports-site] - (save-sports-site! db search user sports-site false)) - ([db search user sports-site draft?] + ([db search ptv user sports-site] + (save-sports-site! db search ptv user sports-site false)) + ([db search ptv user sports-site draft?] (jdbc/with-db-transaction [tx db] (let [resp (upsert-sports-site! tx user sports-site draft?) route? (-> resp :type :type-code types/all :geometry-type #{"LineString"})] @@ -522,16 +521,27 @@ (add-to-webhook-queue! tx {:lipas-ids [(:lipas-id resp)]})) - ;; Sync the updated site to ptv if the ptv integration is enabled + ;; Sync the site to PTV if + ;; - it was previously sent to PTV (we might archive it now if it no longer looks like PTV candidate) + ;; - it is PTV candidate now + ;; - do nothing (keep the previous data in PTV if site was previously sent there) if sync-enabled is false + ;; Note: if site status or something is updated in Lipas, so that the site is no longer candidate, + ;; that doesn't trigger update if sync-enabled is false. (if (and (not draft?) - (:ptv resp) - (:sync-enabled (:ptv resp))) + (:sync-enabled (:ptv resp)) + ;; TODO: Check privilage :ptv/basic or such + (or (ptv-data/ptv-candidate? resp) + (ptv-data/is-sent-to-ptv? resp))) ;; TODO: Currently this will create a new sports-site rev. ;; Make it instead update the sports-site already created in the tx? ;; Otherwise each save-sports-site! will create two sports-site revs. - (let [new-ptv-data (:ptv ((resolve 'lipas.backend.ptv.core/upsert-ptv-service-location!) - tx user - {:org (:org-id (:ptv resp)) + ;; TODO: If this fails, store failure to the site-data so it can be shown on the + ;; UI and user can try again. We don't know how often PTV causes problems, + ;; and the sports-site save should work even if this fails. + (let [new-ptv-data (:ptv ((resolve 'lipas.backend.ptv.core/sync-ptv!) + tx search ptv user + {:sports-site resp + :org-id (:org-id (:ptv resp)) :lipas-id (:lipas-id resp) :ptv (:ptv resp)}))] (log/infof "Sports site updated and PTV integration enabled") diff --git a/webapp/src/clj/lipas/backend/handler.clj b/webapp/src/clj/lipas/backend/handler.clj index 140571aab..a476635d4 100644 --- a/webapp/src/clj/lipas/backend/handler.clj +++ b/webapp/src/clj/lipas/backend/handler.clj @@ -54,7 +54,7 @@ exception-handlers))) (defn create-app - [{:keys [db emailer search mailchimp aws] :as ctx}] + [{:keys [db emailer search mailchimp aws ptv] :as ctx}] (ring/ring-handler (ring/router @@ -121,7 +121,7 @@ valid? (s/valid? spec body-params)] (if valid? {:status 201 - :body (core/save-sports-site! db search identity body-params draft?)} + :body (core/save-sports-site! db search ptv identity body-params draft?)} {:status 400 :body (s/explain-data spec body-params)})))}}] diff --git a/webapp/src/clj/lipas/backend/ptv/core.clj b/webapp/src/clj/lipas/backend/ptv/core.clj index 6daf6f4d0..8d3fca273 100644 --- a/webapp/src/clj/lipas/backend/ptv/core.clj +++ b/webapp/src/clj/lipas/backend/ptv/core.clj @@ -99,7 +99,7 @@ :service-channel-ids]) (defn upsert-ptv-service-location! - [db ptv-component user {:keys [org lipas-id ptv] :as _m}] + [db ptv-component user {:keys [org-id lipas-id ptv] :as _m}] (jdbc/with-db-transaction [tx db] (let [site (db/get-sports-site db lipas-id) _ (assert (some? site) (str "Sports site " lipas-id " not found in DB")) @@ -109,7 +109,7 @@ site (update site :ptv merge ptv) ;; Use the same TS for sourceId, ptv last-sync and site event-date now (utils/timestamp) - data (ptv-data/->ptv-service-location org gis/wgs84->tm35fin-no-wrap now (core/enrich site)) + data (ptv-data/->ptv-service-location org-id gis/wgs84->tm35fin-no-wrap now (core/enrich site)) ptv-resp (if id (ptv/update-service-location ptv-component id data) (ptv/create-service-location ptv-component data)) @@ -117,6 +117,9 @@ new-ptv-data (-> ptv (select-keys persisted-ptv-keys) (assoc :last-sync now + ;; Store the current type-code into ptv data, so this can be + ;; used to comapre if the services need to recalculated on site data update. + :previous-type-code (:type-code (:type site)) :source-id (:sourceId ptv-resp) ;; Store the PTV status so we can ignore Lipas archived places that we already archived in PTV. :publishing-status (:publishingStatus ptv-resp) @@ -144,6 +147,88 @@ (:value x))) (:serviceChannelNames ptv-resp))}}))) +(comment + + (let [ptv-component (:lipas/ptv integrant.repl.state/system) + org-id ptv-data/liminka-org-id-test + services (:itemList (ptv/get-org-services ptv-component org-id))] + (->> services + (utils/index-by :sourceId) + keys))) + +;; Used through resolve due to circular dep +;; TODO: Check if code can be moved around to avoid this +^{:clj-kondo/ignore [:clojure-lsp/unused-public-var]} +(defn sync-ptv! [tx search ptv-component user {:keys [sports-site ptv org-id lipas-id]}] + (let [type-code (-> sports-site :type :type-code) + + previous-sent? (ptv-data/is-sent-to-ptv? sports-site) + candidate-now? (ptv-data/ptv-candidate? sports-site) + + to-archive? (and previous-sent? + (not candidate-now?)) + + ;; TODO: to-archive + ;; 1. set PTV status Deleted + ;; 2. remove :ptv :source-id, :service-channel-ids + + type-code-changed? (not= type-code (:previous-type-code ptv)) + ptv (if type-code-changed? + (let [types types/all + ;; Figure out what services are available in PTV for the site organization + services (:itemList (ptv/get-org-services ptv-component org-id)) + source-id->service (->> services + (utils/index-by :sourceId)) + + ;; Check if services for the current/new site type-code exist + missing-services-input [{:service-ids #{} + :sub-category-id (-> sports-site :type :type-code types :sub-category) + :sub-cateogry (-> sports-site :search-meta :type :sub-category :name :fi)}] + missing-services (ptv-data/resolve-missing-services org-id source-id->service nil missing-services-input) + + _ (log/infof "Missing services? %s" (pr-str missing-services)) + + ;; TODO: Move the check for missing services to UI, so + ;; user can validate the texts. + ;; Go through missing services, create data for them and send to PTV + source-id->service (reduce (fn [acc missing] + (let [x (generate-ptv-service-descriptions search + {:sub-category-id (:sub-category-id missing) + :city-codes [(:city-code (:city (:location sports-site)))]}) + service (-> missing + (assoc :org-id org-id + :city-codes [(:city-code (:city (:location sports-site)))] + ;; :languages ["fi" "se" "en"] + :description (:description x) + :summary (:summary x))) + _ (log/infof "Missing service, generated descriptions: %s" service) + + ;; Hope this returns data in same format as list services... + resp (upsert-ptv-service! ptv-component service)] + (assoc acc (:source-id service) resp))) + source-id->service + missing-services) + + ;; Remove old service-ids from :ptv data and add the new. + ;; Don't touch other service-ids in the data, those could have be added manually in UI or in PTV. + ;; NOTE: OK, PTV updates are likely lost, because our :ptv :service-ids is what the create/update from + ;; Lipas previously returned, so if PTV ServiceLocation was modified after that in PTV, we lose those changes. + old-sports-site (assoc-in sports-site [:type :type-code] (:previous-type-code ptv)) + old-service-ids (ptv-data/sports-site->service-ids types source-id->service old-sports-site) + new-service-ids (ptv-data/sports-site->service-ids types source-id->service sports-site)] + (log/infof "Site type changed %s => %s, service-ids updated %s => %s" + (:previous-type-code ptv) type-code + old-service-ids new-service-ids) + (update ptv :service-ids (fn [x] + (->> x + (remove (fn [y] (contains? old-service-ids y))) + (into new-service-ids))))) + ptv) + resp (upsert-ptv-service-location! tx ptv-component user {:org-id org-id + :ptv ptv + :lipas-id lipas-id})] + resp)) + (defn save-ptv-integration-definitions "Saves ptv definitions under key :ptv. Does not notify webhooks, integrations or analysis queues since they're not likely interested diff --git a/webapp/src/clj/lipas/backend/ptv/integration.clj b/webapp/src/clj/lipas/backend/ptv/integration.clj index d6a2c75ee..8374fbac7 100644 --- a/webapp/src/clj/lipas/backend/ptv/integration.clj +++ b/webapp/src/clj/lipas/backend/ptv/integration.clj @@ -77,15 +77,17 @@ ;; NOTE: deref + swap (let [x (get @(:tokens ptv) org-id)] (if (or (not x) (expired? (:payload x))) - (let [new-token (authenticate (merge {:token-url (:token-url ptv) - :username (get-in ptv [:creds :api :username]) - :password (get-in ptv [:creds :api :password]) - :org-id org-id} - (when (= "test" (:env ptv)) - (get-test-credentials org-id)))) + (let [token-props (merge {:token-url (:token-url ptv) + :username (get-in ptv [:creds :api :username]) + :password (get-in ptv [:creds :api :password]) + :org-id org-id} + (when (= "test" (:env ptv)) + (get-test-credentials org-id))) + new-token (authenticate token-props) + payload (parse-payload new-token) x {:token new-token - :payload (parse-payload new-token)}] - (log/infof "Create token %s => %s" org-id new-token) + :payload payload}] + (log/infof "Create token %s => %s (%s)" org-id new-token payload) (swap! (:tokens ptv) assoc org-id x) (:token x)) (:token x)))) @@ -95,7 +97,6 @@ ([ptv auth-org-id req retried?] (let [token (get-token ptv auth-org-id) req* (-> req - (dissoc :auth-org-id) (assoc :accept :json :as :json) (assoc-in [:headers :Authorization] (str "bearer " token))) @@ -157,8 +158,9 @@ (defn create-service [ptv - {:keys [org-id] :as service}] - (let [params {:url (make-url ptv "/v11/Service") + service] + (let [org-id (:mainResponsibleOrganization service) + params {:url (make-url ptv "/v11/Service") :method :post :form-params service}] (log/infof "Create PTV service %s" service) @@ -175,9 +177,10 @@ (defn update-service [ptv service-id - {:keys [org-id] :as data}] + data] (log/info "Update PTV service with id " service-id "and data" data) - (let [params {:url (make-url ptv "/v11/Service/" service-id) + (let [org-id (:mainResponsibleOrganization data) + params {:url (make-url ptv "/v11/Service/" service-id) :method :put :form-params data}] (-> (http ptv org-id params) @@ -196,7 +199,7 @@ (defn update-service-location [ptv service-location-id data] - (let [org-id (-> data :organization :id) + (let [org-id (-> data :organizationId) params {:url (make-url ptv "/v11/ServiceChannel/ServiceLocation/" service-location-id) :method :put :form-params data}] diff --git a/webapp/src/clj/lipas/maintenance.clj b/webapp/src/clj/lipas/maintenance.clj index 08bfe6628..b03ac9be0 100644 --- a/webapp/src/clj/lipas/maintenance.clj +++ b/webapp/src/clj/lipas/maintenance.clj @@ -23,7 +23,7 @@ [taoensso.timbre :as log])) (defn merge-types - [db search user type-code-from type-code-to] + [db search ptv user type-code-from type-code-to] (let [types* (merge old-types/all types/all)] (assert (contains? types* type-code-from)) (assert (contains? types/all type-code-to)) @@ -33,11 +33,11 @@ (log/info "Migrating" (count sites) "type" type-code-from " -> " type-code-to) (doseq [site sites] (log/info "Migrating" (:lipas-id site)) - (core/save-sports-site! db search user (assoc-in site [:type :type-code] type-code-to))) + (core/save-sports-site! db search ptv user (assoc-in site [:type :type-code] type-code-to))) (log/info "All done!"))) (defn duplicate-point->area-draft - [db search user type-code-from type-code-to] + [db search ptv user type-code-from type-code-to] (let [types* (merge old-types/all types/all)] (assert (contains? types* type-code-from)) (assert (contains? types/all type-code-to)) @@ -47,7 +47,7 @@ (log/info "Migrating" (count sites) "type" type-code-from "(Point) ->" type-code-to "(Polygon)") (doseq [site sites] (log/info "Migrating" (:lipas-id site)) - (core/save-sports-site! db search user + (core/save-sports-site! db search ptv user (-> site (dissoc :lipas-id) (assoc :event-date (utils/timestamp)) diff --git a/webapp/src/cljc/lipas/data/ptv.cljc b/webapp/src/cljc/lipas/data/ptv.cljc index a294a75f4..c85d6509d 100644 --- a/webapp/src/cljc/lipas/data/ptv.cljc +++ b/webapp/src/cljc/lipas/data/ptv.cljc @@ -163,7 +163,7 @@ {:organizationId (:org-id ptv) ;; Keep using existing sourceId for sites that were already initialized in PTV, ;; generate a new unique ID (with timestamp) for new sites. - :sourceId (or (:sourceId ptv) + :sourceId (or (:source-id ptv) (let [ts (str/replace now #":" "-") x (str "lipas-" (:org-id ptv) "-" lipas-id "-" ts)] (log/infof "Creating new PTV source-id %s" x) @@ -437,3 +437,29 @@ (resolve-service-channel-name)) :service-channel-integration (or (-> site :ptv :service-channel-integration) (:service-channel-integration org-defaults))})) + +(defn sports-site->service-ids [types source-id->service sports-site] + (let [sub-cat-id (-> sports-site :type :type-code types :sub-category) + org-id (-> sports-site :ptv :org-id) + source-id (str "lipas-" org-id "-" sub-cat-id)] + (when-let [service (get source-id->service source-id)] + #{(:id service)}))) + +(defn is-sent-to-ptv? + "Check if the :ptv data shows that the site has been sent to PTV previously" + [site] + (let [{:keys [ptv]} site] + (and (-> ptv :service-channel-ids first) + (:source-id ptv) + (= "Published" (:publishing-status ptv))))) + +(defn ptv-candidate? + "Does the site look like it should be sent to the ptv?" + [site] + (let [{:keys [status ptv]} site + {:keys [summary description]} ptv + type-code (-> site :type :type-code)] + (boolean (and (not (contains? #{"incorrect-data" "out-of-service-permanently"} status)) + (some-> description :fi count (> 5)) + (some-> summary :fi count (> 5)) + (#{7000} type-code))))) diff --git a/webapp/src/cljs/lipas/ui/ptv/events.cljs b/webapp/src/cljs/lipas/ui/ptv/events.cljs index d962c2b54..7cc634778 100644 --- a/webapp/src/cljs/lipas/ui/ptv/events.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/events.cljs @@ -589,21 +589,19 @@ (fn [db _] (let [org-id (get-in db [:ptv :selected-org :id]) types (get-in db [:sports-sites :types]) - services (->> (get-in db [:ptv :org org-id :data :services]) - vals - (utils/index-by :sourceId))] - (-> db - (update-in [:ptv :org org-id :data :sports-sites] - (fn [m] - (reduce-kv - (fn [m lipas-id sports-site] - (let [sub-cat-id (-> sports-site :type :type-code types :sub-category) - source-id (str "lipas-" org-id "-" sub-cat-id)] - (if-let [service (get services source-id)] - (update-in m [lipas-id :ptv :service-ids] #(set (conj % (:id service)))) - m))) - m - m))))))) + source-id->service (->> (get-in db [:ptv :org org-id :data :services]) + vals + (utils/index-by :sourceId)) + sports-sites (get-in db [:ptv :org org-id :data :sports-sites]) + sports-sites (reduce-kv + (fn [sports-sites lipas-id sports-site] + (let [service-ids (ptv-data/sports-site->service-ids types source-id->service sports-site)] + (if (seq service-ids) + (update-in sports-sites [lipas-id :ptv :service-ids] (fnil into #{}) service-ids) + sports-sites))) + sports-sites + sports-sites)] + (assoc-in db [:ptv :org org-id :data :sports-sites] sports-sites)))) ;;; Create service locations in PTV ;;; diff --git a/webapp/test/clj/lipas/backend/ptv_test.clj b/webapp/test/clj/lipas/backend/ptv_test.clj index 27a3b5336..6b632e1ce 100644 --- a/webapp/test/clj/lipas/backend/ptv_test.clj +++ b/webapp/test/clj/lipas/backend/ptv_test.clj @@ -124,5 +124,6 @@ (is (some? (:last-sync (:ptv body)))) (is (= "Published" (:publishing-status (:ptv body)))))) + ;; TODO: Archive the site in Lipas and PTV )) From 586771489ccc141adebf4be0cbcb4a9ad239bbb8 Mon Sep 17 00:00:00 2001 From: Juho Teperi Date: Thu, 14 Nov 2024 15:19:24 +0200 Subject: [PATCH 54/68] Fix --- webapp/src/cljc/lipas/data/ptv.cljc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/src/cljc/lipas/data/ptv.cljc b/webapp/src/cljc/lipas/data/ptv.cljc index c85d6509d..3207867b5 100644 --- a/webapp/src/cljc/lipas/data/ptv.cljc +++ b/webapp/src/cljc/lipas/data/ptv.cljc @@ -462,4 +462,4 @@ (boolean (and (not (contains? #{"incorrect-data" "out-of-service-permanently"} status)) (some-> description :fi count (> 5)) (some-> summary :fi count (> 5)) - (#{7000} type-code))))) + (not (#{7000} type-code)))))) From 3c4abef199201ff0277166a9ee9d6aa0c7d38e39 Mon Sep 17 00:00:00 2001 From: Juho Teperi Date: Thu, 14 Nov 2024 15:30:26 +0200 Subject: [PATCH 55/68] Archive site in PTV if updated to non PTV candidate in Lipas and create new PTV site if updated so site looks like PTV candidate --- webapp/src/clj/lipas/backend/ptv/core.clj | 14 ++++++++++---- webapp/src/cljc/lipas/data/ptv.cljc | 6 +++--- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/webapp/src/clj/lipas/backend/ptv/core.clj b/webapp/src/clj/lipas/backend/ptv/core.clj index 8d3fca273..3e8d7770e 100644 --- a/webapp/src/clj/lipas/backend/ptv/core.clj +++ b/webapp/src/clj/lipas/backend/ptv/core.clj @@ -99,7 +99,7 @@ :service-channel-ids]) (defn upsert-ptv-service-location! - [db ptv-component user {:keys [org-id lipas-id ptv] :as _m}] + [db ptv-component user {:keys [org-id lipas-id ptv archive?] :as _m}] (jdbc/with-db-transaction [tx db] (let [site (db/get-sports-site db lipas-id) _ (assert (some? site) (str "Sports site " lipas-id " not found in DB")) @@ -110,6 +110,8 @@ ;; Use the same TS for sourceId, ptv last-sync and site event-date now (utils/timestamp) data (ptv-data/->ptv-service-location org-id gis/wgs84->tm35fin-no-wrap now (core/enrich site)) + data (cond-> data + archive? (assoc :publishingStatus "Deleted")) ptv-resp (if id (ptv/update-service-location ptv-component id data) (ptv/create-service-location ptv-component data)) @@ -125,7 +127,10 @@ :publishing-status (:publishingStatus ptv-resp) ;; Take the created ID from ptv response and store to Lipas DB right away. ;; TODO: Is there a case where this could be multiple ids? - :service-channel-ids (set [(:id ptv-resp)])))] + :service-channel-ids (set [(:id ptv-resp)])) + (cond-> + archive? (dissoc :source-id + :service-channel-ids)))] (log/infof "Upserted (Lipas status: %s, updated: %s) service-location %s: %s" (:status site) (boolean id) data new-ptv-data) @@ -170,7 +175,7 @@ ;; TODO: to-archive ;; 1. set PTV status Deleted - ;; 2. remove :ptv :source-id, :service-channel-ids + ;; 2. remove :ptv :source-id, :service-channel-ids -> if restored, a new service-location is created type-code-changed? (not= type-code (:previous-type-code ptv)) ptv (if type-code-changed? @@ -226,7 +231,8 @@ ptv) resp (upsert-ptv-service-location! tx ptv-component user {:org-id org-id :ptv ptv - :lipas-id lipas-id})] + :lipas-id lipas-id + :archive? to-archive?})] resp)) (defn save-ptv-integration-definitions diff --git a/webapp/src/cljc/lipas/data/ptv.cljc b/webapp/src/cljc/lipas/data/ptv.cljc index 3207867b5..dd2493965 100644 --- a/webapp/src/cljc/lipas/data/ptv.cljc +++ b/webapp/src/cljc/lipas/data/ptv.cljc @@ -143,7 +143,7 @@ })) (defn ->ptv-service-location - [org + [_org coord-transform-fn now {:keys [status ptv lipas-id location search-meta] :as sports-site}] @@ -152,8 +152,8 @@ (->> (map lipas-lang->ptv-lang)) set) type (get types/all (get-in sports-site [:type :type-code])) - sub-cat (get types/sub-categories (:sub-category type)) - main-cat (get types/main-categories (:main-category type))] + _sub-cat (get types/sub-categories (:sub-category type)) + _main-cat (get types/main-categories (:main-category type))] (println "PTV data") (prn ptv) From 48940d53fbc10fc04c2b99b7813072e573f5b26d Mon Sep 17 00:00:00 2001 From: Juho Teperi Date: Thu, 14 Nov 2024 15:38:36 +0200 Subject: [PATCH 56/68] Check owner field when checking if site is ptv candidate --- webapp/src/cljc/lipas/data/ptv.cljc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/webapp/src/cljc/lipas/data/ptv.cljc b/webapp/src/cljc/lipas/data/ptv.cljc index dd2493965..1e278f28a 100644 --- a/webapp/src/cljc/lipas/data/ptv.cljc +++ b/webapp/src/cljc/lipas/data/ptv.cljc @@ -456,10 +456,11 @@ (defn ptv-candidate? "Does the site look like it should be sent to the ptv?" [site] - (let [{:keys [status ptv]} site + (let [{:keys [status ptv owner]} site {:keys [summary description]} ptv type-code (-> site :type :type-code)] (boolean (and (not (contains? #{"incorrect-data" "out-of-service-permanently"} status)) (some-> description :fi count (> 5)) (some-> summary :fi count (> 5)) + (#{"city" "city-main-owner"} owner) (not (#{7000} type-code)))))) From b3766a64eb01247612601bc895b1822371943964 Mon Sep 17 00:00:00 2001 From: Juho Teperi Date: Tue, 19 Nov 2024 14:15:19 +0200 Subject: [PATCH 57/68] Create missing service from PTV site view tab --- webapp/src/clj/lipas/backend/handler.clj | 7 +- webapp/src/clj/lipas/backend/ptv/core.clj | 17 +- webapp/src/clj/lipas/backend/ptv/handler.clj | 31 ++- webapp/src/cljc/lipas/data/ptv.cljc | 5 +- webapp/src/cljs/lipas/ui/ptv/events.cljs | 80 +++--- webapp/src/cljs/lipas/ui/ptv/site_view.cljs | 242 ++++++++++++++++--- webapp/src/cljs/lipas/ui/ptv/subs.cljs | 91 +++---- webapp/src/cljs/lipas/ui/ptv/views.cljs | 31 ++- webapp/test/clj/lipas/backend/ptv_test.clj | 1 - 9 files changed, 358 insertions(+), 147 deletions(-) diff --git a/webapp/src/clj/lipas/backend/handler.clj b/webapp/src/clj/lipas/backend/handler.clj index a476635d4..28c8b11bc 100644 --- a/webapp/src/clj/lipas/backend/handler.clj +++ b/webapp/src/clj/lipas/backend/handler.clj @@ -45,7 +45,12 @@ ;; Return 500 and print stack trace for exceptions that are not ;; specifically handled - ::exception/default (exception-handler 500 :internal-server-error :print-stack)}) + ::exception/default (exception-handler 500 :internal-server-error :print-stack) + + :reitit.coercion/request-coercion (let [handler (:reitit.coercion/request-coercion exception/default-handlers)] + (fn [e x] + (log/errorf e "Request coercion error") + (handler e x)))}) (def exceptions-mw (exception/create-exception-middleware diff --git a/webapp/src/clj/lipas/backend/ptv/core.clj b/webapp/src/clj/lipas/backend/ptv/core.clj index 3e8d7770e..bbe0a8711 100644 --- a/webapp/src/clj/lipas/backend/ptv/core.clj +++ b/webapp/src/clj/lipas/backend/ptv/core.clj @@ -51,13 +51,14 @@ (defn generate-ptv-service-descriptions [search - {:keys [_id sub-category-id city-codes]}] - (let [type-codes (->> (types/by-sub-category sub-category-id) - (map :type-code)) - sites (ptv/get-eligible-sites search {:type-codes type-codes - :city-codes city-codes - :owners ["city" "city-main-owner"]}) - doc (make-overview sites)] + {:keys [_id sub-category-id city-codes overview]}] + (let [doc (or overview + (let [type-codes (->> (types/by-sub-category sub-category-id) + (map :type-code)) + sites (ptv/get-eligible-sites search {:type-codes type-codes + :city-codes city-codes + :owners ["city" "city-main-owner"]})] + (make-overview sites)))] (-> (ai/generate-ptv-service-descriptions doc) :message :content))) @@ -189,7 +190,7 @@ missing-services-input [{:service-ids #{} :sub-category-id (-> sports-site :type :type-code types :sub-category) :sub-cateogry (-> sports-site :search-meta :type :sub-category :name :fi)}] - missing-services (ptv-data/resolve-missing-services org-id source-id->service nil missing-services-input) + missing-services (ptv-data/resolve-missing-services org-id source-id->service missing-services-input) _ (log/infof "Missing services? %s" (pr-str missing-services)) diff --git a/webapp/src/clj/lipas/backend/ptv/handler.clj b/webapp/src/clj/lipas/backend/ptv/handler.clj index 11934ea96..ab5ce99b9 100644 --- a/webapp/src/clj/lipas/backend/ptv/handler.clj +++ b/webapp/src/clj/lipas/backend/ptv/handler.clj @@ -84,11 +84,26 @@ ["/actions/generate-ptv-service-descriptions" {:post {:require-privilege :ptv/manage - :parameters {:body [:any]} + :parameters {:body [:map + [:org-id :string] + [:city-codes [:vector :int]] + [:owners [:vector :string]] + [:supported-languages [:vector [:enum "fi" "se" "en"]]] + [:sourceId :string] + [:sub-category-id :int] + [:overview {:optional true + :description "Use this to replace the AI input with non-saved site information"} + [:maybe + [:map + [:city-name (localized-string-schema nil)] + [:service-name (localized-string-schema nil)] + [:sports-facilties [:vector + [:map + [:type :string]]]]]]]]} :handler - (fn [{:keys [body-params]}] + (fn [req] {:status 200 - :body (ptv-core/generate-ptv-service-descriptions search body-params)})}}] + :body (ptv-core/generate-ptv-service-descriptions search (-> req :parameters :body))})}}] ["/actions/fetch-ptv-org" {:post @@ -112,9 +127,15 @@ ["/actions/save-ptv-service" {:post - ;; FIXME: Schema {:require-privilege :ptv/manage - :parameters {:body [:any]} + :parameters {:body [:map + [:org-id :string] + [:city-codes [:vector :int]] + [:source-id :string] + [:sub-category-id :int] + [:languages [:vector [:enum "fi" "se" "en"]]] + [:summary (localized-string-schema {:max 150})] + [:description (localized-string-schema nil)]]} :handler (fn [{:keys [body-params]}] {:status 200 diff --git a/webapp/src/cljc/lipas/data/ptv.cljc b/webapp/src/cljc/lipas/data/ptv.cljc index 1e278f28a..7016ad335 100644 --- a/webapp/src/cljc/lipas/data/ptv.cljc +++ b/webapp/src/cljc/lipas/data/ptv.cljc @@ -331,7 +331,7 @@ (defn resolve-missing-services "Infer services (sub-categories) that need to be created in PTV and attached to sports-sites." - [org-id services _types sports-sites] + [org-id services sports-sites] (let [source-ids (->> services vals (keep :sourceId) set)] (->> sports-sites (filter (fn [{:keys [ptv]}] (empty? (:service-ids ptv)))) @@ -341,6 +341,9 @@ distinct (remove (fn [m] (contains? source-ids (:source-id m))))))) +(defn sub-category-id->service [org-id source-id->service sub-category-id] + (get source-id->service (->service-source-id org-id sub-category-id))) + (defn parse-summary "Returns first line-delimited paragraph." [s] diff --git a/webapp/src/cljs/lipas/ui/ptv/events.cljs b/webapp/src/cljs/lipas/ui/ptv/events.cljs index 7cc634778..97aa1153b 100644 --- a/webapp/src/cljs/lipas/ui/ptv/events.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/events.cljs @@ -78,16 +78,18 @@ (rf/reg-event-fx ::fetch-org (fn [{:keys [db]} [_ org]] - (when org - {:db (assoc-in db [:ptv :loading-from-ptv :org] true) - :fx [[:http-xhrio - {:method :post - :uri (str (:backend-url db) "/actions/fetch-ptv-org") - :params {:org-id (:id org)} - :format (ajax/transit-request-format) - :response-format (ajax/transit-response-format) - :on-success [::fetch-org-success (:id org)] - :on-failure [::fetch-org-failure]}]]}))) + (let [token (-> db :user :login :token)] + (when org + {:db (assoc-in db [:ptv :loading-from-ptv :org] true) + :fx [[:http-xhrio + {:method :post + :headers {:Authorization (str "Token " token)} + :uri (str (:backend-url db) "/actions/fetch-ptv-org") + :params {:org-id (:id org)} + :format (ajax/transit-request-format) + :response-format (ajax/transit-response-format) + :on-success [::fetch-org-success (:id org)] + :on-failure [::fetch-org-failure]}]]})))) (rf/reg-event-fx ::fetch-org-success (fn [{:keys [db]} [_ org-id resp]] @@ -425,9 +427,8 @@ ;;; Service descriptions generation ;;; (rf/reg-event-fx ::generate-service-descriptions - (fn [{:keys [db]} [_ id success-fx failure-fx]] - (let [token (-> db :user :login :token) - org-id (-> db :ptv :selected-org :id)] + (fn [{:keys [db]} [_ org-id id overview success-fx failure-fx]] + (let [token (-> db :user :login :token)] {:db (assoc-in db [:ptv :loading-from-lipas :service-descriptions] true) :fx [[:http-xhrio {:method :post @@ -437,22 +438,22 @@ :params (merge (org-id->params org-id) {:sourceId id - :sub-category-id (parse-long (last (str/split id #"-")))}) + :sub-category-id (parse-long (last (str/split id #"-"))) + :overview overview}) :format (ajax/transit-request-format) :response-format (ajax/transit-response-format) - :on-success [::generate-service-descriptions-success id success-fx] - :on-failure [::generate-service-descriptions-failure id failure-fx]}]]}))) + :on-success [::generate-service-descriptions-success org-id id success-fx] + :on-failure [::generate-service-descriptions-failure org-id id failure-fx]}]]}))) (rf/reg-event-fx ::generate-service-descriptions-success - (fn [{:keys [db]} [_ id extra-fx resp]] - (let [org-id (get-in db [:ptv :selected-org :id])] - {:db (-> db - (assoc-in [:ptv :loading-from-lipas :lipas-managed-service-descriptions] false) - (update-in [:ptv :org org-id :data :service-candidates id] merge resp)) - :fx extra-fx}))) + (fn [{:keys [db]} [_ org-id id extra-fx resp]] + {:db (-> db + (assoc-in [:ptv :loading-from-lipas :lipas-managed-service-descriptions] false) + (update-in [:ptv :org org-id :data :service-candidates id] merge resp)) + :fx extra-fx})) (rf/reg-event-fx ::generate-service-descriptions-failure - (fn [{:keys [db]} [_ _id extra-fx resp]] + (fn [{:keys [db]} [_ _org-id _id extra-fx resp]] (let [tr (:translator db) notification {:message (tr :notifications/get-failed) :success? false}] @@ -477,7 +478,9 @@ :halt? halt?})) :fx [(when (and (not halt?) (seq ids)) [:dispatch [::generate-service-descriptions + org-id (first ids) + nil on-single-success on-single-failure]])]}))) @@ -511,33 +514,32 @@ ;;; Create Services in PTV ;;; (rf/reg-event-fx ::create-ptv-service - (fn [{:keys [db]} [_ id success-fx failure-fx]] - (let [token (-> db :user :login :token) - org-id (-> db :ptv :selected-org :id) - data (-> (get-in db [:ptv :services-creation :data id]))] + (fn [{:keys [db]} [_ org-id id data success-fx failure-fx]] + (let [token (-> db :user :login :token)] {:db (assoc-in db [:ptv :loading-from-lipas :services] true) :fx [[:http-xhrio {:method :post :headers {:Authorization (str "Token " token)} :uri (str (:backend-url db) "/actions/save-ptv-service") + ;; FIXME: org-id->params adds some extra keys that aren't used? + ;; supported-languages (languages is used instead) :params (merge data (org-id->params org-id)) :format (ajax/transit-request-format) :response-format (ajax/transit-response-format) - :on-success [::create-ptv-service-success id success-fx] - :on-failure [::create-ptv-service-failure id failure-fx]}]]}))) + :on-success [::create-ptv-service-success org-id id success-fx] + :on-failure [::create-ptv-service-failure org-id id failure-fx]}]]}))) (rf/reg-event-fx ::create-ptv-service-success - (fn [{:keys [db]} [_ id extra-fx resp]] - (let [org-id (get-in db [:ptv :selected-org :id])] - {:db (-> db - (assoc-in [:ptv :loading-from-lipas :services] false) - (assoc-in [:ptv :org org-id :data :services (:id resp)] resp) - (update-in [:ptv :org org-id :data :service-candidates id] - assoc :created-in-ptv true)) - :fx extra-fx}))) + (fn [{:keys [db]} [_ org-id id extra-fx resp]] + {:db (-> db + (assoc-in [:ptv :loading-from-lipas :services] false) + (assoc-in [:ptv :org org-id :data :services (:id resp)] resp) + (update-in [:ptv :org org-id :data :service-candidates id] + assoc :created-in-ptv true)) + :fx extra-fx})) (rf/reg-event-fx ::create-ptv-service-failure - (fn [{:keys [db]} [_ _id extra-fx resp]] + (fn [{:keys [db]} [_ _org-id _id extra-fx resp]] (let [tr (:translator db) notification {:message (tr :notifications/get-failed) :success? false}] @@ -563,7 +565,9 @@ :halt? halt?})) :fx [(when (and (not halt?) (seq ids)) [:dispatch [::create-ptv-service + org-id (first ids) + (get-in db [:ptv :services-creation :data (first ids)]) on-single-success on-single-failure]])]}))) diff --git a/webapp/src/cljs/lipas/ui/ptv/site_view.cljs b/webapp/src/cljs/lipas/ui/ptv/site_view.cljs index 9f7651a3a..b03b777e8 100644 --- a/webapp/src/cljs/lipas/ui/ptv/site_view.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/site_view.cljs @@ -3,53 +3,209 @@ ["@mui/material/Button$default" :as Button] ["@mui/material/CircularProgress$default" :as CircularProgress] ["@mui/material/FormControl$default" :as FormControl] + ["@mui/material/FormControlLabel$default" :as FormControlLabel] ["@mui/material/FormLabel$default" :as FormLabel] + ["@mui/material/Paper$default" :as Paper] ["@mui/material/Stack$default" :as Stack] + ["@mui/material/Switch$default" :as Switch] ["@mui/material/Typography$default" :as Typography] + [lipas.data.ptv :as ptv-data] + [lipas.data.types :as types] [lipas.ui.components :as lui] [lipas.ui.ptv.controls :as controls] [lipas.ui.ptv.events :as events] [lipas.ui.ptv.subs :as subs] [lipas.ui.uix.hooks :refer [use-subscribe]] + [lipas.utils :as utils] [re-frame.core :as rf] [reagent.core :as r] [uix.core :as uix :refer [$ defui]])) +(defui new-service-form [{:keys [org-id tr service data]}] + (let [{:keys [source-id sub-category-id]} service + loading? false + read-only? false + + [selected-tab set-selected-tab] (uix/use-state :fi) + + org-languages (use-subscribe [::subs/org-languages org-id]) + service-candidate-descriptions (use-subscribe [::subs/service-candidate-descriptions org-id]) + {:keys [summary description]} (get service-candidate-descriptions source-id) + + city (use-subscribe [:lipas.ui.sports-sites.subs/city (-> data :location :city :city-code)]) + type-data (use-subscribe [:lipas.ui.sports-sites.subs/type-by-type-code (-> data :type :type-code)]) + overview {:city-name (:name city) + :service-name (:name (get types/sub-categories sub-category-id)) + :sports-facilties [{:type (-> type-data :name :fi)}]}] + ($ Paper + {:sx #js {:p 2}} + + ($ Stack + {:direction "column" + :sx #js {:gap 2}} + ($ Typography + {:variant "h5"} + "Luo " + (:fi (:name (get types/sub-categories sub-category-id)))) + + ($ Stack + {:sx #js {:position "relative"}} + ($ Button + {:disabled (or loading? + read-only?) + :variant "outlined" + :on-click (fn [_e] + (rf/dispatch [::events/generate-service-descriptions org-id source-id overview [] []]))} + (tr :ptv.actions/generate-with-ai)) + (when loading? + ($ CircularProgress + {:size 24 + :sx #js {:position "absolute" + :top "50%" + :left "50%" + :mt "-12px"}}))) + + ($ controls/lang-selector + {:value selected-tab + :on-change set-selected-tab}) + + ;; Summary + (r/as-element + [lui/text-field + {:disabled (or loading? + read-only?) + :multiline true + :variant "outlined" + :on-change (fn [v] + ) + :label "Tiivistelmä" + :value (get summary selected-tab)}]) + + ;; Description + (r/as-element + [lui/text-field + {:disabled (or loading? + read-only?) + :variant "outlined" + :rows 5 + :multiline true + :on-change (fn [v] + ) + :label "Kuvaus" + :value (get description selected-tab)}]) + + ($ Button + {:variant "contained" + :disabled (or loading? + read-only?) + :on-click (fn [_e] + (let [data {:source-id source-id + :sub-category-id sub-category-id + :summary summary + :description description + :languages (vec org-languages)}] + (rf/dispatch [::events/create-ptv-service org-id source-id data [] []])))} + "Luo Palvelu")) + ))) + (defui site-view [{:keys [tr lipas-id can-edit? edit-data]}] (let [[selected-tab set-selected-tab] (uix/use-state :fi) editing* (boolean (use-subscribe [:lipas.ui.sports-sites.subs/editing? lipas-id])) editing? (and can-edit? editing*) read-only? (not editing?) - site (use-subscribe [:lipas.ui.sports-sites.subs/latest-rev lipas-id]) + sports-site (use-subscribe [:lipas.ui.sports-sites.subs/latest-rev lipas-id]) + + ;; FIXME: Edit-data and sports-site schema can be a bit different? + x (if editing? + edit-data + sports-site) + + _ (js/console.log edit-data sports-site) + + {:keys [descriptions-integration org-id sync-enabled last-sync publishing-status]} (:ptv x) + + _ (js/console.log org-id) ;; default-settings {} - enabled (boolean (:ptv site)) - descriptions-enabled (not= "manual" (:descriptions-integration (:ptv site))) + ;; enabled (boolean (:ptv site)) + descriptions-enabled (not= "manual" descriptions-integration) + + loading? (use-subscribe [::subs/generating-descriptions?]) + + type-code (-> x :type :type-code) + + type-code-changed? (not= type-code (:previous-type-code (:ptv x))) + previous-sent? (ptv-data/is-sent-to-ptv? x) + candidate-now? (ptv-data/ptv-candidate? x) + + types (use-subscribe [:lipas.ui.sports-sites.subs/all-types]) + services (use-subscribe [::subs/services-by-id org-id]) + missing-services-input [{:service-ids #{} + :sub-category-id (-> x :type :type-code types :sub-category) + :sub-category (-> x :search-meta :type :sub-category :name :fi)}] + missing-services (ptv-data/resolve-missing-services org-id services missing-services-input) + + source-id->service (utils/index-by :sourceId (vals services)) + new-service (ptv-data/sub-category-id->service org-id source-id->service (-> x :type :type-code types :sub-category)) + + to-archive? (and previous-sent? + (not candidate-now?))] + + (js/console.log missing-services new-service) + + (uix/use-effect (fn [] + (rf/dispatch [::events/fetch-org {:id org-id}]) + (rf/dispatch [::events/fetch-services {:id org-id}])) + [org-id]) - loading? (use-subscribe [::subs/generating-descriptions?])] ($ Stack {:direction "column" :sx #js {:gap 2}} - (when (not enabled) - ($ Alert - {:severity "warning"} - "PTV integraatio ei käytössä tälle paikalle, käytä PTV käyttöönotto wizardia PTV palvelun alustamiseen.")) + (cond + (and previous-sent? candidate-now?) + (if sync-enabled + ($ Alert {:severity "success"} "PTV integraatio käytössä") + ($ Alert {:severity "success"} "PTV integraatio käytössä, mutta paikan synkronointi PTV on kytketty pois päältä.")) - ($ FormControl - ($ FormLabel - "Lipas tila") - ($ Typography - (:status site))) + (and previous-sent? (not candidate-now?)) + ($ Alert {:severity "warning"} "Paikka on viety PTV, mutta on muutettu niin että näyttää nyt siltä että sen ei pidä mennä PTV -> PTV palvelu paikka arkistoidaan tallennuksessa.") + + candidate-now? + ($ Alert {:sevierty "info"} "Paikkaa ei viety PTV, mutta palvelu paikka luodaan tallennuksessa") + + :else + ($ Alert {:severity "warning"} "Paikka näyttää siltä ettei sitä pidä viedä PTV")) + + (when candidate-now? + (cond + (seq missing-services) + ($ Alert {:severity "warning"} "Lipas tyyppi muuttuu, service puuttuu PTV") + + type-code-changed? + ($ Alert {:severity "info"} "Lipas tyyppi muuttuu, uusi service " (:id new-service)))) + + ; ($ FormControl + ; ($ FormLabel + ; "Lipas tila") + ; ($ Typography + ; status)) + + (when (seq missing-services) + ($ new-service-form + {:data x + :tr tr + :org-id org-id + :service (first missing-services)})) ($ FormControl ($ FormLabel "PTV Tila") ($ Typography - (:publishing-status (:ptv site))) + publishing-status) ($ Typography - (:last-sync (:ptv site)))) + last-sync)) #_ ($ controls/description-integration @@ -57,25 +213,35 @@ :on-change identity :tr tr}) - (when (= "lipas-managed-ptv-fields" (:descriptions-integration (:ptv site))) - ($ Stack - {:sx #js {:position "relative"}} - ($ Button - {:disabled (or loading? - read-only?) - :variant "outlined" - ;; NOTE: Could use the lipas-id version when not editing? But then we don't have - ;; place to store the results. - :on-click (fn [_e] - (rf/dispatch [::events/generate-descriptions-from-data lipas-id]))} - (tr :ptv.actions/generate-with-ai)) - (when loading? - ($ CircularProgress - {:size 24 - :sx #js {:position "absolute" - :top "50%" - :left "50%" - :mt "-12px"}})))) + ($ FormControlLabel + {:label "Sync-enabled" + :control ($ Switch + {:disabled read-only? + :value sync-enabled + :checked sync-enabled + :on-change (fn [_e v] + (js/console.log _e v) + (rf/dispatch [:lipas.ui.sports-sites.events/edit-field lipas-id [:ptv :sync-enabled] v]))})}) + + (when (= "lipas-managed-ptv-fields" descriptions-integration) + ($ Stack + {:sx #js {:position "relative"}} + ($ Button + {:disabled (or loading? + read-only?) + :variant "outlined" + ;; NOTE: Could use the lipas-id version when not editing? But then we don't have + ;; place to store the results. + :on-click (fn [_e] + (rf/dispatch [::events/generate-descriptions-from-data lipas-id]))} + (tr :ptv.actions/generate-with-ai)) + (when loading? + ($ CircularProgress + {:size 24 + :sx #js {:position "absolute" + :top "50%" + :left "50%" + :mt "-12px"}})))) ($ controls/lang-selector {:value selected-tab @@ -93,7 +259,7 @@ (rf/dispatch [:lipas.ui.sports-sites.events/edit-field lipas-id [:ptv :summary selected-tab] v])) :label "Tiivistelmä" :value (or (get-in edit-data [:ptv :summary selected-tab]) - (get-in site [:ptv :summary selected-tab]))}]) + (get-in sports-site [:ptv :summary selected-tab]))}]) ;; Description (r/as-element @@ -108,12 +274,12 @@ (rf/dispatch [:lipas.ui.sports-sites.events/edit-field lipas-id [:ptv :description selected-tab] v])) :label "Kuvaus" :value (or (get-in edit-data [:ptv :description selected-tab]) - (get-in site [:ptv :description selected-tab]))}]) + (get-in sports-site [:ptv :description selected-tab]))}]) ($ Button {:disabled (or loading? read-only?) :on-click (fn [_e] - (rf/dispatch [::events/translate-to-other-langs lipas-id {:from (name selected-tab) - :to (disj #{"fi" "en" "se"} (name selected-tab))}]))} + (rf/dispatch [::events/translate-to-other-langs lipas-id {:from (name selected-tab) + :to (disj #{"fi" "en" "se"} (name selected-tab))}]))} "Käännä muille kielille")))) diff --git a/webapp/src/cljs/lipas/ui/ptv/subs.cljs b/webapp/src/cljs/lipas/ui/ptv/subs.cljs index eb3127c4d..516e26d27 100644 --- a/webapp/src/cljs/lipas/ui/ptv/subs.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/subs.cljs @@ -51,23 +51,24 @@ (rf/reg-sub ::org-default-settings :<- [::ptv] - :<- [::selected-org-id] - (fn [[ptv org-id] _] + (fn [ptv [_ org-id]] (get-in ptv [:org org-id :default-settings]))) (rf/reg-sub ::default-settings - :<- [::ptv] - :<- [::org-default-settings] + (fn [[_ org-id]] + [(rf/subscribe [::ptv]) + (rf/subscribe [::org-default-settings org-id])]) (fn [[ptv org-defaults] _] (merge (:default-settings ptv) org-defaults))) (def lang - {"fi" "fi" "sv" "se" "en" "en"}) + {"fi" "fi" + "sv" "se" + "en" "en"}) (rf/reg-sub ::org-languages :<- [::ptv] - :<- [::selected-org-id] - (fn [[ptv org-id] _] + (fn [ptv [_ org-id]] ;; There are (undocumented) business rules regarding in which lang ;; data can be entered. One of the rules seems to be that the org ;; must be described with all the desired languages before other @@ -79,8 +80,7 @@ (rf/reg-sub ::selected-org-data :<- [::ptv] - :<- [::selected-org-id] - (fn [[ptv org-id] _] + (fn [ptv [_ org-id]] (when org-id (let [{:keys [services _service-channels]} (get-in ptv [:org org-id :data])] (for [s services @@ -102,15 +102,15 @@ (rf/reg-sub ::services-by-id :<- [::ptv] - :<- [::selected-org-id] - (fn [[ptv org-id] _] + (fn [ptv [_ org-id]] (when org-id (get-in ptv [:org org-id :data :services])))) (def langs {"sv" "se" "fi" "fi" "en" "en"}) (rf/reg-sub ::services - :<- [::services-by-id] + (fn [[_ org-id]] + (rf/subscribe [::services-by-id org-id])) (fn [services _] (for [[id service] services] (let [service-name (->> service :serviceNames (some #(when (= "fi" (:language %)) @@ -143,8 +143,9 @@ (:services-filter ptv))) (rf/reg-sub ::services-filtered - :<- [::services] - :<- [::services-filter] + (fn [[_ org-id]] + [(rf/subscribe [::services org-id]) + (rf/subscribe [::services-filter])]) (fn [[services filter'] _] (sort-by :label (case filter' @@ -152,23 +153,22 @@ services)))) (rf/reg-sub ::missing-services - :<- [::selected-org-id] - :<- [::services-by-id] - :<- [::sports-sites] - :<- [:lipas.ui.sports-sites.subs/all-types] - (fn [[org-id services sports-sites types] _] - (ptv-data/resolve-missing-services org-id services types sports-sites))) + (fn [[_ org-id]] + [(rf/subscribe [::services-by-id org-id]) + (rf/subscribe [::sports-sites])]) + (fn [[services sports-sites] [_ org-id]] + (ptv-data/resolve-missing-services org-id services sports-sites))) (rf/reg-sub ::service-candidate-descriptions - :<- [::selected-org-id] :<- [::ptv] - (fn [[org-id ptv] _] + (fn [ptv [_ org-id]] (get-in ptv [:org org-id :data :service-candidates]))) (rf/reg-sub ::service-candidates - :<- [::missing-services] - :<- [::service-candidate-descriptions] - :<- [::org-languages] + (fn [[_ org-id]] + [(rf/subscribe [::missing-services org-id]) + (rf/subscribe [::service-candidate-descriptions org-id]) + (rf/subscribe [::org-languages org-id])]) (fn [[missing-services descriptions org-langs] _] (->> missing-services (map (fn [{:keys [source-id] :as m}] @@ -185,13 +185,13 @@ (rf/reg-sub ::service-channels-by-id :<- [::ptv] - :<- [::selected-org-id] - (fn [[ptv org-id] _] + (fn [ptv [_ org-id]] (when org-id (get-in ptv [:org org-id :data :service-channels])))) (rf/reg-sub ::service-channels - :<- [::service-channels-by-id] + (fn [[_ org-id]] + (rf/subscribe [::service-channels-by-id org-id])) (fn [channels _] (vals channels))) @@ -203,15 +203,15 @@ :name (ptv-data/resolve-service-channel-name m)}))) (rf/reg-sub ::sports-sites - :<- [::ptv] - :<- [::selected-org-id] - :<- [::services-by-id] - :<- [::service-channels-by-id] - :<- [::default-settings] - :<- [:lipas.ui.subs/translator] - :<- [:lipas.ui.sports-sites.subs/all-types] - :<- [::org-languages] - (fn [[ptv org-id services service-channels org-defaults tr types org-langs] _] + (fn [[_ org-id]] + [(rf/subscribe [::ptv]) + (rf/subscribe [::services-by-id org-id]) + (rf/subscribe [::service-channels-by-id org-id]) + (rf/subscribe [::default-settings org-id]) + (rf/subscribe [:lipas.ui.subs/translator]) + (rf/subscribe [:lipas.ui.sports-sites.subs/all-types]) + (rf/subscribe [::org-languages org-id])]) + (fn [[ptv services service-channels org-defaults tr types org-langs] [_ org-id]] (let [lipas-id->site (get-in ptv [:org org-id :data :sports-sites])] (for [site (vals lipas-id->site)] (ptv-data/sports-site->ptv-input {:org-id org-id @@ -224,12 +224,14 @@ site))))) (rf/reg-sub ::sports-sites-count - :<- [::sports-sites] + (fn [[_ org-id]] + (rf/subscribe [::sports-sites org-id])) (fn [sports-sites _] (count sports-sites))) (rf/reg-sub ::sync-all-enabled? - :<- [::sports-sites] + (fn [[_ org-id]] + (rf/subscribe [::sports-sites org-id])) (fn [sports-sites _] (every? true? (map :sync-enabled sports-sites)))) @@ -254,7 +256,8 @@ 100)}))) (rf/reg-sub ::sports-site-setup-done - :<- [::sports-sites] + (fn [[_ org-id]] + (rf/subscribe [::sports-sites org-id])) (fn [ms _] (every? (fn [{:keys [last-sync sync-enabled] :as _m}] (or (utils/iso-date-time-string? (or last-sync "")) @@ -267,8 +270,9 @@ (:sports-sites-filter m))) (rf/reg-sub ::sports-sites-filtered - :<- [::sports-sites] - :<- [::sports-sites-filter] + (fn [[_ org-id]] + [(rf/subscribe [::sports-sites org-id]) + (rf/subscribe [::sports-sites-filter])]) (fn [[sites filter*] _] (case filter* "all" @@ -289,7 +293,8 @@ sites)))) (rf/reg-sub ::sports-sites-filtered-count - :<- [::sports-sites-filtered] + (fn [[_ org-id]] + (rf/subscribe [::sports-sites-filtered org-id])) (fn [sports-sites _] (count sports-sites))) diff --git a/webapp/src/cljs/lipas/ui/ptv/views.cljs b/webapp/src/cljs/lipas/ui/ptv/views.cljs index 503d9c521..a4d506232 100644 --- a/webapp/src/cljs/lipas/ui/ptv/views.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/views.cljs @@ -91,7 +91,8 @@ (defn settings [] (let [tr (<== [:lipas.ui.subs/translator]) - default-settings (<== [::subs/default-settings])] + org-id (<== [::subs/selected-org-id]) + default-settings (<== [::subs/default-settings org-id])] [mui/grid {:container true :spacing 4 :style {:margin-left "-32px"}} [mui/grid {:item true :xs 12} @@ -276,8 +277,9 @@ (defn table [] (r/with-let [expanded-rows (r/atom {})] (let [tr (<== [:lipas.ui.subs/translator]) - sites (<== [::subs/sports-sites]) - sync-all-enabled? (<== [::subs/sync-all-enabled?]) + org-id (<== [::subs/selected-org-id]) + sites (<== [::subs/sports-sites org-id]) + sync-all-enabled? (<== [::subs/sync-all-enabled? org-id]) headers [{:key :expand :label "" :padding "checkbox"} #_ @@ -405,8 +407,9 @@ (defn descriptions-generator [] (let [tr (<== [:lipas.ui.subs/translator]) - sports-sites (<== [::subs/sports-sites-filtered]) - sports-sites-count (<== [::subs/sports-sites-filtered-count]) + org-id (<== [::subs/selected-org-id]) + sports-sites (<== [::subs/sports-sites-filtered org-id]) + sports-sites-count (<== [::subs/sports-sites-filtered-count org-id]) sports-sites-filter (<== [::subs/sports-sites-filter]) {:keys [in-progress? @@ -529,7 +532,8 @@ [] (r/with-let [selected-tab (r/atom :fi)] (let [tr (<== [:lipas.ui.subs/translator]) - service-candidates (<== [::subs/service-candidates]) + org-id (<== [::subs/selected-org-id]) + service-candidates (<== [::subs/service-candidates org-id]) {:keys [in-progress? halt? processed-percent @@ -787,9 +791,10 @@ (defn integrate-service-locations [] (let [tr (<== [:lipas.ui.subs/translator]) - sports-sites (<== [::subs/sports-sites]) - setup-done? (<== [::subs/sports-site-setup-done]) - sports-sites-count (<== [::subs/sports-sites-count]) + org-id (<== [::subs/selected-org-id]) + sports-sites (<== [::subs/sports-sites org-id]) + setup-done? (<== [::subs/sports-site-setup-done org-id]) + sports-sites-count (<== [::subs/sports-sites-count org-id]) sports-sites-filter (<== [::subs/sports-sites-filter]) [selected-tab set-selected-tab] (uix/use-state :fi) @@ -1013,7 +1018,8 @@ [] (let [tr (<== [:lipas.ui.subs/translator]) services-filter (<== [::subs/services-filter]) - services (<== [::subs/services-filtered])] + org-id (<== [::subs/selected-org-id]) + services (<== [::subs/services-filtered org-id])] [mui/paper ;; Filter checkbox @@ -1039,8 +1045,9 @@ (let [open? (<== [::subs/dialog-open?]) selected-tab (<== [::subs/selected-tab]) loading? (<== [::subs/loading-from-ptv?]) - org-data (<== [::subs/selected-org-data]) - sites (<== [::subs/sports-sites])] + org-id (<== [::subs/selected-org-id]) + org-data (<== [::subs/selected-org-data org-id]) + sites (<== [::subs/sports-sites org-id])] [lui/dialog {:open? open? diff --git a/webapp/test/clj/lipas/backend/ptv_test.clj b/webapp/test/clj/lipas/backend/ptv_test.clj index 6b632e1ce..fb0dfa6bb 100644 --- a/webapp/test/clj/lipas/backend/ptv_test.clj +++ b/webapp/test/clj/lipas/backend/ptv_test.clj @@ -98,7 +98,6 @@ (is (= [] (ptv-data/resolve-missing-services org-id services - nil ptv-sites))) ;; Add ptv summary and description to the site, enabling the From 62fb687a3c82c00f3a42665efe67a472bcb0f929 Mon Sep 17 00:00:00 2001 From: Juho Teperi Date: Tue, 19 Nov 2024 15:22:57 +0200 Subject: [PATCH 58/68] PTV errors --- webapp/src/clj/lipas/backend/core.clj | 33 ++++++++++++++------- webapp/src/clj/lipas/backend/ptv/core.clj | 28 +++++------------ webapp/src/cljs/lipas/ui/ptv/site_view.cljs | 4 +++ 3 files changed, 34 insertions(+), 31 deletions(-) diff --git a/webapp/src/clj/lipas/backend/core.clj b/webapp/src/clj/lipas/backend/core.clj index 56fe22fe2..22cf52b2f 100644 --- a/webapp/src/clj/lipas/backend/core.clj +++ b/webapp/src/clj/lipas/backend/core.clj @@ -535,17 +535,28 @@ ;; TODO: Currently this will create a new sports-site rev. ;; Make it instead update the sports-site already created in the tx? ;; Otherwise each save-sports-site! will create two sports-site revs. - ;; TODO: If this fails, store failure to the site-data so it can be shown on the - ;; UI and user can try again. We don't know how often PTV causes problems, - ;; and the sports-site save should work even if this fails. - (let [new-ptv-data (:ptv ((resolve 'lipas.backend.ptv.core/sync-ptv!) - tx search ptv user - {:sports-site resp - :org-id (:org-id (:ptv resp)) - :lipas-id (:lipas-id resp) - :ptv (:ptv resp)}))] - (log/infof "Sports site updated and PTV integration enabled") - (assoc resp :ptv new-ptv-data)) + + ;; TODO: Move try-catch to sync-ptv! fn? + (try + (let [new-ptv-data (:ptv ((resolve 'lipas.backend.ptv.core/sync-ptv!) + tx search ptv user + {:sports-site resp + :org-id (:org-id (:ptv resp)) + :lipas-id (:lipas-id resp) + :ptv (:ptv resp)}))] + (log/infof "Sports site updated and PTV integration enabled") + (assoc resp :ptv new-ptv-data)) + (catch Exception e + (let [new-ptv-data (assoc (:ptv resp) + :error {:message (.getMessage e) + :data (ex-data e)})] + (log/infof e "Sports site updated but PTV integration had an error") + (upsert-sports-site! tx + user + (-> resp + (assoc :event-date (utils/timestamp)) + (assoc :ptv new-ptv-data)) + false)))) resp))))) ;;; Cities ;;; diff --git a/webapp/src/clj/lipas/backend/ptv/core.clj b/webapp/src/clj/lipas/backend/ptv/core.clj index bbe0a8711..317de34e7 100644 --- a/webapp/src/clj/lipas/backend/ptv/core.clj +++ b/webapp/src/clj/lipas/backend/ptv/core.clj @@ -194,26 +194,14 @@ _ (log/infof "Missing services? %s" (pr-str missing-services)) - ;; TODO: Move the check for missing services to UI, so - ;; user can validate the texts. - ;; Go through missing services, create data for them and send to PTV - source-id->service (reduce (fn [acc missing] - (let [x (generate-ptv-service-descriptions search - {:sub-category-id (:sub-category-id missing) - :city-codes [(:city-code (:city (:location sports-site)))]}) - service (-> missing - (assoc :org-id org-id - :city-codes [(:city-code (:city (:location sports-site)))] - ;; :languages ["fi" "se" "en"] - :description (:description x) - :summary (:summary x))) - _ (log/infof "Missing service, generated descriptions: %s" service) - - ;; Hope this returns data in same format as list services... - resp (upsert-ptv-service! ptv-component service)] - (assoc acc (:source-id service) resp))) - source-id->service - missing-services) + + ;; FE doesn't update the :ptv :service-ids, that is still handled here. + ;; This code just presumes the user has created the possibly missing Sercices + ;; in the FE first. + + _ (when (seq missing-services) + (throw (ex-info "Site needs a PTV Service that doesn't exists" + {:missing-services missing-services}))) ;; Remove old service-ids from :ptv data and add the new. ;; Don't touch other service-ids in the data, those could have be added manually in UI or in PTV. diff --git a/webapp/src/cljs/lipas/ui/ptv/site_view.cljs b/webapp/src/cljs/lipas/ui/ptv/site_view.cljs index b03b777e8..e4aaa2471 100644 --- a/webapp/src/cljs/lipas/ui/ptv/site_view.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/site_view.cljs @@ -178,6 +178,10 @@ :else ($ Alert {:severity "warning"} "Paikka näyttää siltä ettei sitä pidä viedä PTV")) + (when-let [e (:error (:ptv x))] + ($ Alert {:severity "error"} + "Virhe PTV integraatiossa, uusimpia tietoja ei ole viety PTV: " (:message e))) + (when candidate-now? (cond (seq missing-services) From cf8ea437da25ef957f6f3258118ceb9634a939bc Mon Sep 17 00:00:00 2001 From: Juho Teperi Date: Wed, 20 Nov 2024 15:19:20 +0200 Subject: [PATCH 59/68] WIP --- webapp/src/clj/lipas/backend/handler.clj | 15 +++-- webapp/src/clj/lipas/backend/ptv/core.clj | 15 +++-- webapp/src/clj/lipas/backend/ptv/handler.clj | 34 ++++++---- .../src/clj/lipas/backend/ptv/integration.clj | 34 +++++++--- webapp/src/cljc/lipas/data/ptv.cljc | 37 ++++++++--- webapp/src/cljc/lipas/schema/core.cljc | 65 ++++++++++++++++++- webapp/src/cljs/lipas/ui/ptv/db.cljs | 3 +- webapp/src/cljs/lipas/ui/ptv/events.cljs | 4 +- webapp/src/cljs/lipas/ui/ptv/site_view.cljs | 50 +++++++++++--- .../cljs/lipas/ui/sports_sites/events.cljs | 20 ++++-- .../ui/sports_sites/floorball/events.cljs | 2 +- 11 files changed, 222 insertions(+), 57 deletions(-) diff --git a/webapp/src/clj/lipas/backend/handler.clj b/webapp/src/clj/lipas/backend/handler.clj index 28c8b11bc..52d606c41 100644 --- a/webapp/src/clj/lipas/backend/handler.clj +++ b/webapp/src/clj/lipas/backend/handler.clj @@ -47,10 +47,17 @@ ;; specifically handled ::exception/default (exception-handler 500 :internal-server-error :print-stack) - :reitit.coercion/request-coercion (let [handler (:reitit.coercion/request-coercion exception/default-handlers)] - (fn [e x] - (log/errorf e "Request coercion error") - (handler e x)))}) + :reitit.coercion/response-coercion + (let [handler (:reitit.coercion/response-coercion exception/default-handlers)] + (fn [e x] + (log/errorf e "Response coercion error") + (handler e x))) + + :reitit.coercion/request-coercion + (let [handler (:reitit.coercion/request-coercion exception/default-handlers)] + (fn [e x] + (log/errorf e "Request coercion error") + (handler e x)))}) (def exceptions-mw (exception/create-exception-middleware diff --git a/webapp/src/clj/lipas/backend/ptv/core.clj b/webapp/src/clj/lipas/backend/ptv/core.clj index 317de34e7..30086231c 100644 --- a/webapp/src/clj/lipas/backend/ptv/core.clj +++ b/webapp/src/clj/lipas/backend/ptv/core.clj @@ -64,11 +64,11 @@ :content))) (defn upsert-ptv-service! - [ptv {:keys [id] :as m}] + [ptv {:keys [source-id] :as m}] ;; FIXME: Does ->ptv-service need something from the component config? (let [data (ptv-data/->ptv-service m)] - (if id - (ptv/update-service ptv id data) + (if source-id + (ptv/update-service ptv source-id data) (ptv/create-service ptv data)))) (defn fetch-ptv-org @@ -137,9 +137,9 @@ (core/upsert-sports-site! tx user - (-> site - (assoc :event-date now) - (assoc :ptv new-ptv-data)) + (assoc site + :event-date now + :ptv new-ptv-data) false) ;; No need to re-index for search after ptv change @@ -169,7 +169,8 @@ (let [type-code (-> sports-site :type :type-code) previous-sent? (ptv-data/is-sent-to-ptv? sports-site) - candidate-now? (ptv-data/ptv-candidate? sports-site) + candidate-now? (and (ptv-data/ptv-candidate? sports-site) + (ptv-data/ptv-ready? sports-site)) to-archive? (and previous-sent? (not candidate-now?)) diff --git a/webapp/src/clj/lipas/backend/ptv/handler.clj b/webapp/src/clj/lipas/backend/ptv/handler.clj index ab5ce99b9..b146d6a18 100644 --- a/webapp/src/clj/lipas/backend/ptv/handler.clj +++ b/webapp/src/clj/lipas/backend/ptv/handler.clj @@ -11,15 +11,20 @@ [:en [:string string-props]]]) (def integration-enum - [:enum "lipas-managed"]) + [:enum "lipas-managed" "manual"]) (def ptv-meta [:map - ;; TODO: one or many? - [:service-channel-id :string] - [:service-channel-integration integration-enum] + {:closed true} + ;; [:org-id :string] [:sync-enabled :boolean] + [:service-channel-integration integration-enum] [:service-integration integration-enum] + + [:service-channel-ids [:vector :string]] + ;; [:service-ids [:vector :string]] + ;; [:languages [:vector :string]] + [:summary (localized-string-schema {:max 150})] [:description (localized-string-schema {})]]) @@ -27,7 +32,7 @@ [:map {:closed true} [:org :string] - [:lipas-id :string] + [:lipas-id :int] [:ptv ptv-meta]]) (defn routes [{:keys [db search ptv] :as _ctx}] @@ -39,10 +44,14 @@ ["/actions/get-ptv-integration-candidates" {:post {:require-privilege :ptv/manage + :parameters {:body [:map + [:city-codes [:vector :int]] + [:type-codes [:vector :int]] + [:owners [:vector :string]]]} :handler - (fn [{:keys [body-params]}] + (fn [req] {:status 200 - :body (ptv-core/get-ptv-integration-candidates search body-params)})}}] + :body (ptv-core/get-ptv-integration-candidates search (-> req :parameters :body))})}}] ["/actions/generate-ptv-descriptions" {:post @@ -137,9 +146,9 @@ [:summary (localized-string-schema {:max 150})] [:description (localized-string-schema nil)]]} :handler - (fn [{:keys [body-params]}] + (fn [req] {:status 200 - :body (ptv-core/upsert-ptv-service! ptv body-params)})}}] + :body (ptv-core/upsert-ptv-service! ptv (-> req :parameters :body))})}}] ["/actions/fetch-ptv-services" {:post @@ -173,8 +182,9 @@ ["/actions/save-ptv-meta" {:post {:require-privilege :ptv/manage - :parameters {:body [:any]} + :coercion reitit.coercion.spec/coercion + :parameters {:body :lipas.sports-site/ptv} :handler - (fn [{:keys [body-params identity]}] + (fn [{:keys [identity] :as req}] {:status 200 - :body (ptv-core/save-ptv-integration-definitions db search identity body-params)})}}]]) + :body (ptv-core/save-ptv-integration-definitions db search identity (-> req :parameters :body))})}}]]) diff --git a/webapp/src/clj/lipas/backend/ptv/integration.clj b/webapp/src/clj/lipas/backend/ptv/integration.clj index 8374fbac7..e468fce64 100644 --- a/webapp/src/clj/lipas/backend/ptv/integration.clj +++ b/webapp/src/clj/lipas/backend/ptv/integration.clj @@ -176,11 +176,11 @@ (defn update-service [ptv - service-id + source-id data] - (log/info "Update PTV service with id " service-id "and data" data) + (log/info "Update PTV service with id " source-id "and data" data) (let [org-id (:mainResponsibleOrganization data) - params {:url (make-url ptv "/v11/Service/" service-id) + params {:url (make-url ptv "/v11/Service/SourceId/" source-id) :method :put :form-params data}] (-> (http ptv org-id params) @@ -235,15 +235,20 @@ (->> (map :_source))))) (comment - (def ptv* (:lipas/ptv integrant.repl.state/system)) + (require '[clojure.java.jdbc :as sql] + '[integrant.repl.state :as state] + '[lipas.backend.core :as core] + '[lipas.utils :as utils]) + + (def ptv* (:lipas/ptv state/system)) (get-org-services ptv* ptv-data/liminka-org-id-test) ;; Delete all org services - (doseq [x (:itemList (get-org-services {} ptv-data/liminka-org-id-test))] + (doseq [x (:itemList (get-org-services ptv* ptv-data/liminka-org-id-test))] (update-service ptv* - (:id x) - {:org-id ptv-data/liminka-org-id-test + (:sourceId x) + {:mainResponsibleOrganization ptv-data/liminka-org-id-test :publishingStatus "Deleted"})) (get-service ptv* @@ -253,11 +258,24 @@ first :id)) + (require 'user) + + (doseq [search-site (get-eligible-sites (user/search) + {:city-codes [425] + :owners ["city" "city-main-owner"]}) + :let [site (core/get-sports-site (user/db) (:lipas-id search-site))]] + (core/upsert-sports-site! (user/db) + user/robot + (-> (dissoc site :ptv) + (assoc :event-date (utils/timestamp))) + false)) + (get-org-service-channels ptv* ptv-data/liminka-org-id-test) ;; Delete all org service locations (doseq [x (:itemList (get-org-service-channels ptv* ptv-data/liminka-org-id-test))] - (update-service-location {:org-id ptv-data/liminka-org-id-test} (:id x) {:publishingStatus "Deleted"})) + (update-service-location ptv* (:id x) {:organizationId ptv-data/liminka-org-id-test + :publishingStatus "Deleted"})) (update-service-location ptv* "fc768bb4-268c-4054-9b88-9ecc9a943452" diff --git a/webapp/src/cljc/lipas/data/ptv.cljc b/webapp/src/cljc/lipas/data/ptv.cljc index 7016ad335..152ca7d0d 100644 --- a/webapp/src/cljc/lipas/data/ptv.cljc +++ b/webapp/src/cljc/lipas/data/ptv.cljc @@ -40,6 +40,10 @@ (def default-langs ["fi"]) +(defn ->service-source-id + [org-id sub-category-id] + (str "lipas-" org-id "-" sub-category-id)) + (defn ->ptv-service [{:keys [org-id city-codes source-id sub-category-id languages _description _summary] :or {languages default-langs} :as m}] @@ -48,7 +52,11 @@ sub-cat (get types/sub-categories sub-category-id) main-cat (get types/main-categories (parse-long (:main-category sub-cat)))] - {:sourceId source-id + {:sourceId (or source-id + (let [ts (str/replace (utils/timestamp) #":" "-") + x (str "lipas-" org-id "-" sub-category-id "-" ts)] + (log/infof "Creating new PTV Service source-id %s" x) + x)) #_#_:keywords (let [tags (:tags type)] (for [locale [:fi :se :en] @@ -166,7 +174,7 @@ :sourceId (or (:source-id ptv) (let [ts (str/replace now #":" "-") x (str "lipas-" (:org-id ptv) "-" lipas-id "-" ts)] - (log/infof "Creating new PTV source-id %s" x) + (log/infof "Creating new PTV ServiceLocation source-id %s" x) x)) :serviceChannelNames (keep identity (let [fallback (get-in sports-site [:name])] @@ -324,15 +332,20 @@ ) -(defn ->service-source-id - [org-id sub-category-id] - (str "lipas-" org-id "-" sub-category-id)) +(defn parse-service-source-id [source-id] + ()) + +(defn index-services [services] + ) (defn resolve-missing-services "Infer services (sub-categories) that need to be created in PTV and attached to sports-sites." [org-id services sports-sites] - (let [source-ids (->> services vals (keep :sourceId) set)] + (let [source-ids (->> services + vals + (keep :sourceId) + set)] (->> sports-sites (filter (fn [{:keys [ptv]}] (empty? (:service-ids ptv)))) (map (fn [site] {:source-id (->service-source-id org-id (:sub-category-id site)) @@ -459,11 +472,15 @@ (defn ptv-candidate? "Does the site look like it should be sent to the ptv?" [site] - (let [{:keys [status ptv owner]} site - {:keys [summary description]} ptv + (let [{:keys [status owner]} site type-code (-> site :type :type-code)] (boolean (and (not (contains? #{"incorrect-data" "out-of-service-permanently"} status)) - (some-> description :fi count (> 5)) - (some-> summary :fi count (> 5)) (#{"city" "city-main-owner"} owner) (not (#{7000} type-code)))))) + +(defn ptv-ready? + [site] + (let [{:keys [ptv]} site + {:keys [summary description]} ptv] + (boolean (and (some-> description :fi count (> 5)) + (some-> summary :fi count (> 5)))))) diff --git a/webapp/src/cljc/lipas/schema/core.cljc b/webapp/src/cljc/lipas/schema/core.cljc index ed11760a4..0f7584fd4 100644 --- a/webapp/src/cljc/lipas/schema/core.cljc +++ b/webapp/src/cljc/lipas/schema/core.cljc @@ -1477,6 +1477,68 @@ :field/floorball :lipas.sports-site.fields/floorball) :into [])) +(s/def :lipas.sports-site.ptv/last-sync string?) +(s/def :lipas.sports-site.ptv/org-id string?) +(s/def :lipas.sports-site.ptv/sync-enabled boolean?) +(s/def :lipas.sports-site.ptv/source-id string?) +(s/def :lipas.sports-site.ptv/publishing-status string?) +(s/def :lipas.sports-site.ptv/previous-type-code int?) + +(s/def :lipas.ptv.summary/fi (str-in 0 150)) +(s/def :lipas.ptv.summary/se (str-in 0 150)) +(s/def :lipas.ptv.summary/en (str-in 0 150)) +(s/def :lipas.sports-site.ptv/summary + (s/keys :opt-un [:lipas.ptv.summary/fi + :lipas.ptv.summary/se + :lipas.ptv.summary/en])) + +(s/def :lipas.ptv.description/fi string?) +(s/def :lipas.ptv.description/se string?) +(s/def :lipas.ptv.description/en string?) +(s/def :lipas.sports-site.ptv/description + (s/keys :opt-un [:lipas.ptv.description/fi + :lipas.ptv.description/se + :lipas.ptv.description/en])) + +(s/def :lipas.sports-site.ptv/service-channel-integration #{"lipas-managed" "manual"}) +(s/def :lipas.sports-site.ptv/service-integration #{"lipas-managed" "manual"}) +(s/def :lipas.sports-site.ptv/descriptions-integration #{"lipas-managed-ptv-fields" "lipas-managed-comment-field" "ptv-managed"}) + +(s/def :lipas.sports-site.ptv/service-ids (s/coll-of string?)) +(s/def :lipas.sports-site.ptv/service-channel-ids (s/coll-of string?)) +(s/def :lipas.sports-site.ptv/languages (s/coll-of string?)) + +(s/def :lipas.ptv.error/message string?) +(s/def :lipas.ptv.error/data map?) +(s/def :lipas.sports-site.ptv/error + (s/keys :req-un [:lipas.ptv.error/message + :lipas.ptv.error/data])) + +(s/def :lipas.sports-site/ptv + (s/keys :req-un [:lipas.sports-site.ptv/org-id + :lipas.sports-site.ptv/sync-enabled + + :lipas.sports-site.ptv/summary + :lipas.sports-site.ptv/description + + :lipas.sports-site.ptv/service-channel-integration + :lipas.sports-site.ptv/service-integration + :lipas.sports-site.ptv/descriptions-integration + ] + :opt-un [;; Added on first successful sync + :lipas.sports-site.ptv/last-sync + :lipas.sports-site.ptv/previous-type-code + :lipas.sports-site.ptv/publishing-status + :lipas.sports-site.ptv/service-ids + :lipas.sports-site.ptv/languages + + ;; Added on sync - removed when archived + :lipas.sports-site.ptv/source-id + :lipas.sports-site.ptv/service-channel-ids + + ;; Only added on sync error - removed when success + :lipas.sports-site.ptv/error])) + (s/def :lipas/new-sports-site (s/keys :req-un [:lipas.sports-site/event-date :lipas.sports-site/status @@ -1503,7 +1565,8 @@ :lipas.sports-site/properties :lipas.sports-site/fields :lipas.sports-site/locker-rooms - :lipas.sports-site/circumstances])) + :lipas.sports-site/circumstances + :lipas.sports-site/ptv])) (s/def :lipas/sports-site (s/merge diff --git a/webapp/src/cljs/lipas/ui/ptv/db.cljs b/webapp/src/cljs/lipas/ui/ptv/db.cljs index ac9429bc4..f3d4dd172 100644 --- a/webapp/src/cljs/lipas/ui/ptv/db.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/db.cljs @@ -5,7 +5,8 @@ :loading-from-ptv {:services false :service-channels false :service-collections false} - :default-settings {:service-integration "lipas-managed" + :default-settings {:sync-enabled true + :service-integration "lipas-managed" :service-channel-integration "lipas-managed" :descriptions-integration "lipas-managed-ptv-fields" :integration-interval "manual"} diff --git a/webapp/src/cljs/lipas/ui/ptv/events.cljs b/webapp/src/cljs/lipas/ui/ptv/events.cljs index 97aa1153b..c6f67e19f 100644 --- a/webapp/src/cljs/lipas/ui/ptv/events.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/events.cljs @@ -24,6 +24,7 @@ (fn [db [_ v]] (assoc-in db [:ptv :selected-tab] v))) +;; FIXME: Move this to data ns? (def org-id->params {ptv-data/uta-org-id-test ;; Utajärvi {:org-id ptv-data/uta-org-id-test @@ -317,7 +318,8 @@ {:method :post :headers {:Authorization (str "Token " token)} :uri (str (:backend-url db) "/actions/generate-ptv-descriptions-from-data") - :params (utils/make-saveable edit-data) + ;; :ptv data isn't used as AI input, and the data might not we valid spec yet? + :params (utils/make-saveable (dissoc edit-data :ptv)) :format (ajax/transit-request-format) :response-format (ajax/transit-response-format) :on-success [::generate-descriptions-from-data-success lipas-id] diff --git a/webapp/src/cljs/lipas/ui/ptv/site_view.cljs b/webapp/src/cljs/lipas/ui/ptv/site_view.cljs index e4aaa2471..6ce500cd2 100644 --- a/webapp/src/cljs/lipas/ui/ptv/site_view.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/site_view.cljs @@ -12,9 +12,11 @@ [lipas.data.ptv :as ptv-data] [lipas.data.types :as types] [lipas.ui.components :as lui] + [lipas.ui.components.autocompletes :refer [autocomplete2]] [lipas.ui.ptv.controls :as controls] [lipas.ui.ptv.events :as events] [lipas.ui.ptv.subs :as subs] + [lipas.ui.ptv.views :as ptv-views] [lipas.ui.uix.hooks :refer [use-subscribe]] [lipas.utils :as utils] [re-frame.core :as rf] @@ -23,7 +25,7 @@ (defui new-service-form [{:keys [org-id tr service data]}] (let [{:keys [source-id sub-category-id]} service - loading? false + loading? (use-subscribe [::subs/generating-descriptions?]) read-only? false [selected-tab set-selected-tab] (uix/use-state :fi) @@ -131,20 +133,23 @@ ;; enabled (boolean (:ptv site)) descriptions-enabled (not= "manual" descriptions-integration) - loading? (use-subscribe [::subs/generating-descriptions?]) + loading? (use-subscribe [::subs/generating-descriptions?]) type-code (-> x :type :type-code) type-code-changed? (not= type-code (:previous-type-code (:ptv x))) previous-sent? (ptv-data/is-sent-to-ptv? x) + ready? (ptv-data/ptv-ready? x) candidate-now? (ptv-data/ptv-candidate? x) types (use-subscribe [:lipas.ui.sports-sites.subs/all-types]) + loading-ptv? (use-subscribe [::subs/loading-from-ptv?]) services (use-subscribe [::subs/services-by-id org-id]) missing-services-input [{:service-ids #{} :sub-category-id (-> x :type :type-code types :sub-category) :sub-category (-> x :search-meta :type :sub-category :name :fi)}] - missing-services (ptv-data/resolve-missing-services org-id services missing-services-input) + missing-services (when (and org-id (not loading-ptv?)) + (ptv-data/resolve-missing-services org-id services missing-services-input)) source-id->service (utils/index-by :sourceId (vals services)) new-service (ptv-data/sub-category-id->service org-id source-id->service (-> x :type :type-code types :sub-category)) @@ -163,8 +168,13 @@ {:direction "column" :sx #js {:gap 2}} + ;; TODO: Spinneri? + (when loading-ptv? + ($ Alert {:severity "info"} + "Ladataan PTV tietoja...")) + (cond - (and previous-sent? candidate-now?) + (and previous-sent? candidate-now? ready?) (if sync-enabled ($ Alert {:severity "success"} "PTV integraatio käytössä") ($ Alert {:severity "success"} "PTV integraatio käytössä, mutta paikan synkronointi PTV on kytketty pois päältä.")) @@ -172,8 +182,11 @@ (and previous-sent? (not candidate-now?)) ($ Alert {:severity "warning"} "Paikka on viety PTV, mutta on muutettu niin että näyttää nyt siltä että sen ei pidä mennä PTV -> PTV palvelu paikka arkistoidaan tallennuksessa.") - candidate-now? - ($ Alert {:sevierty "info"} "Paikkaa ei viety PTV, mutta palvelu paikka luodaan tallennuksessa") + (and candidate-now? ready?) + ($ Alert {:severity "info"} "Paikkaa ei viety PTV, mutta palvelu paikka luodaan tallennuksessa") + + (not ready?) + ($ Alert {:severity "info"} "PTV tiedot ovat vielä puutteelliset, täytä tiedot niin paikka viedään PTV tallennuksen yhteydessä") :else ($ Alert {:severity "warning"} "Paikka näyttää siltä ettei sitä pidä viedä PTV")) @@ -187,8 +200,9 @@ (seq missing-services) ($ Alert {:severity "warning"} "Lipas tyyppi muuttuu, service puuttuu PTV") - type-code-changed? - ($ Alert {:severity "info"} "Lipas tyyppi muuttuu, uusi service " (:id new-service)))) + (and previous-sent? type-code-changed?) + ($ Alert {:severity "info"} "Lipas tyyppi muuttuu, uusi service " (:id new-service)) + )) ; ($ FormControl ; ($ FormLabel @@ -196,6 +210,11 @@ ; ($ Typography ; status)) + (when (not (:org-id (:ptv x))) + ($ :<> + ($ Alert {:severity "warning"} + "Valitse organisaatio:"))) + (when (seq missing-services) ($ new-service-form {:data x @@ -211,6 +230,21 @@ ($ Typography last-sync)) + (let [options (uix/use-memo (fn [] + (->> ptv-views/orgs + (map (fn [{:keys [name id]}] + {:label name + :value id})))) + [])] + ($ autocomplete2 + {:options options + :disabled (or loading? + read-only?) + :label "Organisaatio" + :value (:org-id (:ptv x)) + :on-change (fn [_e v] + (rf/dispatch [:lipas.ui.sports-sites.events/edit-field lipas-id [:ptv :org-id] (:value v)]))})) + #_ ($ controls/description-integration {:value (:descriptions-integration (:ptv site)) diff --git a/webapp/src/cljs/lipas/ui/sports_sites/events.cljs b/webapp/src/cljs/lipas/ui/sports_sites/events.cljs index bee580612..8c0c66801 100644 --- a/webapp/src/cljs/lipas/ui/sports_sites/events.cljs +++ b/webapp/src/cljs/lipas/ui/sports_sites/events.cljs @@ -16,12 +16,24 @@ (assoc-in [:sports-sites :name-check] {})) :fx [[:dispatch [:lipas.ui.sports-sites.activities.events/init-edit-view lipas-id rev]]]}))) -(defmulti calc-derived-fields (comp :type-code :type)) -(defmethod calc-derived-fields :default [sports-site] sports-site) +(defmulti calc-derived-fields-for-type (comp :type-code :type)) + +(defmethod calc-derived-fields-for-type :default + [sports-site] + sports-site) + +(defn calc-derived-fields [db sports-site] + (-> sports-site + (calc-derived-fields-for-type) + ;; IF has :ptv key, initialize the default parameters to that map + ;; NOTE: Does add extra slowness to any ::edit-field calls... + (cond-> + (:ptv sports-site) + (update :ptv #(merge (:default-settings (:ptv db)) %))))) (rf/reg-event-db ::calc-derived-fields (fn [db [_ lipas-id sports-site]] - (assoc-in db [:sports-sites lipas-id :editing] (calc-derived-fields sports-site)))) + (assoc-in db [:sports-sites lipas-id :editing] (calc-derived-fields db sports-site)))) (rf/reg-event-fx ::edit-field (fn [{:keys [db]} [_ lipas-id path value]] @@ -214,7 +226,7 @@ (rf/reg-event-db ::calc-new-site-derived-fields (fn [db [_ sports-site]] - (assoc-in db [:new-sports-site :data] (calc-derived-fields sports-site)))) + (assoc-in db [:new-sports-site :data] (calc-derived-fields db sports-site)))) (rf/reg-event-fx ::edit-new-site-field (fn [{:keys [db]} [_ path value]] diff --git a/webapp/src/cljs/lipas/ui/sports_sites/floorball/events.cljs b/webapp/src/cljs/lipas/ui/sports_sites/floorball/events.cljs index 5ca4d01b0..97fc2f3d9 100644 --- a/webapp/src/cljs/lipas/ui/sports_sites/floorball/events.cljs +++ b/webapp/src/cljs/lipas/ui/sports_sites/floorball/events.cljs @@ -42,7 +42,7 @@ (apply +) pos))}) -(defmethod sports-sites.events/calc-derived-fields 2240 +(defmethod sports-sites.events/calc-derived-fields-for-type 2240 [sports-site] (-> sports-site (update :properties (fn [props] From 4e311287e2fe31ab9f673c054c3cc443a1100324 Mon Sep 17 00:00:00 2001 From: Juho Teperi Date: Wed, 20 Nov 2024 16:55:11 +0200 Subject: [PATCH 60/68] Fixes --- webapp/src/clj/lipas/backend/core.clj | 14 ++--- webapp/src/clj/lipas/backend/ptv/core.clj | 40 ++++++++------ webapp/src/clj/lipas/backend/ptv/handler.clj | 8 +-- .../src/clj/lipas/backend/ptv/integration.clj | 21 +++++--- webapp/src/cljs/lipas/ui/ptv/events.cljs | 52 +++++++++++++------ webapp/src/cljs/lipas/ui/ptv/subs.cljs | 5 +- 6 files changed, 92 insertions(+), 48 deletions(-) diff --git a/webapp/src/clj/lipas/backend/core.clj b/webapp/src/clj/lipas/backend/core.clj index 22cf52b2f..81c963b72 100644 --- a/webapp/src/clj/lipas/backend/core.clj +++ b/webapp/src/clj/lipas/backend/core.clj @@ -551,12 +551,14 @@ :error {:message (.getMessage e) :data (ex-data e)})] (log/infof e "Sports site updated but PTV integration had an error") - (upsert-sports-site! tx - user - (-> resp - (assoc :event-date (utils/timestamp)) - (assoc :ptv new-ptv-data)) - false)))) + (let [resp (upsert-sports-site! tx + user + (-> resp + (assoc :event-date (utils/timestamp)) + (assoc :ptv new-ptv-data)) + false)] + (index! search resp :sync) + resp)))) resp))))) ;;; Cities ;;; diff --git a/webapp/src/clj/lipas/backend/ptv/core.clj b/webapp/src/clj/lipas/backend/ptv/core.clj index 30086231c..e48584b45 100644 --- a/webapp/src/clj/lipas/backend/ptv/core.clj +++ b/webapp/src/clj/lipas/backend/ptv/core.clj @@ -65,11 +65,18 @@ (defn upsert-ptv-service! [ptv {:keys [source-id] :as m}] - ;; FIXME: Does ->ptv-service need something from the component config? (let [data (ptv-data/->ptv-service m)] - (if source-id + ;; We have the source-id always? + ; (if source-id + ; (ptv/update-service ptv source-id data) + ; (ptv/create-service ptv data)) + ;; PTV update using sourceId gives 404 if the sourceId doesn't exist yet + (try (ptv/update-service ptv source-id data) - (ptv/create-service ptv data)))) + (catch clojure.lang.ExceptionInfo e + (if (= 404 (:status (:resp (ex-data e)))) + (ptv/create-service ptv data) + (throw e)))))) (defn fetch-ptv-org [ptv org-id] @@ -100,7 +107,7 @@ :service-channel-ids]) (defn upsert-ptv-service-location! - [db ptv-component user {:keys [org-id lipas-id ptv archive?] :as _m}] + [db ptv-component search user {:keys [org-id lipas-id ptv archive?] :as _m}] (jdbc/with-db-transaction [tx db] (let [site (db/get-sports-site db lipas-id) _ (assert (some? site) (str "Sports site " lipas-id " not found in DB")) @@ -128,19 +135,21 @@ :publishing-status (:publishingStatus ptv-resp) ;; Take the created ID from ptv response and store to Lipas DB right away. ;; TODO: Is there a case where this could be multiple ids? - :service-channel-ids (set [(:id ptv-resp)])) + :service-channel-ids [(:id ptv-resp)]) (cond-> archive? (dissoc :source-id :service-channel-ids)))] (log/infof "Upserted (Lipas status: %s, updated: %s) service-location %s: %s" (:status site) (boolean id) data new-ptv-data) - (core/upsert-sports-site! tx - user - (assoc site - :event-date now - :ptv new-ptv-data) - false) + (let [resp (core/upsert-sports-site! tx + user + (assoc site + :event-date now + :ptv new-ptv-data) + false)] + (core/index! search resp :sync)) + ;; No need to re-index for search after ptv change {;; Return the updated :ptv meta for sports-site, to for the app-db @@ -219,10 +228,11 @@ (remove (fn [y] (contains? old-service-ids y))) (into new-service-ids))))) ptv) - resp (upsert-ptv-service-location! tx ptv-component user {:org-id org-id - :ptv ptv - :lipas-id lipas-id - :archive? to-archive?})] + resp (upsert-ptv-service-location! tx ptv-component search user + {:org-id org-id + :ptv ptv + :lipas-id lipas-id + :archive? to-archive?})] resp)) (defn save-ptv-integration-definitions diff --git a/webapp/src/clj/lipas/backend/ptv/handler.clj b/webapp/src/clj/lipas/backend/ptv/handler.clj index b146d6a18..2addbdc55 100644 --- a/webapp/src/clj/lipas/backend/ptv/handler.clj +++ b/webapp/src/clj/lipas/backend/ptv/handler.clj @@ -31,7 +31,7 @@ (def create-ptv-service-location [:map {:closed true} - [:org :string] + [:org-id :string] [:lipas-id :int] [:ptv ptv-meta]]) @@ -46,7 +46,7 @@ {:require-privilege :ptv/manage :parameters {:body [:map [:city-codes [:vector :int]] - [:type-codes [:vector :int]] + [ :type-codes {:optional true} [:vector :int]] [:owners [:vector :string]]]} :handler (fn [req] @@ -57,7 +57,7 @@ {:post {:require-privilege :ptv/manage :parameters {:body [:map - [:lipas-id :string]]} + [:lipas-id :int]]} :handler (fn [req] {:status 200 @@ -177,7 +177,7 @@ :handler (fn [{:keys [body-params identity]}] {:status 200 - :body (ptv-core/upsert-ptv-service-location! db ptv identity body-params)})}}] + :body (ptv-core/upsert-ptv-service-location! db ptv search identity body-params)})}}] ["/actions/save-ptv-meta" {:post diff --git a/webapp/src/clj/lipas/backend/ptv/integration.clj b/webapp/src/clj/lipas/backend/ptv/integration.clj index e468fce64..ea84f332f 100644 --- a/webapp/src/clj/lipas/backend/ptv/integration.clj +++ b/webapp/src/clj/lipas/backend/ptv/integration.clj @@ -218,7 +218,9 @@ "search-meta.location.simple-geoms.*"]} :query {:bool - {:must + {;; Remove huoltorakennukset - they aren't PTV candidates + :must_not [{:term {:type.type-code 7000}}] + :must (remove nil? [{:terms {:status.keyword ["active" "out-of-service-temporarily"]}} (when city-codes @@ -264,11 +266,18 @@ {:city-codes [425] :owners ["city" "city-main-owner"]}) :let [site (core/get-sports-site (user/db) (:lipas-id search-site))]] - (core/upsert-sports-site! (user/db) - user/robot - (-> (dissoc site :ptv) - (assoc :event-date (utils/timestamp))) - false)) + (let [resp (core/upsert-sports-site! (user/db) + user/robot + (-> (dissoc site :ptv) + (assoc :event-date (utils/timestamp))) + false)] + (core/index! (user/search) resp :sync))) + + (doseq [search-site (get-eligible-sites (user/search) + {:city-codes [425] + :owners ["city" "city-main-owner"]}) + :let [site (core/get-sports-site (user/db) (:lipas-id search-site))]] + (core/index! (user/search) site :sync)) (get-org-service-channels ptv* ptv-data/liminka-org-id-test) diff --git a/webapp/src/cljs/lipas/ui/ptv/events.cljs b/webapp/src/cljs/lipas/ui/ptv/events.cljs index c6f67e19f..a8277e649 100644 --- a/webapp/src/cljs/lipas/ui/ptv/events.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/events.cljs @@ -176,15 +176,17 @@ (rf/reg-event-fx ::fetch-service-collections (fn [{:keys [db]} [_ org]] (when org - {:db (assoc-in db [:ptv :loading-from-ptv :service-collections] true) - :fx [[:http-xhrio - {:method :post - :uri (str (:backend-url db) "/actions/fetch-ptv-service-collections") - :params {:org-id (:id org)} - :format (ajax/transit-request-format) - :response-format (ajax/json-response-format {:keywords? true}) - :on-success [::fetch-service-collections-success (:id org)] - :on-failure [::fetch-service-collections-failure]}]]}))) + (let [token (-> db :user :login :token)] + {:db (assoc-in db [:ptv :loading-from-ptv :service-collections] true) + :fx [[:http-xhrio + {:method :post + :headers {:Authorization (str "Token " token)} + :uri (str (:backend-url db) "/actions/fetch-ptv-service-collections") + :params {:org-id (:id org)} + :format (ajax/transit-request-format) + :response-format (ajax/json-response-format {:keywords? true}) + :on-success [::fetch-service-collections-success (:id org)] + :on-failure [::fetch-service-collections-failure]}]]})))) (rf/reg-event-fx ::fetch-service-collections-success (fn [{:keys [db]} [_ org-id resp]] @@ -616,8 +618,27 @@ (let [token (-> db :user :login :token) ;; Or per site? org-id (-> db :ptv :selected-org :id) - ptv-data (get-in db [:ptv :org org-id :data :sports-sites lipas-id :ptv]) + + types (get-in db [:sports-sites :types]) + source-id->service (->> (get-in db [:ptv :org org-id :data :services]) + vals + (utils/index-by :sourceId)) + + sports-site (get-in db [:ptv :org org-id :data :sports-sites lipas-id]) + + ;; Add default org-id for service-ids linking + sports-site (update sports-site :ptv #(merge {:org-id org-id} %)) + + service-ids (ptv-data/sports-site->service-ids types source-id->service sports-site) + + ;; Add other defaults and merge with summary/description from the UI + ptv-data (merge (:default-settings (:ptv db)) + {:service-ids service-ids + :service-channel-ids []} + ;; {:org-id org-id} + (:ptv sports-site)) ;; What is this? + ;; This is the subscription data stored when starting the sync... I rather not use this here. ;; data (get-in db [:ptv :service-locations-creation :data lipas-id]) ] {:db (assoc-in db [:ptv :loading-from-lipas :service-locations] true) @@ -626,7 +647,7 @@ :headers {:Authorization (str "Token " token)} :uri (str (:backend-url db) "/actions/save-ptv-service-location") :params {:lipas-id lipas-id - :org (org-id->params org-id) + :org-id org-id :ptv ptv-data} :format (ajax/transit-request-format) :response-format (ajax/transit-response-format) @@ -634,14 +655,14 @@ :on-failure [::create-ptv-service-location-failure lipas-id failure-fx]}]]}))) (rf/reg-event-fx ::create-ptv-service-location-success - (fn [{:keys [db]} [_ lipas-id extra-fx {:keys [ptv-resp ptv-meta]}]] + (fn [{:keys [db]} [_ lipas-id extra-fx {:keys [ptv-resp ptv]}]] (let [org-id (get-in db [:ptv :selected-org :id])] {:db (-> db (assoc-in [:ptv :loading-from-lipas :service-channels] false) (assoc-in [:ptv :org org-id :data :service-channels (:id ptv-resp)] ptv-resp) ;; Update the lipas TS also, it will be the same TS as PTV last-sync now - (assoc-in [:ptv :org org-id :data :sports-sites lipas-id :event-date] (:last-sync ptv-meta)) - (assoc-in [:ptv :org org-id :data :sports-sites lipas-id :ptv] ptv-meta)) + (assoc-in [:ptv :org org-id :data :sports-sites lipas-id :event-date] (:last-sync ptv)) + (assoc-in [:ptv :org org-id :data :sports-sites lipas-id :ptv] ptv)) :fx extra-fx}))) (rf/reg-event-fx ::create-ptv-service-location-failure @@ -691,7 +712,8 @@ {:db (update-in db [:ptv :service-locations-creation] merge - {:data (utils/index-by :lipas-id to-sync) + {;; NOTE: This data is unnecessary? Event is just reading the :sports-site raw data + :data (utils/index-by :lipas-id to-sync) :batch-size (count ids) :halt? false :size (count ids) diff --git a/webapp/src/cljs/lipas/ui/ptv/subs.cljs b/webapp/src/cljs/lipas/ui/ptv/subs.cljs index 516e26d27..f12358ed6 100644 --- a/webapp/src/cljs/lipas/ui/ptv/subs.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/subs.cljs @@ -76,7 +76,8 @@ ;; 'supported languages' so we infer them from org name ;; translations. wtf (->> (get-in ptv [:org org-id :data :org org-id :organizationNames]) - (keep #(get lang (:language %)))))) + (keep #(get lang (:language %))) + vec))) (rf/reg-sub ::selected-org-data :<- [::ptv] @@ -155,7 +156,7 @@ (rf/reg-sub ::missing-services (fn [[_ org-id]] [(rf/subscribe [::services-by-id org-id]) - (rf/subscribe [::sports-sites])]) + (rf/subscribe [::sports-sites org-id])]) (fn [[services sports-sites] [_ org-id]] (ptv-data/resolve-missing-services org-id services sports-sites))) From 2e1b8a6ccaa2d8f5d90c123e482f0a82e321d85e Mon Sep 17 00:00:00 2001 From: Juho Teperi Date: Wed, 20 Nov 2024 17:38:48 +0200 Subject: [PATCH 61/68] No need to store :service-locations-creation :data --- webapp/src/cljs/lipas/ui/ptv/events.cljs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/webapp/src/cljs/lipas/ui/ptv/events.cljs b/webapp/src/cljs/lipas/ui/ptv/events.cljs index a8277e649..7d1fb4e96 100644 --- a/webapp/src/cljs/lipas/ui/ptv/events.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/events.cljs @@ -584,6 +584,7 @@ {:batch-size (count ids) :halt? false :size (count ids) + ;; TODO: Is this necessary? Maybe? :data (utils/index-by :source-id ms) :ids (set ids)}) :fx [[:dispatch [::create-all-ptv-services* org-id ids]]]}))) @@ -636,11 +637,7 @@ {:service-ids service-ids :service-channel-ids []} ;; {:org-id org-id} - (:ptv sports-site)) - ;; What is this? - ;; This is the subscription data stored when starting the sync... I rather not use this here. - ;; data (get-in db [:ptv :service-locations-creation :data lipas-id]) - ] + (:ptv sports-site))] {:db (assoc-in db [:ptv :loading-from-lipas :service-locations] true) :fx [[:http-xhrio {:method :post @@ -712,9 +709,7 @@ {:db (update-in db [:ptv :service-locations-creation] merge - {;; NOTE: This data is unnecessary? Event is just reading the :sports-site raw data - :data (utils/index-by :lipas-id to-sync) - :batch-size (count ids) + {:batch-size (count ids) :halt? false :size (count ids) :ids (set ids)}) From 723f035ff5eba857a22f95a67d855b62e7961584 Mon Sep 17 00:00:00 2001 From: Juho Teperi Date: Fri, 22 Nov 2024 10:54:17 +0200 Subject: [PATCH 62/68] Cleanup --- webapp/src/clj/lipas/backend/core.clj | 34 ++---- webapp/src/clj/lipas/backend/ptv/core.clj | 129 +++++++++++--------- webapp/src/cljc/lipas/data/ptv.cljc | 8 +- webapp/src/cljs/lipas/ui/ptv/site_view.cljs | 39 +++--- webapp/src/cljs/lipas/ui/ptv/views.cljs | 4 +- 5 files changed, 105 insertions(+), 109 deletions(-) diff --git a/webapp/src/clj/lipas/backend/core.clj b/webapp/src/clj/lipas/backend/core.clj index 81c963b72..c3d437c68 100644 --- a/webapp/src/clj/lipas/backend/core.clj +++ b/webapp/src/clj/lipas/backend/core.clj @@ -532,33 +532,17 @@ ;; TODO: Check privilage :ptv/basic or such (or (ptv-data/ptv-candidate? resp) (ptv-data/is-sent-to-ptv? resp))) - ;; TODO: Currently this will create a new sports-site rev. + ;; NOTE: this will create a new sports-site rev. ;; Make it instead update the sports-site already created in the tx? ;; Otherwise each save-sports-site! will create two sports-site revs. - - ;; TODO: Move try-catch to sync-ptv! fn? - (try - (let [new-ptv-data (:ptv ((resolve 'lipas.backend.ptv.core/sync-ptv!) - tx search ptv user - {:sports-site resp - :org-id (:org-id (:ptv resp)) - :lipas-id (:lipas-id resp) - :ptv (:ptv resp)}))] - (log/infof "Sports site updated and PTV integration enabled") - (assoc resp :ptv new-ptv-data)) - (catch Exception e - (let [new-ptv-data (assoc (:ptv resp) - :error {:message (.getMessage e) - :data (ex-data e)})] - (log/infof e "Sports site updated but PTV integration had an error") - (let [resp (upsert-sports-site! tx - user - (-> resp - (assoc :event-date (utils/timestamp)) - (assoc :ptv new-ptv-data)) - false)] - (index! search resp :sync) - resp)))) + (let [new-ptv-data ((resolve 'lipas.backend.ptv.core/sync-ptv!) + tx search ptv user + {:sports-site resp + :org-id (:org-id (:ptv resp)) + :lipas-id (:lipas-id resp) + :ptv (:ptv resp)})] + (log/infof "Sports site updated and PTV integration enabled") + (assoc resp :ptv new-ptv-data)) resp))))) ;;; Cities ;;; diff --git a/webapp/src/clj/lipas/backend/ptv/core.clj b/webapp/src/clj/lipas/backend/ptv/core.clj index e48584b45..28685fa46 100644 --- a/webapp/src/clj/lipas/backend/ptv/core.clj +++ b/webapp/src/clj/lipas/backend/ptv/core.clj @@ -108,6 +108,9 @@ (defn upsert-ptv-service-location! [db ptv-component search user {:keys [org-id lipas-id ptv archive?] :as _m}] + ;; FIXME: This is called from inside tx in save-sports-site! is that a problem? + ;; FIXME: Separate version from this fn for use in sync-ptv! which doesn't load the + ;; sports site from db etc.? (jdbc/with-db-transaction [tx db] (let [site (db/get-sports-site db lipas-id) _ (assert (some? site) (str "Sports site " lipas-id " not found in DB")) @@ -175,65 +178,73 @@ ;; TODO: Check if code can be moved around to avoid this ^{:clj-kondo/ignore [:clojure-lsp/unused-public-var]} (defn sync-ptv! [tx search ptv-component user {:keys [sports-site ptv org-id lipas-id]}] - (let [type-code (-> sports-site :type :type-code) - - previous-sent? (ptv-data/is-sent-to-ptv? sports-site) - candidate-now? (and (ptv-data/ptv-candidate? sports-site) - (ptv-data/ptv-ready? sports-site)) - - to-archive? (and previous-sent? - (not candidate-now?)) - - ;; TODO: to-archive - ;; 1. set PTV status Deleted - ;; 2. remove :ptv :source-id, :service-channel-ids -> if restored, a new service-location is created - - type-code-changed? (not= type-code (:previous-type-code ptv)) - ptv (if type-code-changed? - (let [types types/all - ;; Figure out what services are available in PTV for the site organization - services (:itemList (ptv/get-org-services ptv-component org-id)) - source-id->service (->> services - (utils/index-by :sourceId)) - - ;; Check if services for the current/new site type-code exist - missing-services-input [{:service-ids #{} - :sub-category-id (-> sports-site :type :type-code types :sub-category) - :sub-cateogry (-> sports-site :search-meta :type :sub-category :name :fi)}] - missing-services (ptv-data/resolve-missing-services org-id source-id->service missing-services-input) - - _ (log/infof "Missing services? %s" (pr-str missing-services)) - - - ;; FE doesn't update the :ptv :service-ids, that is still handled here. - ;; This code just presumes the user has created the possibly missing Sercices - ;; in the FE first. - - _ (when (seq missing-services) - (throw (ex-info "Site needs a PTV Service that doesn't exists" - {:missing-services missing-services}))) - - ;; Remove old service-ids from :ptv data and add the new. - ;; Don't touch other service-ids in the data, those could have be added manually in UI or in PTV. - ;; NOTE: OK, PTV updates are likely lost, because our :ptv :service-ids is what the create/update from - ;; Lipas previously returned, so if PTV ServiceLocation was modified after that in PTV, we lose those changes. - old-sports-site (assoc-in sports-site [:type :type-code] (:previous-type-code ptv)) - old-service-ids (ptv-data/sports-site->service-ids types source-id->service old-sports-site) - new-service-ids (ptv-data/sports-site->service-ids types source-id->service sports-site)] - (log/infof "Site type changed %s => %s, service-ids updated %s => %s" - (:previous-type-code ptv) type-code - old-service-ids new-service-ids) - (update ptv :service-ids (fn [x] - (->> x - (remove (fn [y] (contains? old-service-ids y))) - (into new-service-ids))))) - ptv) - resp (upsert-ptv-service-location! tx ptv-component search user - {:org-id org-id - :ptv ptv - :lipas-id lipas-id - :archive? to-archive?})] - resp)) + (try + (let [type-code (-> sports-site :type :type-code) + + previous-sent? (ptv-data/is-sent-to-ptv? sports-site) + candidate-now? (and (ptv-data/ptv-candidate? sports-site) + (ptv-data/ptv-ready? sports-site)) + + ;; If it looks like site that was previously sent to PTV is no longer + ;; a candidate, mark for it archival. + ;; The other function will mark the document Deleted when archive flag is true + to-archive? (and previous-sent? + (not candidate-now?)) + + type-code-changed? (not= type-code (:previous-type-code ptv)) + ptv (if type-code-changed? + (let [types types/all + ;; Figure out what services are available in PTV for the site organization + services (:itemList (ptv/get-org-services ptv-component org-id)) + source-id->service (->> services + (utils/index-by :sourceId)) + + ;; Check if services for the current/new site type-code exist + missing-services-input [{:service-ids #{} + :sub-category-id (-> sports-site :type :type-code types :sub-category) + :sub-cateogry (-> sports-site :search-meta :type :sub-category :name :fi)}] + missing-services (ptv-data/resolve-missing-services org-id source-id->service missing-services-input) + + ;; FE doesn't update the :ptv :service-ids, that is still handled here. + ;; This code just presumes the user has created the possibly missing Sercices + ;; in the FE first. + + _ (when (seq missing-services) + (throw (ex-info "Site needs a PTV Service that doesn't exists" + {:missing-services missing-services}))) + + ;; Remove old service-ids from :ptv data and add the new. + ;; Don't touch other service-ids in the data, those could have be added manually in UI or in PTV. + ;; NOTE: OK, PTV updates are likely lost, because our :ptv :service-ids is what the create/update from + ;; Lipas previously returned, so if PTV ServiceLocation was modified after that in PTV, we lose those changes. + old-sports-site (assoc-in sports-site [:type :type-code] (:previous-type-code ptv)) + old-service-ids (ptv-data/sports-site->service-ids types source-id->service old-sports-site) + new-service-ids (ptv-data/sports-site->service-ids types source-id->service sports-site)] + (log/infof "Site type changed %s => %s, service-ids updated %s => %s" + (:previous-type-code ptv) type-code + old-service-ids new-service-ids) + (update ptv :service-ids (fn [x] + (->> x + (remove (fn [y] (contains? old-service-ids y))) + (into new-service-ids))))) + ptv)] + (:ptv (upsert-ptv-service-location! tx ptv-component search user + {:org-id org-id + :ptv ptv + :lipas-id lipas-id + :archive? to-archive?}))) + (catch Exception e + (let [new-ptv-data (assoc ptv :error {:message (.getMessage e) + :data (ex-data e)})] + (log/infof e "Sports site updated but PTV integration had an error") + (let [resp (core/upsert-sports-site! tx + user + (-> sports-site + (assoc :event-date (utils/timestamp)) + (assoc :ptv new-ptv-data)) + false)] + (core/index! search resp :sync) + (:ptv resp)))))) (defn save-ptv-integration-definitions "Saves ptv definitions under key :ptv. Does not notify webhooks, diff --git a/webapp/src/cljc/lipas/data/ptv.cljc b/webapp/src/cljc/lipas/data/ptv.cljc index 152ca7d0d..b5cc2e922 100644 --- a/webapp/src/cljc/lipas/data/ptv.cljc +++ b/webapp/src/cljc/lipas/data/ptv.cljc @@ -395,23 +395,23 @@ summary (case descriptions-integration "lipas-managed-comment-field" - (-> site :comment parse-summary) + {:fi (-> site :comment parse-summary)} "lipas-managed-ptv-fields" (-> site :ptv :summary) "ptv-managed" ;; FIXME: avoid tr here - (tr :ptv.integration.description/ptv-managed-helper)) + {:fi (tr :ptv.integration.description/ptv-managed-helper)}) description (case descriptions-integration "lipas-managed-comment-field" - (-> site :comment) + {:fi (-> site :comment)} "lipas-managed-ptv-fields" (-> site :ptv :description) "ptv-managed" - (tr :ptv.integration.description/ptv-managed-helper)) + {:fi (tr :ptv.integration.description/ptv-managed-helper)}) last-sync (-> site :ptv :last-sync)] {:valid (boolean (and (some-> description :fi count (> 5)) diff --git a/webapp/src/cljs/lipas/ui/ptv/site_view.cljs b/webapp/src/cljs/lipas/ui/ptv/site_view.cljs index 6ce500cd2..9aa537cfb 100644 --- a/webapp/src/cljs/lipas/ui/ptv/site_view.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/site_view.cljs @@ -118,16 +118,17 @@ read-only? (not editing?) sports-site (use-subscribe [:lipas.ui.sports-sites.subs/latest-rev lipas-id]) - ;; FIXME: Edit-data and sports-site schema can be a bit different? - x (if editing? - edit-data - sports-site) + ;; NOTE: Edit-data and sports-site schema can be a bit different. + ;; Shouldn't matter for the :ptv fields we mostly need here. + site (if editing? + edit-data + sports-site) - _ (js/console.log edit-data sports-site) + ;; _ (js/console.log edit-data sports-site) - {:keys [descriptions-integration org-id sync-enabled last-sync publishing-status]} (:ptv x) + {:keys [descriptions-integration org-id sync-enabled last-sync publishing-status]} (:ptv site) - _ (js/console.log org-id) + ;; _ (js/console.log org-id) ;; default-settings {} ;; enabled (boolean (:ptv site)) @@ -135,24 +136,24 @@ loading? (use-subscribe [::subs/generating-descriptions?]) - type-code (-> x :type :type-code) + type-code (-> site :type :type-code) - type-code-changed? (not= type-code (:previous-type-code (:ptv x))) - previous-sent? (ptv-data/is-sent-to-ptv? x) - ready? (ptv-data/ptv-ready? x) - candidate-now? (ptv-data/ptv-candidate? x) + type-code-changed? (not= type-code (:previous-type-code (:ptv site))) + previous-sent? (ptv-data/is-sent-to-ptv? site) + ready? (ptv-data/ptv-ready? site) + candidate-now? (ptv-data/ptv-candidate? site) types (use-subscribe [:lipas.ui.sports-sites.subs/all-types]) loading-ptv? (use-subscribe [::subs/loading-from-ptv?]) services (use-subscribe [::subs/services-by-id org-id]) missing-services-input [{:service-ids #{} - :sub-category-id (-> x :type :type-code types :sub-category) - :sub-category (-> x :search-meta :type :sub-category :name :fi)}] + :sub-category-id (-> site :type :type-code types :sub-category) + :sub-category (-> site :search-meta :type :sub-category :name :fi)}] missing-services (when (and org-id (not loading-ptv?)) (ptv-data/resolve-missing-services org-id services missing-services-input)) source-id->service (utils/index-by :sourceId (vals services)) - new-service (ptv-data/sub-category-id->service org-id source-id->service (-> x :type :type-code types :sub-category)) + new-service (ptv-data/sub-category-id->service org-id source-id->service (-> site :type :type-code types :sub-category)) to-archive? (and previous-sent? (not candidate-now?))] @@ -191,7 +192,7 @@ :else ($ Alert {:severity "warning"} "Paikka näyttää siltä ettei sitä pidä viedä PTV")) - (when-let [e (:error (:ptv x))] + (when-let [e (:error (:ptv site))] ($ Alert {:severity "error"} "Virhe PTV integraatiossa, uusimpia tietoja ei ole viety PTV: " (:message e))) @@ -210,14 +211,14 @@ ; ($ Typography ; status)) - (when (not (:org-id (:ptv x))) + (when (not (:org-id (:ptv site))) ($ :<> ($ Alert {:severity "warning"} "Valitse organisaatio:"))) (when (seq missing-services) ($ new-service-form - {:data x + {:data site :tr tr :org-id org-id :service (first missing-services)})) @@ -241,7 +242,7 @@ :disabled (or loading? read-only?) :label "Organisaatio" - :value (:org-id (:ptv x)) + :value (:org-id (:ptv site)) :on-change (fn [_e v] (rf/dispatch [:lipas.ui.sports-sites.events/edit-field lipas-id [:ptv :org-id] (:value v)]))})) diff --git a/webapp/src/cljs/lipas/ui/ptv/views.cljs b/webapp/src/cljs/lipas/ui/ptv/views.cljs index a4d506232..994c6c38f 100644 --- a/webapp/src/cljs/lipas/ui/ptv/views.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/views.cljs @@ -250,7 +250,7 @@ ;; Summary [lui/text-field {:disabled (or loading? - (not= "manual" (:descriptions-integration site))) + (= "manual" (:descriptions-integration site))) :multiline true :variant "outlined" :on-change #(==> [::events/set-summary site @selected-tab %]) @@ -260,7 +260,7 @@ ;; Description [lui/text-field {:disabled (or loading? - (not= "manual" (:descriptions-integration site))) + (= "manual" (:descriptions-integration site))) :variant "outlined" :rows 5 :multiline true From 0158e0f1e1766c83f48fbd0e9336d63ca7d7dde6 Mon Sep 17 00:00:00 2001 From: Juho Teperi Date: Fri, 22 Nov 2024 15:33:36 +0200 Subject: [PATCH 63/68] Cleanup --- webapp/src/clj/lipas/backend/core.clj | 15 ++-- webapp/src/clj/lipas/backend/ptv/core.clj | 86 ++++++++++++--------- webapp/src/cljc/lipas/data/ptv.cljc | 25 ++++++ webapp/src/cljs/lipas/ui/ptv/events.cljs | 19 +---- webapp/src/cljs/lipas/ui/ptv/site_view.cljs | 3 +- webapp/src/cljs/lipas/ui/ptv/views.cljs | 10 +-- 6 files changed, 88 insertions(+), 70 deletions(-) diff --git a/webapp/src/clj/lipas/backend/core.clj b/webapp/src/clj/lipas/backend/core.clj index c3d437c68..f08ab764f 100644 --- a/webapp/src/clj/lipas/backend/core.clj +++ b/webapp/src/clj/lipas/backend/core.clj @@ -492,6 +492,10 @@ [db {:keys [_lipas-ids _loi-ids] :as m}] (db/add-to-webhook-queue! db m)) +(defn sync-ptv! [tx search ptv-component user props] + (let [f (resolve 'lipas.backend.ptv.core/sync-ptv!)] + (f tx search ptv-component user props))) + ;; TODO refactor upsert-sports-site!, upsert-sports-site!* and ;; save-sports-site! to form more sensible API. (defn save-sports-site! @@ -535,12 +539,11 @@ ;; NOTE: this will create a new sports-site rev. ;; Make it instead update the sports-site already created in the tx? ;; Otherwise each save-sports-site! will create two sports-site revs. - (let [new-ptv-data ((resolve 'lipas.backend.ptv.core/sync-ptv!) - tx search ptv user - {:sports-site resp - :org-id (:org-id (:ptv resp)) - :lipas-id (:lipas-id resp) - :ptv (:ptv resp)})] + (let [new-ptv-data (sync-ptv! tx search ptv user + {:sports-site resp + :org-id (:org-id (:ptv resp)) + :lipas-id (:lipas-id resp) + :ptv (:ptv resp)})] (log/infof "Sports site updated and PTV integration enabled") (assoc resp :ptv new-ptv-data)) resp))))) diff --git a/webapp/src/clj/lipas/backend/ptv/core.clj b/webapp/src/clj/lipas/backend/ptv/core.clj index 28685fa46..277c4b01c 100644 --- a/webapp/src/clj/lipas/backend/ptv/core.clj +++ b/webapp/src/clj/lipas/backend/ptv/core.clj @@ -106,8 +106,42 @@ :service-ids :service-channel-ids]) +(defn upsert-ptv-service-location!* + [tx ptv-component search user {:keys [org-id site ptv archive?] :as _m}] + (let [id (-> ptv :service-channel-ids first) + ;; merge or just replace? + site (update site :ptv merge ptv) + ;; Use the same TS for sourceId, ptv last-sync and site event-date + now (utils/timestamp) + data (ptv-data/->ptv-service-location org-id gis/wgs84->tm35fin-no-wrap now (core/enrich site)) + data (cond-> data + archive? (assoc :publishingStatus "Deleted")) + ptv-resp (if id + (ptv/update-service-location ptv-component id data) + (ptv/create-service-location ptv-component data)) + ;; Store the new PTV info to Lipas DB + new-ptv-data (-> ptv + (select-keys persisted-ptv-keys) + (assoc :last-sync now + ;; Store the current type-code into ptv data, so this can be + ;; used to comapre if the services need to recalculated on site data update. + :previous-type-code (:type-code (:type site)) + :source-id (:sourceId ptv-resp) + ;; Store the PTV status so we can ignore Lipas archived places that we already archived in PTV. + :publishing-status (:publishingStatus ptv-resp) + ;; Take the created ID from ptv response and store to Lipas DB right away. + ;; TODO: Is there a case where this could be multiple ids? + :service-channel-ids [(:id ptv-resp)]) + (cond-> + archive? (dissoc :source-id + :service-channel-ids)))] + + (log/infof "Upserted (Lipas status: %s, updated: %s) service-location %s: %s" (:status site) (boolean id) data new-ptv-data) + + [ptv-resp new-ptv-data])) + (defn upsert-ptv-service-location! - [db ptv-component search user {:keys [org-id lipas-id ptv archive?] :as _m}] + [db ptv-component search user {:keys [lipas-id org-id ptv archive?]}] ;; FIXME: This is called from inside tx in save-sports-site! is that a problem? ;; FIXME: Separate version from this fn for use in sync-ptv! which doesn't load the ;; sports site from db etc.? @@ -115,40 +149,16 @@ (let [site (db/get-sports-site db lipas-id) _ (assert (some? site) (str "Sports site " lipas-id " not found in DB")) - id (-> ptv :service-channel-ids first) - ;; merge or just replace? - site (update site :ptv merge ptv) - ;; Use the same TS for sourceId, ptv last-sync and site event-date - now (utils/timestamp) - data (ptv-data/->ptv-service-location org-id gis/wgs84->tm35fin-no-wrap now (core/enrich site)) - data (cond-> data - archive? (assoc :publishingStatus "Deleted")) - ptv-resp (if id - (ptv/update-service-location ptv-component id data) - (ptv/create-service-location ptv-component data)) - ;; Store the new PTV info to Lipas DB - new-ptv-data (-> ptv - (select-keys persisted-ptv-keys) - (assoc :last-sync now - ;; Store the current type-code into ptv data, so this can be - ;; used to comapre if the services need to recalculated on site data update. - :previous-type-code (:type-code (:type site)) - :source-id (:sourceId ptv-resp) - ;; Store the PTV status so we can ignore Lipas archived places that we already archived in PTV. - :publishing-status (:publishingStatus ptv-resp) - ;; Take the created ID from ptv response and store to Lipas DB right away. - ;; TODO: Is there a case where this could be multiple ids? - :service-channel-ids [(:id ptv-resp)]) - (cond-> - archive? (dissoc :source-id - :service-channel-ids)))] - - (log/infof "Upserted (Lipas status: %s, updated: %s) service-location %s: %s" (:status site) (boolean id) data new-ptv-data) + [ptv-resp new-ptv-data] (upsert-ptv-service-location!* tx ptv-component search user + {:org-id org-id + :site site + :ptv ptv + :archive? archive?})] (let [resp (core/upsert-sports-site! tx user (assoc site - :event-date now + :event-date (:last-sync new-ptv-data) :ptv new-ptv-data) false)] (core/index! search resp :sync)) @@ -227,12 +237,14 @@ (->> x (remove (fn [y] (contains? old-service-ids y))) (into new-service-ids))))) - ptv)] - (:ptv (upsert-ptv-service-location! tx ptv-component search user - {:org-id org-id - :ptv ptv - :lipas-id lipas-id - :archive? to-archive?}))) + ptv) + + [_ptv-resp new-ptv-data] (upsert-ptv-service-location!* tx ptv-component search user + {:org-id org-id + :ptv ptv + :site sports-site + :archive? to-archive?})] + new-ptv-data) (catch Exception e (let [new-ptv-data (assoc ptv :error {:message (.getMessage e) :data (ex-data e)})] diff --git a/webapp/src/cljc/lipas/data/ptv.cljc b/webapp/src/cljc/lipas/data/ptv.cljc index b5cc2e922..f04783c11 100644 --- a/webapp/src/cljc/lipas/data/ptv.cljc +++ b/webapp/src/cljc/lipas/data/ptv.cljc @@ -27,6 +27,31 @@ #_(def uta-org-id-test "92374b0f-7d3c-4017-858e-666ee3ca2761") #_(def uta-org-id-prod "7b83257d-06ad-4e3b-985d-16a5c9d3fced") +(def organizations + [{:name "Utajärven kunta (test)" + :props {:org-id uta-org-id-test + :city-codes [889] + :owners ["city" "city-main-owner"] + :supported-languages ["fi" "se" "en"]}} + {:name "Limingan kunta (test)" + :props {:org-id liminka-org-id-test + :city-codes [425] + :owners ["city" "city-main-owner"] + :supported-languages ["fi" "se" "en"]}} ]) + +(def org-id->params + (reduce (fn [acc x] + (assoc acc (:org-id (:props x)) + (:props x))) + {} + organizations)) + +(def orgs + (mapv (fn [x] + {:name (:name x) + :id (:org-id (:props x))}) + organizations)) + ;; TODO: Tulossa 5 kuntaa, muut: ;; (Lumijoki. Pyhäjärvi, Ii, Liminka ja Oulu sekä tietenkin bonuksena Utajärvi). diff --git a/webapp/src/cljs/lipas/ui/ptv/events.cljs b/webapp/src/cljs/lipas/ui/ptv/events.cljs index 7d1fb4e96..b4a7edede 100644 --- a/webapp/src/cljs/lipas/ui/ptv/events.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/events.cljs @@ -24,19 +24,6 @@ (fn [db [_ v]] (assoc-in db [:ptv :selected-tab] v))) -;; FIXME: Move this to data ns? -(def org-id->params - {ptv-data/uta-org-id-test ;; Utajärvi - {:org-id ptv-data/uta-org-id-test - :city-codes [889] - :owners ["city" "city-main-owner"] - :supported-languages ["fi" "se" "en"]} - ptv-data/liminka-org-id-test - {:org-id ptv-data/liminka-org-id-test - :city-codes [425] - :owners ["city" "city-main-owner"] - :supported-languages ["fi" "se" "en"]}}) - (rf/reg-event-fx ::fetch-integration-candidates (fn [{:keys [db]} [_ org]] (when org @@ -46,7 +33,7 @@ {:method :post :headers {:Authorization (str "Token " token)} :uri (str (:backend-url db) "/actions/get-ptv-integration-candidates") - :params (get org-id->params (:id org)) + :params (get ptv-data/org-id->params (:id org)) :format (ajax/transit-request-format) :response-format (ajax/transit-response-format) :on-success [::fetch-integration-candidates-success (:id org)] @@ -440,7 +427,7 @@ :uri (str (:backend-url db) "/actions/generate-ptv-service-descriptions") :params (merge - (org-id->params org-id) + (ptv-data/org-id->params org-id) {:sourceId id :sub-category-id (parse-long (last (str/split id #"-"))) :overview overview}) @@ -527,7 +514,7 @@ :uri (str (:backend-url db) "/actions/save-ptv-service") ;; FIXME: org-id->params adds some extra keys that aren't used? ;; supported-languages (languages is used instead) - :params (merge data (org-id->params org-id)) + :params (merge data (ptv-data/org-id->params org-id)) :format (ajax/transit-request-format) :response-format (ajax/transit-response-format) :on-success [::create-ptv-service-success org-id id success-fx] diff --git a/webapp/src/cljs/lipas/ui/ptv/site_view.cljs b/webapp/src/cljs/lipas/ui/ptv/site_view.cljs index 9aa537cfb..c60c7e3db 100644 --- a/webapp/src/cljs/lipas/ui/ptv/site_view.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/site_view.cljs @@ -16,7 +16,6 @@ [lipas.ui.ptv.controls :as controls] [lipas.ui.ptv.events :as events] [lipas.ui.ptv.subs :as subs] - [lipas.ui.ptv.views :as ptv-views] [lipas.ui.uix.hooks :refer [use-subscribe]] [lipas.utils :as utils] [re-frame.core :as rf] @@ -232,7 +231,7 @@ last-sync)) (let [options (uix/use-memo (fn [] - (->> ptv-views/orgs + (->> ptv-data/orgs (map (fn [{:keys [name id]}] {:label name :value id})))) diff --git a/webapp/src/cljs/lipas/ui/ptv/views.cljs b/webapp/src/cljs/lipas/ui/ptv/views.cljs index 994c6c38f..03a34032f 100644 --- a/webapp/src/cljs/lipas/ui/ptv/views.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/views.cljs @@ -32,14 +32,6 @@ ;; - ...anyway, somehow re-using stuff that's already there ;; - auto-sync on save -(def orgs - [{:name "Utajärven kunta (test)" - :id ptv-data/uta-org-id-test} - {:name "Limingan kunta (test)" - :id ptv-data/liminka-org-id-test} - #_{:name "Utajärven kunta (prod)" - :id ptv-data/uta-org-id-prod}]) - (defn lang-selector [{:keys [value on-change opts]}] (let [opts (set opts)] @@ -56,7 +48,7 @@ [{:keys [label]}] (let [selected-org (<== [::subs/selected-org])] [lui/select - {:items orgs + {:items ptv-data/orgs :label label :label-fn :name :value-fn identity From 1ab26e7a3ffad497dba1dd5918ca5753dc44fc37 Mon Sep 17 00:00:00 2001 From: Juho Teperi Date: Fri, 22 Nov 2024 15:36:54 +0200 Subject: [PATCH 64/68] Cleanup --- webapp/src/cljc/lipas/data/ptv.cljc | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/webapp/src/cljc/lipas/data/ptv.cljc b/webapp/src/cljc/lipas/data/ptv.cljc index f04783c11..3bcb4c944 100644 --- a/webapp/src/cljc/lipas/data/ptv.cljc +++ b/webapp/src/cljc/lipas/data/ptv.cljc @@ -27,6 +27,9 @@ #_(def uta-org-id-test "92374b0f-7d3c-4017-858e-666ee3ca2761") #_(def uta-org-id-prod "7b83257d-06ad-4e3b-985d-16a5c9d3fced") +;; TODO: Tulossa 5 kuntaa, muut: +;; (Lumijoki. Pyhäjärvi, Ii, Liminka ja Oulu sekä tietenkin bonuksena Utajärvi). + (def organizations [{:name "Utajärven kunta (test)" :props {:org-id uta-org-id-test @@ -39,6 +42,10 @@ :owners ["city" "city-main-owner"] :supported-languages ["fi" "se" "en"]}} ]) +;; For adding default params to some requests from the FE +;; NOTE: This should eventually be replaced with Lipas organizations. +;; TODO: Not sure if e.g. owners and supported-languages should be +;; hardcoded to the same values for everyone? (def org-id->params (reduce (fn [acc x] (assoc acc (:org-id (:props x)) @@ -46,15 +53,13 @@ {} organizations)) +;; For UI org dropdown (def orgs (mapv (fn [x] {:name (:name x) :id (:org-id (:props x))}) organizations)) -;; TODO: Tulossa 5 kuntaa, muut: -;; (Lumijoki. Pyhäjärvi, Ii, Liminka ja Oulu sekä tietenkin bonuksena Utajärvi). - (def lang->locale {"fi" :fi, "sv" :se, "en" :en}) From 1268a7f81eb922eadc2ffef5f2496db31ae4f803 Mon Sep 17 00:00:00 2001 From: Juho Teperi Date: Fri, 22 Nov 2024 15:56:35 +0200 Subject: [PATCH 65/68] Show ptv site tab using ptv/manage privilege --- webapp/src/cljs/lipas/ui/map/views.cljs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/webapp/src/cljs/lipas/ui/map/views.cljs b/webapp/src/cljs/lipas/ui/map/views.cljs index 82550ce22..2f6e81643 100644 --- a/webapp/src/cljs/lipas/ui/map/views.cljs +++ b/webapp/src/cljs/lipas/ui/map/views.cljs @@ -810,6 +810,9 @@ view-floorball? (when floorball-type? (<== [:lipas.ui.user.subs/check-privilege role-site-ctx :floorball/view])) edit-floorball? (when floorball-type? (<== [:lipas.ui.user.subs/check-privilege role-site-ctx :floorball/edit])) + ;; TODO: Maybe always show the ptv tab if the ptv integration is enabled for the site? + view-ptv? (<== [:lipas.ui.user.subs/check-privilege role-site-ctx :ptv/manage]) + hide-actions? (<== [::subs/hide-actions?]) ;; FIXME: Bad pattern to combine n subs into one @@ -932,10 +935,11 @@ :value 4 :label (tr :sports-site.elevation-profile/headline)}]) - [mui/tab - {:style {:min-width 0} - :value 6 - :label "PTV"}]] + (when view-ptv? + [mui/tab + {:style {:min-width 0} + :value 6 + :label "PTV"}])] (when delete-dialog-open? [sports-sites/delete-dialog From cd48b45e7feffac803eee67ccb9b5a7650681f21 Mon Sep 17 00:00:00 2001 From: Juho Teperi Date: Fri, 22 Nov 2024 16:02:58 +0200 Subject: [PATCH 66/68] Cleanup site tab content order --- webapp/src/cljs/lipas/ui/ptv/site_view.cljs | 114 +++++++++++--------- 1 file changed, 62 insertions(+), 52 deletions(-) diff --git a/webapp/src/cljs/lipas/ui/ptv/site_view.cljs b/webapp/src/cljs/lipas/ui/ptv/site_view.cljs index c60c7e3db..339fdf677 100644 --- a/webapp/src/cljs/lipas/ui/ptv/site_view.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/site_view.cljs @@ -111,6 +111,7 @@ (defui site-view [{:keys [tr lipas-id can-edit? edit-data]}] (let [[selected-tab set-selected-tab] (uix/use-state :fi) + locale (tr) editing* (boolean (use-subscribe [:lipas.ui.sports-sites.subs/editing? lipas-id])) editing? (and can-edit? editing*) @@ -154,10 +155,12 @@ source-id->service (utils/index-by :sourceId (vals services)) new-service (ptv-data/sub-category-id->service org-id source-id->service (-> site :type :type-code types :sub-category)) + new-service-sub-cat (get types/sub-categories (-> site :type :type-code types :sub-category)) + to-archive? (and previous-sent? (not candidate-now?))] - (js/console.log missing-services new-service) + (js/console.log missing-services new-service new-service-sub-cat) (uix/use-effect (fn [] (rf/dispatch [::events/fetch-org {:id org-id}]) @@ -170,39 +173,8 @@ ;; TODO: Spinneri? (when loading-ptv? - ($ Alert {:severity "info"} - "Ladataan PTV tietoja...")) - - (cond - (and previous-sent? candidate-now? ready?) - (if sync-enabled - ($ Alert {:severity "success"} "PTV integraatio käytössä") - ($ Alert {:severity "success"} "PTV integraatio käytössä, mutta paikan synkronointi PTV on kytketty pois päältä.")) - - (and previous-sent? (not candidate-now?)) - ($ Alert {:severity "warning"} "Paikka on viety PTV, mutta on muutettu niin että näyttää nyt siltä että sen ei pidä mennä PTV -> PTV palvelu paikka arkistoidaan tallennuksessa.") - - (and candidate-now? ready?) - ($ Alert {:severity "info"} "Paikkaa ei viety PTV, mutta palvelu paikka luodaan tallennuksessa") - - (not ready?) - ($ Alert {:severity "info"} "PTV tiedot ovat vielä puutteelliset, täytä tiedot niin paikka viedään PTV tallennuksen yhteydessä") - - :else - ($ Alert {:severity "warning"} "Paikka näyttää siltä ettei sitä pidä viedä PTV")) - - (when-let [e (:error (:ptv site))] - ($ Alert {:severity "error"} - "Virhe PTV integraatiossa, uusimpia tietoja ei ole viety PTV: " (:message e))) - - (when candidate-now? - (cond - (seq missing-services) - ($ Alert {:severity "warning"} "Lipas tyyppi muuttuu, service puuttuu PTV") - - (and previous-sent? type-code-changed?) - ($ Alert {:severity "info"} "Lipas tyyppi muuttuu, uusi service " (:id new-service)) - )) + ($ Alert {:severity "info"} + "Ladataan PTV tietoja...")) ; ($ FormControl ; ($ FormLabel @@ -211,24 +183,9 @@ ; status)) (when (not (:org-id (:ptv site))) - ($ :<> - ($ Alert {:severity "warning"} - "Valitse organisaatio:"))) - - (when (seq missing-services) - ($ new-service-form - {:data site - :tr tr - :org-id org-id - :service (first missing-services)})) - - ($ FormControl - ($ FormLabel - "PTV Tila") - ($ Typography - publishing-status) - ($ Typography - last-sync)) + ($ :<> + ($ Alert {:severity "warning"} + "Valitse organisaatio:"))) (let [options (uix/use-memo (fn [] (->> ptv-data/orgs @@ -245,6 +202,59 @@ :on-change (fn [_e v] (rf/dispatch [:lipas.ui.sports-sites.events/edit-field lipas-id [:ptv :org-id] (:value v)]))})) + ($ FormControl + ($ FormLabel + "PTV Tila") + (cond + (:error (:ptv site)) + (let [e (:error (:ptv site))] + ($ Alert {:severity "error"} + "Virhe PTV integraatiossa, uusimpia tietoja ei ole viety PTV: " (:message e))) + + (and previous-sent? candidate-now? ready?) + (if sync-enabled + ($ Alert {:severity "success"} "PTV integraatio käytössä") + ($ Alert {:severity "success"} "PTV integraatio käytössä, mutta paikan synkronointi PTV on kytketty pois päältä.")) + + (and previous-sent? (not candidate-now?)) + ($ Alert {:severity "warning"} "Paikka on viety PTV, mutta on muutettu niin että näyttää nyt siltä että sen ei pidä mennä PTV -> PTV palvelu paikka arkistoidaan tallennuksessa.") + + (and candidate-now? ready?) + ($ Alert {:severity "info"} "Paikkaa ei viety PTV, mutta palvelu paikka luodaan tallennuksessa") + + (not ready?) + ($ Alert {:severity "info"} "PTV tiedot ovat vielä puutteelliset, täytä tiedot niin paikka viedään PTV tallennuksen yhteydessä") + + :else + ($ Alert {:severity "warning"} "Paikka näyttää siltä ettei sitä pidä viedä PTV") + + ; ($ Typography + ; publishing-status) + ; ($ Typography + ; last-sync) + )) + + (when candidate-now? + ($ FormControl + ($ FormLabel + "PTV Palvelu") + ($ Typography + (get-in new-service-sub-cat [:name locale])) + (cond + (seq missing-services) + ($ Alert {:severity "warning"} "Liikuntapaikkatyyppiä vaihdettu, uusi PTV Palvelu puuttuu") + + (and previous-sent? type-code-changed?) + ($ Alert {:severity "info"} "Liikuntapaikkatyyppiä vaihdettu, vaihdetaan PTV Palvelu")) + )) + + (when (seq missing-services) + ($ new-service-form + {:data site + :tr tr + :org-id org-id + :service (first missing-services)})) + #_ ($ controls/description-integration {:value (:descriptions-integration (:ptv site)) From f66d0250ccaf56bf6b6f994c2ea99cf18f847b94 Mon Sep 17 00:00:00 2001 From: Juho Teperi Date: Fri, 22 Nov 2024 16:26:36 +0200 Subject: [PATCH 67/68] Mostly remove ptv integration options --- webapp/src/clj/lipas/backend/ptv/handler.clj | 11 +- webapp/src/cljc/lipas/data/ptv.cljc | 33 +- webapp/src/cljc/lipas/schema/core.cljc | 12 +- webapp/src/cljs/lipas/ui/ptv/controls.cljs | 102 ------ webapp/src/cljs/lipas/ui/ptv/db.cljs | 1 + webapp/src/cljs/lipas/ui/ptv/site_view.cljs | 48 ++- webapp/src/cljs/lipas/ui/ptv/subs.cljs | 9 +- webapp/src/cljs/lipas/ui/ptv/views.cljs | 333 +++---------------- webapp/test/clj/lipas/backend/ptv_test.clj | 3 +- 9 files changed, 81 insertions(+), 471 deletions(-) diff --git a/webapp/src/clj/lipas/backend/ptv/handler.clj b/webapp/src/clj/lipas/backend/ptv/handler.clj index 2addbdc55..050723b2a 100644 --- a/webapp/src/clj/lipas/backend/ptv/handler.clj +++ b/webapp/src/clj/lipas/backend/ptv/handler.clj @@ -18,8 +18,15 @@ {:closed true} ;; [:org-id :string] [:sync-enabled :boolean] - [:service-channel-integration integration-enum] - [:service-integration integration-enum] + + ;; These options aren't used now: + ;; TODO: Remove + [:service-channel-integration + {:optional true} + integration-enum] + [:service-integration + {:optional true} + integration-enum] [:service-channel-ids [:vector :string]] ;; [:service-ids [:vector :string]] diff --git a/webapp/src/cljc/lipas/data/ptv.cljc b/webapp/src/cljc/lipas/data/ptv.cljc index 3bcb4c944..65d5af9f7 100644 --- a/webapp/src/cljc/lipas/data/ptv.cljc +++ b/webapp/src/cljc/lipas/data/ptv.cljc @@ -417,31 +417,11 @@ {:service-channel-id (:id service-channel)}))) service-channels))) -(defn sports-site->ptv-input [{:keys [tr types org-id org-defaults org-langs]} service-channels services site] +(defn sports-site->ptv-input [{:keys [types org-id org-defaults org-langs]} service-channels services site] (let [service-id (-> site :ptv :service-ids first) service-channel-id (-> site :ptv :service-channel-ids first) - descriptions-integration (or (-> site :ptv :descriptions-integration) - (:descriptions-integration org-defaults)) - - summary (case descriptions-integration - "lipas-managed-comment-field" - {:fi (-> site :comment parse-summary)} - - "lipas-managed-ptv-fields" - (-> site :ptv :summary) - - "ptv-managed" - ;; FIXME: avoid tr here - {:fi (tr :ptv.integration.description/ptv-managed-helper)}) - description (case descriptions-integration - "lipas-managed-comment-field" - {:fi (-> site :comment)} - - "lipas-managed-ptv-fields" - (-> site :ptv :description) - - "ptv-managed" - {:fi (tr :ptv.integration.description/ptv-managed-helper)}) + summary (-> site :ptv :summary) + description (-> site :ptv :description) last-sync (-> site :ptv :last-sync)] {:valid (boolean (and (some-> description :fi count (> 5)) @@ -462,7 +442,6 @@ :description description :languages (or (-> site :ptv :languages) org-langs) - :descriptions-integration descriptions-integration :sync-enabled (get-in site [:ptv :sync-enabled] true) :last-sync last-sync ;; :last-sync-human (some-> last-sync utils/->human-date-time-at-user-tz) @@ -475,14 +454,10 @@ :service-ids (-> site :ptv :service-ids) :service-name (-> services (get service-id) :serviceNames (->> (some #(when (= "fi" (:language %)) (:value %))))) - :service-integration (or (-> site :ptv :service-integration) - (:service-integration org-defaults)) :service-channel-id service-channel-id :service-channel-ids (-> site :ptv :service-channel-ids) :service-channel-name (-> (get service-channels service-channel-id) - (resolve-service-channel-name)) - :service-channel-integration (or (-> site :ptv :service-channel-integration) - (:service-channel-integration org-defaults))})) + (resolve-service-channel-name))})) (defn sports-site->service-ids [types source-id->service sports-site] (let [sub-cat-id (-> sports-site :type :type-code types :sub-category) diff --git a/webapp/src/cljc/lipas/schema/core.cljc b/webapp/src/cljc/lipas/schema/core.cljc index 0f7584fd4..439f5eecf 100644 --- a/webapp/src/cljc/lipas/schema/core.cljc +++ b/webapp/src/cljc/lipas/schema/core.cljc @@ -1519,12 +1519,7 @@ :lipas.sports-site.ptv/sync-enabled :lipas.sports-site.ptv/summary - :lipas.sports-site.ptv/description - - :lipas.sports-site.ptv/service-channel-integration - :lipas.sports-site.ptv/service-integration - :lipas.sports-site.ptv/descriptions-integration - ] + :lipas.sports-site.ptv/description] :opt-un [;; Added on first successful sync :lipas.sports-site.ptv/last-sync :lipas.sports-site.ptv/previous-type-code @@ -1536,6 +1531,11 @@ :lipas.sports-site.ptv/source-id :lipas.sports-site.ptv/service-channel-ids + ;; Previously used keys, not used now + :lipas.sports-site.ptv/service-channel-integration + :lipas.sports-site.ptv/service-integration + :lipas.sports-site.ptv/descriptions-integration + ;; Only added on sync error - removed when success :lipas.sports-site.ptv/error])) diff --git a/webapp/src/cljs/lipas/ui/ptv/controls.cljs b/webapp/src/cljs/lipas/ui/ptv/controls.cljs index d0cd125a3..38dd8dcf9 100644 --- a/webapp/src/cljs/lipas/ui/ptv/controls.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/controls.cljs @@ -33,108 +33,6 @@ :on-change (fn [_e v] (on-change (:value v)))}))) -(defui service-integration [{:keys [tr value on-change service-ids set-service-ids services]}] - ($ :<> - ($ Typography {:variant "h6"} - (tr :ptv/services)) - - ;; Integration type - ($ FormControl - ($ FormLabel (tr :ptv.actions/select-integration)) - ($ RadioGroup - {:on-change (fn [_e v] (on-change v)) - :value value} - ($ FormControlLabel - {:value "lipas-managed" - :label (tr :ptv.integration.service/lipas-managed) - :control ($ Radio)}) - - ($ FormControlLabel - {:value "manual" - :label (tr :ptv.integration/manual) - :control ($ Radio)}))) - - (when (= "lipas-managed" value) - (tr :ptv.integration.service/lipas-managed-helper)) - - (when (= "manual" value) - ($ services-selector - {:options services - :value service-ids - :on-change set-service-ids - :value-fn :service-id - :label (tr :ptv.actions/select-service)})))) - -(defui service-channel-integration [{:keys [tr value on-change]}] - ($ :<> - ($ Typography {:variant "h6"} - (tr :ptv/service-channels)) - - ;; Integration type - ($ FormControl - ($ FormLabel (tr :ptv.actions/select-integration)) - ($ RadioGroup - {:on-change (fn [_e v] (on-change v)) - :value value} - ($ FormControlLabel - {:value "lipas-managed" - :label (tr :ptv.integration.service-channel/lipas-managed) - :control ($ Radio)}) - - ($ FormControlLabel - {:value "manual" - :label (tr :ptv.integration/manual) - :control ($ Radio)}))) - - (case value - "lipas-managed" - ($ info-text (tr :ptv.integration.service-channel/lipas-managed-helper)) - - "manual" - ($ info-text (tr :ptv.integration.service-channel/manual-helper)) - - nil))) - -(defui description-integration [{:keys [tr value on-change]}] - ($ :<> - ($ Typography - {:variant "h6"} - (tr :ptv/descriptions)) - - ;; Integration type - ($ FormControl - ($ FormLabel (tr :ptv.actions/select-integration)) - ($ RadioGroup - {:on-change (fn [_e v] - (on-change v)) - :value value} - ($ FormControlLabel - {:value "lipas-managed-ptv-fields" - :label (tr :ptv.integration.description/lipas-managed-ptv-fields) - :control ($ Radio)}) - - ($ FormControlLabel - {:value "lipas-managed-comment-field" - :label (tr :ptv.integration.description/lipas-managed-comment-field) - :control ($ Radio)}) - - ($ FormControlLabel - {:value "ptv-managed" - :label (tr :ptv.integration.description/ptv-managed) - :control ($ Radio)}))) - - (case value - "lipas-managed-ptv-fields" - ($ Typography (tr :ptv.integration.description/lipas-managed-ptv-fields-helper)) - - "lipas-managed-comment-field" - ($ Typography (tr :ptv.integration.description/lipas-managed-comment-field-helper)) - - "ptv-managed" - ($ Typography (tr :ptv.integration.description/ptv-managed-helper)) - - nil))) - (defui lang-selector [{:keys [value on-change]}] ($ Tabs {:value value diff --git a/webapp/src/cljs/lipas/ui/ptv/db.cljs b/webapp/src/cljs/lipas/ui/ptv/db.cljs index f3d4dd172..f26b63b13 100644 --- a/webapp/src/cljs/lipas/ui/ptv/db.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/db.cljs @@ -6,6 +6,7 @@ :service-channels false :service-collections false} :default-settings {:sync-enabled true + ;; TODO: These are not used now, could be removed once made optional in the schemas: :service-integration "lipas-managed" :service-channel-integration "lipas-managed" :descriptions-integration "lipas-managed-ptv-fields" diff --git a/webapp/src/cljs/lipas/ui/ptv/site_view.cljs b/webapp/src/cljs/lipas/ui/ptv/site_view.cljs index 339fdf677..a08d527d8 100644 --- a/webapp/src/cljs/lipas/ui/ptv/site_view.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/site_view.cljs @@ -126,13 +126,12 @@ ;; _ (js/console.log edit-data sports-site) - {:keys [descriptions-integration org-id sync-enabled last-sync publishing-status]} (:ptv site) + {:keys [org-id sync-enabled last-sync publishing-status]} (:ptv site) ;; _ (js/console.log org-id) ;; default-settings {} ;; enabled (boolean (:ptv site)) - descriptions-enabled (not= "manual" descriptions-integration) loading? (use-subscribe [::subs/generating-descriptions?]) @@ -255,12 +254,6 @@ :org-id org-id :service (first missing-services)})) - #_ - ($ controls/description-integration - {:value (:descriptions-integration (:ptv site)) - :on-change identity - :tr tr}) - ($ FormControlLabel {:label "Sync-enabled" :control ($ Switch @@ -271,25 +264,24 @@ (js/console.log _e v) (rf/dispatch [:lipas.ui.sports-sites.events/edit-field lipas-id [:ptv :sync-enabled] v]))})}) - (when (= "lipas-managed-ptv-fields" descriptions-integration) - ($ Stack - {:sx #js {:position "relative"}} - ($ Button - {:disabled (or loading? - read-only?) - :variant "outlined" - ;; NOTE: Could use the lipas-id version when not editing? But then we don't have - ;; place to store the results. - :on-click (fn [_e] - (rf/dispatch [::events/generate-descriptions-from-data lipas-id]))} - (tr :ptv.actions/generate-with-ai)) - (when loading? - ($ CircularProgress - {:size 24 - :sx #js {:position "absolute" - :top "50%" - :left "50%" - :mt "-12px"}})))) + ($ Stack + {:sx #js {:position "relative"}} + ($ Button + {:disabled (or loading? + read-only?) + :variant "outlined" + ;; NOTE: Could use the lipas-id version when not editing? But then we don't have + ;; place to store the results. + :on-click (fn [_e] + (rf/dispatch [::events/generate-descriptions-from-data lipas-id]))} + (tr :ptv.actions/generate-with-ai)) + (when loading? + ($ CircularProgress + {:size 24 + :sx #js {:position "absolute" + :top "50%" + :left "50%" + :mt "-12px"}}))) ($ controls/lang-selector {:value selected-tab @@ -299,7 +291,6 @@ (r/as-element [lui/text-field {:disabled (or loading? - (not descriptions-enabled) read-only?) :multiline true :variant "outlined" @@ -313,7 +304,6 @@ (r/as-element [lui/text-field {:disabled (or loading? - (not descriptions-enabled) read-only?) :variant "outlined" :rows 5 diff --git a/webapp/src/cljs/lipas/ui/ptv/subs.cljs b/webapp/src/cljs/lipas/ui/ptv/subs.cljs index f12358ed6..eb7233497 100644 --- a/webapp/src/cljs/lipas/ui/ptv/subs.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/subs.cljs @@ -197,8 +197,9 @@ (vals channels))) (rf/reg-sub ::service-channels-list - :<- [::service-channels] - (fn [channels _] + (fn [[_ org-id]] + (rf/subscribe [::service-channels org-id])) + (fn [channels [_ _org-id]] (for [m channels] {:service-channel-id (:id m) :name (ptv-data/resolve-service-channel-name m)}))) @@ -209,14 +210,12 @@ (rf/subscribe [::services-by-id org-id]) (rf/subscribe [::service-channels-by-id org-id]) (rf/subscribe [::default-settings org-id]) - (rf/subscribe [:lipas.ui.subs/translator]) (rf/subscribe [:lipas.ui.sports-sites.subs/all-types]) (rf/subscribe [::org-languages org-id])]) - (fn [[ptv services service-channels org-defaults tr types org-langs] [_ org-id]] + (fn [[ptv services service-channels org-defaults types org-langs] [_ org-id]] (let [lipas-id->site (get-in ptv [:org org-id :data :sports-sites])] (for [site (vals lipas-id->site)] (ptv-data/sports-site->ptv-input {:org-id org-id - :tr tr :types types :org-defaults org-defaults :org-langs org-langs} diff --git a/webapp/src/cljs/lipas/ui/ptv/views.cljs b/webapp/src/cljs/lipas/ui/ptv/views.cljs index 03a34032f..0c559cebb 100644 --- a/webapp/src/cljs/lipas/ui/ptv/views.cljs +++ b/webapp/src/cljs/lipas/ui/ptv/views.cljs @@ -56,10 +56,10 @@ :on-change #(==> [::events/select-org %])}])) (defui service-channel-selector - [{:keys [value on-change label value-fn] + [{:keys [org-id value on-change label value-fn] :or {value-fn identity label ""}}] - (let [items (use-subscribe [::subs/service-channels-list]) + (let [items (use-subscribe [::subs/service-channels-list org-id]) options (uix/use-memo (fn [] (map (fn [x] {:value (value-fn x) @@ -75,97 +75,9 @@ (println v) (on-change [(:value v)]))}))) -(defn info-text - [s] - #_[mui/paper {:style {:padding "1em" :background-color mui/gray3}}] - [mui/typography {:variant "body1" #_#_:style {:font-size "0.9rem"}} s]) - -(defn settings - [] - (let [tr (<== [:lipas.ui.subs/translator]) - org-id (<== [::subs/selected-org-id]) - default-settings (<== [::subs/default-settings org-id])] - [mui/grid {:container true :spacing 4 :style {:margin-left "-32px"}} - - [mui/grid {:item true :xs 12} - [mui/stack {:spacing 2} - - [mui/typography {:variant "h5"} - (tr :ptv.integration.interval/headline)] - - [mui/form-control - [mui/form-label (tr :ptv.integration.interval/label)] - [mui/radio-group - {:on-change #(==> [::events/select-integration-interval %2]) - :value (:integration-interval default-settings)} - [mui/form-control-label - {:value "immediate" - :label (tr :ptv.integration.interval/immediate) - :control (r/as-element [mui/radio])}] - - [mui/form-control-label - {:value "daily" - :label (tr :ptv.integration.interval/daily) - :control (r/as-element [mui/radio])}] - - [mui/form-control-label - {:value "manual" - :label (tr :ptv.integration.interval/manual) - :control (r/as-element [mui/radio])}]]]]] - - [mui/grid {:item true :xs 12} - [mui/typography {:variant "h5"} (tr :ptv.integration.default-settings/headline)]] - - [mui/grid {:item true :xs 12} - [info-text (tr :ptv.integration.default-settings/helper)]] - - ;; Service - [mui/grid {:item true :xs 12 :lg 4} - [mui/stack {:spacing 2} - [mui/typography {:variant "h6"} - (tr :ptv/services)] - - ;; Integration type - [mui/form-control - [mui/form-label (tr :ptv.actions/select-integration)] - [mui/radio-group - {:on-change #(==> [::events/select-service-integration-default %2]) - :value (:service-integration default-settings)} - [mui/form-control-label - {:value "lipas-managed" - :label (tr :ptv.integration.service/lipas-managed) - :control (r/as-element [mui/radio])}] - - [mui/form-control-label - {:value "manual" - :label (tr :ptv.integration/manual) - :control (r/as-element [mui/radio])}]]] - - (when (= "lipas-managed" (:service-integration default-settings)) - [info-text (tr :ptv.integration.service/lipas-managed-helper)]) - - (when (= "manual" (:service-integration default-settings)) - [info-text (tr :ptv.integration.service/manual-helper)])]] - - ;; Service channel - [mui/grid {:item true :xs 12 :lg 4} - [mui/stack {:spacing 2} - ($ controls/service-channel-integration - {:tr tr - :value (:service-channel-integration default-settings) - :on-change (fn [v] (rf/dispatch [::events/select-service-channel-integration-default v]))})]] - - ;; Descriptions - [mui/grid {:item true :xs 12 :lg 4} - [mui/stack {:spacing 2} - ($ controls/description-integration - {:tr tr - :value (:descriptions-integration default-settings) - :on-change (fn [v] (rf/dispatch [::events/select-descriptions-integration-default v]))})]]])) - (defn form - [{:keys [tr site]}] - (let [locale (tr)] + [{:keys [org-id tr site]}] + (let [services @(rf/subscribe [::subs/services org-id])] [mui/grid {:container true :spacing 2 @@ -174,12 +86,15 @@ ;; Service [mui/grid {:item true :xs 12 :lg 4} [mui/stack {:spacing 2} - ($ controls/service-integration - {:tr tr - :value (:service-integration site) - :on-change (fn [v] (==> [::events/select-service-integration site v])) - :service-ids (:service-ids site) - :set-service-ids (fn [ids] (rf/dispatch [::events/select-services site ids]))})]] + [mui/typography {:variant "h6"} + (tr :ptv/services)] + + ($ controls/services-selector + {:options services + :value (:service-ids site) + :on-change (fn [ids] (rf/dispatch [::events/select-services site ids])) + :value-fn :service-id + :label (tr :ptv.actions/select-service)})]] ;; Service channels [mui/grid {:item true :xs 12 :lg 4} @@ -187,47 +102,24 @@ [mui/typography {:variant "h6"} (tr :ptv/service-channels)] - ;; Integration type - [mui/form-control - [mui/form-label (tr :ptv.actions/select-integration)] - [mui/radio-group - {:on-change #(==> [::events/select-service-channel-integration site %2]) - :value (:service-channel-integration site)} - [mui/form-control-label - {:value "lipas-managed" - :label (tr :ptv.integration.service-channel/lipas-managed) - :control (r/as-element [mui/radio])}] - - [mui/form-control-label - {:value "manual" - :label (tr :ptv.integration/manual) - :control (r/as-element [mui/radio])}]]] - - (when (= "lipas-managed" (:service-channel-integration site)) - (tr :ptv.integration.service-channel/lipas-managed-helper)) - - (when (= "manual" (:service-channel-integration site)) - ($ service-channel-selector - {:value (:service-channel-ids site) - :value-fn :id - :on-change #(==> [::events/select-service-channels site %]) - :label (tr :ptv.actions/select-service-channel)}))]] + ($ service-channel-selector + {:org-id org-id + :value (:service-channel-ids site) + :value-fn :service-channel-id + :on-change #(==> [::events/select-service-channels site %]) + :label (tr :ptv.actions/select-service-channel)})]] ;; Descriptions (r/with-let [selected-tab (r/atom :fi)] (let [loading? (<== [::subs/generating-descriptions?])] [mui/grid {:item true :xs 12 :lg 4} [mui/stack {:spacing 2} + [mui/typography {:variant "h6"} + (tr :ptv/descriptions)] - ($ controls/description-integration - {:tr tr - :value (:descriptions-integration site) - :on-change (fn [v] (rf/dispatch [::events/select-descriptions-integration site v]))}) - - (when (= "lipas-managed-ptv-fields" (:descriptions-integration site)) - [mui/button {:disabled loading? - :on-click #(==> [::events/generate-descriptions (:lipas-id site) [] []])} - (tr :ptv.actions/generate-with-ai)]) + [mui/button {:disabled loading? + :on-click #(==> [::events/generate-descriptions (:lipas-id site) [] []])} + (tr :ptv.actions/generate-with-ai)] (when loading? [mui/circular-progress]) @@ -241,8 +133,7 @@ ;; Summary [lui/text-field - {:disabled (or loading? - (= "manual" (:descriptions-integration site))) + {:disabled loading? :multiline true :variant "outlined" :on-change #(==> [::events/set-summary site @selected-tab %]) @@ -251,8 +142,7 @@ ;; Description [lui/text-field - {:disabled (or loading? - (= "manual" (:descriptions-integration site))) + {:disabled loading? :variant "outlined" :rows 5 :multiline true @@ -394,131 +284,9 @@ [mui/collapse {:in (get @expanded-rows lipas-id false) :timeout "auto" :unmountOnExit true} - [form {:tr tr :site site}]]]]]))]]])))) - -(defn descriptions-generator - [] - (let [tr (<== [:lipas.ui.subs/translator]) - org-id (<== [::subs/selected-org-id]) - sports-sites (<== [::subs/sports-sites-filtered org-id]) - sports-sites-count (<== [::subs/sports-sites-filtered-count org-id]) - sports-sites-filter (<== [::subs/sports-sites-filter]) - - {:keys [in-progress? - processed-lipas-ids - processed-count - total-count - processed-percent - halt?] :as m} (<== [::subs/batch-descriptions-generation-progress])] - - [lui/expansion-panel {:default-expanded false :label (tr :ptv.tools.ai/headline)} - [mui/grid {:container true :spacing 4} - [mui/grid {:item true :xs 12 :lg 4} - - ;; Settings - [mui/stack {:spacing 4} - [mui/typography (tr :ptv.tools.ai/start-helper)] - - [mui/form-control - [mui/form-label (tr :ptv.tools.ai.sports-sites-filter/label)] - [mui/radio-group - {:on-change #(==> [::events/select-sports-sites-filter %2]) - :value sports-sites-filter} - [mui/form-control-label - {:value "all" - :label (tr :ptv.tools.ai.sports-sites-filter/all) - :control (r/as-element [mui/radio])}] - - [mui/form-control-label - {:value "no-existing-description" - :label (tr :ptv.tools.ai.sports-sites-filter/no-existing-description) - :control (r/as-element [mui/radio])}] - - [mui/form-control-label - {:value "sync-enabled" - :label (tr :ptv.tools.ai.sports-sites-filter/sync-enabled) - :control (r/as-element [mui/radio])}] - - [mui/form-control-label - {:value "sync-enabled-no-existing-description" - :label (tr :ptv.tools.ai.sports-sites-filter/sync-enabled-no-existing-description) - :control (r/as-element [mui/radio])}] - - #_[mui/form-control-label - {:value "manual" - :label (tr :ptv.tools.ai.sports-sites-filter/manual) - :control (r/as-element [mui/radio])}]]] - - ;; Start button - [mui/button - {:variant "outlined" - :disabled in-progress? - :color "secondary" - :startIcon (r/as-element [mui/icon "play_arrow"]) - :on-click #(==> [::events/generate-all-descriptions sports-sites])} - (tr :ptv.tools.ai/start)] - - ;; Cancel button - (when in-progress? - [mui/button - {:variant "outlined" - :disabled halt? - :color "secondary" - :startIcon (r/as-element [mui/icon "cancel"]) - :on-click #(==> [::events/halt-descriptions-generation])} - (tr :actions/cancel)]) - - (when (and halt? in-progress?) - [mui/typography (tr :ptv.tools.ai/canceling)]) - - (when in-progress? - [mui/stack {:direction "row" :spacing 2 :align-items "center"} - [mui/circular-progress {:variant "indeterminate" :value processed-percent}] - [mui/typography (str processed-count "/" total-count)]])]] - - ;; Results - (r/with-let [selected-tab (r/atom :fi)] - [mui/grid {:item true :xs 12 :lg 8} - [mui/stack {:spacing 4} - - [mui/typography {:variant "h6"} - (tr :ptv/sports-sites)] - - [mui/typography {:variant "subtitle1" :style {:margin-top "0px"}} - (str sports-sites-count " kpl")] - - (doall - (for [{:keys [lipas-id] :as site} sports-sites] - ^{:key lipas-id} - [lui/expansion-panel - {:label (:name site) - :disabled (not (contains? processed-lipas-ids lipas-id))} - [mui/stack {:spacing 2} - [mui/tabs - {:value @selected-tab - :on-change #(reset! selected-tab (keyword %2))} - [mui/tab {:value "fi" :label "FI"}] - [mui/tab {:value "se" :label "SE"}] - [mui/tab {:value "en" :label "EN"}]] - - ;; Summary - [lui/text-field - {:multiline true - :read-only? (not= "manual" (:descriptions-integration site)) - :variant "outlined" - :on-change #(==> [::events/set-summary site @selected-tab %]) - :label (tr :ptv/summary) - :value (get-in site [:summary @selected-tab])}] - - ;; Description - [lui/text-field - {:variant "outlined" - :read-only? (not= "manual" (:descriptions-integration site)) - :rows 5 - :multiline true - :on-change #(==> [::events/set-description site @selected-tab %]) - :label (tr :ptv/description) - :value (get-in site [:description @selected-tab])}]]]))]])]])) + [form {:tr tr + :org-id org-id + :site site}]]]]]))]]])))) (defn create-services [] @@ -532,7 +300,7 @@ total-count processed-count]} (<== [::subs/service-descriptions-generation-progress]) - services @(rf/subscribe [::subs/services])] + services @(rf/subscribe [::subs/services org-id])] [lui/expansion-panel {:label (str "1. " (tr :ptv.tools.generate-services/headline)) @@ -607,22 +375,6 @@ [mui/icon {:color "success"} "done"] [mui/icon {:color "disabled"} "done"])} [mui/stack {:spacing 2} - - #_[mui/form-control - [mui/form-label (tr :ptv.integration.interval/label)] - [mui/radio-group - {:on-change #(==> [::events/select-integration-interval %2]) - :value "lipas-managed"} - [mui/form-control-label - {:value "lipas-managed" - :label (tr :ptv.integration.service/lipas-managed) - :control (r/as-element [mui/radio])}] - - [mui/form-control-label - {:value "manual" - :label (tr :ptv.integration/manual) - :control (r/as-element [mui/radio])}]]] - [lui/autocomplete {:label (tr :ptv.actions/select-languages) :multi? true @@ -670,8 +422,8 @@ :value (get-in m [:description @selected-tab])}]]]))]]]]]))) (defui service-location-details - [{:keys [tr site lipas-id sync-enabled name-conflict service-ids selected-tab set-selected-tab service-channel-ids]}] - (let [services (use-subscribe [::subs/services])] + [{:keys [org-id tr site lipas-id sync-enabled name-conflict service-ids selected-tab set-selected-tab service-channel-ids]}] + (let [services (use-subscribe [::subs/services org-id])] ($ AccordionDetails {} (r/as-element @@ -721,7 +473,8 @@ (tr :ptv.wizard/attach-to-conflicting-service-channel)]) ($ service-channel-selector - {:value service-channel-ids + {:org-id org-id + :value service-channel-ids :value-fn :service-channel-id :on-change #(==> [::events/select-service-channels site %]) :label (tr :ptv/service-channel)})] @@ -736,7 +489,6 @@ ;; Summary [lui/text-field {:multiline true - :read-only? (not= "manual" (:descriptions-integration site)) :variant "outlined" :on-change #(==> [::events/set-summary site selected-tab %]) :label (tr :ptv/summary) @@ -745,7 +497,6 @@ ;; Description [lui/text-field {:variant "outlined" - :read-only? (not= "manual" (:descriptions-integration site)) :rows 5 :multiline true :on-change #(==> [::events/set-description site selected-tab %]) @@ -925,6 +676,7 @@ {:key lipas-id :tr tr :site site + :org-id org-id :lipas-id lipas-id :name-conflict name-conflict :sync-enabled sync-enabled @@ -934,11 +686,6 @@ :set-selected-tab set-selected-tab :service-channel-ids service-channel-ids}))]]]])) -(defn tools - [] - [mui/paper - [descriptions-generator]]) - (defn service-panel [{:keys [service]}] (r/with-let [lang (r/atom "fi")] @@ -1071,9 +818,7 @@ [mui/tab {:value "wizard" :label (tr :ptv/wizard)}] [mui/tab {:value "services" :label (tr :ptv/services)}] - [mui/tab {:value "sports-sites" :label (tr :ptv/sports-sites)}] - [mui/tab {:value "ai" :label (tr :ptv/tools)}] - [mui/tab {:value "settings" :label (tr :ptv/settings)}]] + [mui/tab {:value "sports-sites" :label (tr :ptv/sports-sites)}]] (when (= selected-tab "wizard") [wizard]) @@ -1084,11 +829,7 @@ (when (= selected-tab "sports-sites") [table]) - (when (= selected-tab "settings") - [settings]) - - (when (= selected-tab "ai") - [tools])])]])) + ])]])) ;; Juhan kommentit wizardiin ;; - mahdollisuus valita kielet diff --git a/webapp/test/clj/lipas/backend/ptv_test.clj b/webapp/test/clj/lipas/backend/ptv_test.clj index fb0dfa6bb..75374485d 100644 --- a/webapp/test/clj/lipas/backend/ptv_test.clj +++ b/webapp/test/clj/lipas/backend/ptv_test.clj @@ -84,8 +84,7 @@ ;; TODO: is this ptv-input data useful? Could everything (the view components) just use raw site data directly? ptv-sites (for [site (vals sports-sites)] - (ptv-data/sports-site->ptv-input {:tr (constantly "FOO") - :types types + (ptv-data/sports-site->ptv-input {:types types :org-id org-id :org-defaults default-settings :org-langs org-langs} From 7ff5fd840389232f5c91a9068274dcd71e62fe2c Mon Sep 17 00:00:00 2001 From: Juho Teperi Date: Fri, 22 Nov 2024 16:31:38 +0200 Subject: [PATCH 68/68] Ensure service-ids aren't duplicated, fix sync-ptv --- webapp/src/clj/lipas/backend/ptv/core.clj | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/webapp/src/clj/lipas/backend/ptv/core.clj b/webapp/src/clj/lipas/backend/ptv/core.clj index 277c4b01c..a963cb302 100644 --- a/webapp/src/clj/lipas/backend/ptv/core.clj +++ b/webapp/src/clj/lipas/backend/ptv/core.clj @@ -233,10 +233,11 @@ (log/infof "Site type changed %s => %s, service-ids updated %s => %s" (:previous-type-code ptv) type-code old-service-ids new-service-ids) - (update ptv :service-ids (fn [x] - (->> x - (remove (fn [y] (contains? old-service-ids y))) - (into new-service-ids))))) + (update ptv :service-ids (fn [ids] + (let [x (set ids) + x (apply disj x old-service-ids) + x (into x new-service-ids)] + (vec x))))) ptv) [_ptv-resp new-ptv-data] (upsert-ptv-service-location!* tx ptv-component search user @@ -244,6 +245,15 @@ :ptv ptv :site sports-site :archive? to-archive?})] + + (let [resp (core/upsert-sports-site! tx + user + (assoc sports-site + :event-date (:last-sync new-ptv-data) + :ptv new-ptv-data) + false)] + (core/index! search resp :sync)) + new-ptv-data) (catch Exception e (let [new-ptv-data (assoc ptv :error {:message (.getMessage e)