diff --git a/__init__.py b/__init__.py index 9dac68a7..3b270337 100644 --- a/__init__.py +++ b/__init__.py @@ -4,6 +4,13 @@ from flask_sqlalchemy import SQLAlchemy from flask_bootstrap import Bootstrap +#import de babel pour traduction +#from flask_babel import Babel, gettext, ngettext +#from flask_babel import Babel + +#app = Flask(__name__) +#babel = Babel(app) + APP_DIR = os.path.abspath(os.path.dirname(__file__)) BASE_DIR = os.path.abspath(os.path.join(APP_DIR, os.pardir)) TEMPLATE_DIR = APP_DIR+'/templates' diff --git a/babel.cfg b/babel.cfg new file mode 100644 index 00000000..0cc0baca --- /dev/null +++ b/babel.cfg @@ -0,0 +1,3 @@ +[python: **.py] +[jinja2: **/templates/**.html] +extensions=jinja2.ext.autoescape,jinja2.ext.with_ \ No newline at end of file diff --git a/data/gbif.sql b/data/gbif.sql new file mode 100644 index 00000000..c329f08d --- /dev/null +++ b/data/gbif.sql @@ -0,0 +1,722 @@ +-- SQL to update atlas database with GBIF data and backbone + +---------------------- +-- Remove default data +---------------------- + +-- Drop materialized in order to recreate it later +drop materialized view atlas.vm_altitudes; +drop materialized view atlas.vm_mois; +drop materialized view atlas.vm_taxons_plus_observes; +drop materialized view atlas.vm_observations_mailles; +drop materialized view atlas.vm_search_taxon; +drop materialized view atlas.vm_taxons; +drop materialized view atlas.vm_observations; +drop materialized view atlas.vm_taxref; + +-- Delete a constraint dependancy +ALTER TABLE taxonomie.taxref_protection_especes DROP CONSTRAINT taxref_protection_especes_cd_nom_fkey; + +-- Truncate taxref table content (with default French taxonomic data to replace it later with GBIF backbone taxonomy) +DELETE FROM taxonomie.taxref; + +-- Drop some views to recreate them later +DROP view taxonomie.v_taxref_all_listes; +DROP view taxonomie.v_taxref_hierarchie_bibtaxons; + +-- Update lb_auteur and lb_nom field length to 255 characters +ALTER TABLE taxonomie.taxref ALTER COLUMN lb_auteur TYPE character varying (255); +ALTER TABLE taxonomie.taxref ALTER COLUMN lb_nom TYPE character varying (255); + +-- Create a function to convert GBIF rank names to codes +CREATE OR REPLACE FUNCTION gbif.convert_rank(my_rank text) + RETURNS text AS +$BODY$ + DECLARE + the_rank text; + BEGIN + IF my_rank = 'KINGDOM' THEN + the_rank = 'KD'; + ELSIF my_rank = 'PHYLUM' THEN + the_rank = 'PH'; + ELSIF my_rank = 'CLASS' THEN + the_rank = 'CL'; + ELSIF my_rank = 'ORDER' THEN + the_rank = 'OR'; + ELSIF my_rank = 'FAMILY' THEN + the_rank = 'FM'; + ELSIF my_rank = 'GENUS' THEN + the_rank = 'GN'; + ELSIF my_rank = 'SPECIES' THEN + the_rank = 'ES'; + ELSIF my_rank = 'SUBSPECIES' THEN + the_rank = 'SSES'; + ELSE my_rank = NULL; + END IF; + return the_rank; + END; + $BODY$ + LANGUAGE plpgsql VOLATILE + COST 100; + +----------------- +-- Taxonomic data +----------------- + +-- Fill taxref table with GBIF backbone taxonomy data (more than 5 millions, can be long) +INSERT INTO taxonomie.taxref( + cd_nom, + id_statut, + id_habitat, + id_rang, + regne, + phylum, + classe, + ordre, + famille, + cd_taxsup, + cd_sup, + cd_ref, + lb_nom, + lb_auteur, + nom_complet, + nom_complet_html, + nom_valide, + nom_vern, + nom_vern_eng, + group1_inpn, + group2_inpn + ) +WITH sup_species AS + (SELECT id, parent_key FROM gbif.backbone WHERE is_synonym = true LIMIT 100), +k AS + (SELECT id, scientific_name FROM gbif.backbone + WHERE rank ='KINGDOM'), +p AS + (SELECT id, scientific_name FROM gbif.backbone + WHERE rank ='PHYLUM'), +c AS + (SELECT id, scientific_name FROM gbif.backbone + WHERE rank ='CLASS'), +o AS + (SELECT id, scientific_name FROM gbif.backbone + WHERE rank ='ORDER'), +f AS + (SELECT id, scientific_name FROM gbif.backbone + WHERE rank ='FAMILY') +SELECT + b.id AS cd_nom, + '' AS id_statut, + 0 AS id_habitat, + gbif.convert_rank(rank) AS id_rang, + k.scientific_name AS regne, + p.scientific_name AS phylum, + c.scientific_name AS classe, + o.scientific_name AS ordre, + f.scientific_name AS famille, + CASE WHEN (b.is_synonym = false) THEN b.parent_key + WHEN (b.is_synonym = true) THEN NULL + END AS cd_taxsup, + CASE WHEN (b.is_synonym = false) THEN b.parent_key + WHEN (b.is_synonym = true) THEN NULL + END AS cd_sup, + CASE WHEN (b.is_synonym = false) THEN b.id + WHEN (b.is_synonym = true) THEN b.parent_key + END AS cd_ref, + b.scientific_name AS lb_nom, + b.authorship AS lb_auteur, + b.canonical_name AS nom_complet, + b.canonical_name AS nom_complet_html, + b.scientific_name AS nom_valide, + b.scientific_name AS nom_vern, + b.scientific_name AS nom_vern_eng, + p.scientific_name AS group1_inpn, + p.scientific_name AS group2_inpn +FROM gbif.backbone AS b +LEFT JOIN k ON k.id = b.kingdom_key +LEFT JOIN p ON p.id = b.phylum_key +LEFT JOIN c ON c.id = b.class_key +LEFT JOIN o ON o.id = b.order_key +LEFT JOIN f ON f.id = b.family_key; + +-- Add primary key index on taxonKey field from gbif.gbifjam table +create index on gbif.gbifjam ("taxonKey"); + +-- Insert taxons (that have at least 1 observation data) in bib_noms table, in order to be able to associate them some medias later +INSERT INTO taxonomie.bib_noms (cd_nom, cd_ref, nom_francais) +SELECT DISTINCT cd_nom, cd_ref, nom_vern +FROM taxonomie.taxref t +JOIN gbif.gbifjam j ON j."taxonKey" = t.cd_nom +; + +-------------------- +-- Observations data +-------------------- + +-- Function to change date type from gbif.gbifjam table +CREATE OR REPLACE FUNCTION synthese.change_date(my_date character varying(254)) + RETURNS date AS +$BODY$ + DECLARE + the_date date; + BEGIN + the_date = to_date(my_date, 'YYYY-MM-DD'); + return the_date; + EXCEPTION + WHEN others + THEN + raise notice 'Error date'; + return null; + END; +$BODY$ +LANGUAGE plpgsql VOLATILE +COST 100; + +-- Truncate default content from syntheff table +DELETE FROM synthese.syntheseff + +-- Change observateurs field type from character varying(255) to text +ALTER TABLE synthese.syntheseff ALTER COLUMN observateurs TYPE text; + +-- Change id_synthese field type from serial to bigint to fill it with gbif.gbifjam.gbifid +ALTER TABLE synthese.syntheseff ALTER COLUMN id_synthese TYPE bigint; + +-- Insert GBIF observations data into syntheseff table +INSERT INTO synthese.syntheseff (id_synthese, cd_nom, dateobs, observateurs, the_geom_point, effectif_total, diffusable) +SELECT + "gbifID", + "taxonKey", + synthese.change_date("eventDate"), + ' ', + ST_transform(ST_SETSRID(ST_MakePoint("decimalLongitude", "decimalLatitude"),4326),3857), + 1, + 'True' +FROM gbif.gbifjam +WHERE synthese.change_date("eventDate") IS NOT NULL; + +-- Create a function to get all parent taxons from a taxon with its unique ID (cd_nom) +CREATE OR REPLACE FUNCTION atlas.get_all_cd_sup(the_cd_nom integer) + RETURNS SETOF integer AS +$BODY$ +DECLARE rec record; +BEGIN +for rec in + WITH RECURSIVE taxon_sup(cd_nom, lb_nom, cd_taxsup) AS ( + SELECT cd_nom, lb_nom, cd_taxsup + FROM taxonomie.taxref WHERE cd_nom = the_cd_nom + UNION ALL + SELECT e.cd_nom, e.lb_nom, e.cd_taxsup + FROM taxon_sup AS ss, taxonomie.taxref AS e + WHERE e.cd_nom = ss.cd_taxsup +) +SELECT cd_nom FROM taxon_sup +LOOP + RETURN NEXT rec.cd_nom; +END LOOP; + END; +$BODY$ +LANGUAGE plpgsql IMMUTABLE +COST 100; + +-- Delete a materialized view +DROP materialized view atlas.vm_taxref; +-- Recreate vm_taxref with all taxons observed at least once + their synonyms and parents +-- Better for performances, rather than including the whole GBIF backbone that has more than 5 millions records +CREATE materialized view atlas.vm_taxref AS +WITH observed_taxons AS ( + SELECT DISTINCT atlas.get_all_cd_sup(cd_nom) AS cd_nom FROM synthese.syntheseff) +SELECT + tx.cd_nom, + tx.id_statut, + tx.id_habitat, + tx.id_rang, + tx.regne, + tx.phylum, + tx.classe, + tx.ordre, + tx.famille, + tx.cd_taxsup, + tx.cd_sup, + tx.cd_ref, + tx.lb_nom, + tx.lb_auteur, + tx.nom_complet, + tx.nom_complet_html, + tx.nom_valide, + tx.nom_vern, + tx.nom_vern_eng, + tx.group1_inpn, + tx.group2_inpn +FROM taxonomie.taxref tx + RIGHT JOIN observed_taxons ot ON ot.cd_nom = tx.cd_ref; + +-- Add an index on cd_nom field from atlas.vm_taxref materialized view +CREATE UNIQUE INDEX vm_taxref_cd_nom_idx + ON atlas.vm_taxref + USING btree + (cd_nom); + +-- Add another index +CREATE INDEX vm_taxref_cd_ref_idx + ON atlas.vm_taxref + USING btree + (cd_ref); + +-- Add another index +CREATE INDEX vm_taxref_cd_taxsup_idx + ON atlas.vm_taxref + USING btree + (cd_taxsup); + +-- Add another index +CREATE INDEX vm_taxref_lb_nom_idx + ON atlas.vm_taxref + USING btree + (lb_nom COLLATE pg_catalog."default"); + +-- Add another index +CREATE INDEX vm_taxref_nom_complet_idx + ON atlas.vm_taxref + USING btree + (nom_complet COLLATE pg_catalog."default"); + +-- Add another index +CREATE INDEX vm_taxref_nom_valide_idx + ON atlas.vm_taxref + USING btree + (nom_valide COLLATE pg_catalog."default"); + +-- Now that we have inserted GBIF data, we can recreate all materialized views used by GeoNature-atlas + +CREATE MATERIALIZED VIEW atlas.vm_observations AS + SELECT s.id_synthese AS id_observation, + s.insee, + s.dateobs, + s.observateurs, + s.altitude_retenue, + s.the_geom_point, + s.effectif_total, + tx.cd_ref, + st_asgeojson(st_transform(st_setsrid(s.the_geom_point, 3857), 4326)) AS geojson_point + FROM synthese.syntheseff s + LEFT JOIN atlas.vm_taxref tx ON tx.cd_nom = s.cd_nom + JOIN atlas.t_layer_territoire m ON ST_Intersects(m.the_geom, s.the_geom_point) + WHERE s.supprime = false AND s.diffusable = true +WITH DATA; + +CREATE MATERIALIZED VIEW atlas.vm_observations_mailles AS + SELECT obs.cd_ref, + obs.id_observation, + m.id_maille, + m.the_geom, + m.geojson_maille + FROM atlas.vm_observations obs + JOIN atlas.t_mailles_territoire m ON st_intersects(obs.the_geom_point, st_transform(m.the_geom, 3857)) +WITH DATA; + +REINDEX INDEX atlas.vm_observations_mailles_cd_ref_idx; +REINDEX INDEX atlas.index_gist_atlas_vm_observations_mailles_geom; +REINDEX INDEX atlas.vm_observations_mailles_geojson_maille_idx; +REINDEX INDEX atlas.vm_observations_mailles_id_maille_idx; +REINDEX INDEX atlas.vm_observations_mailles_id_observation_idx; + +DROP MATERIALIZED VIEW atlas.vm_search_taxon; +DROP MATERIALIZED VIEW atlas.vm_taxons_plus_observes; +DROP MATERIALIZED VIEW atlas.vm_taxons; + +CREATE MATERIALIZED VIEW atlas.vm_taxons AS + WITH obs_min_taxons AS ( + SELECT vm_observations.cd_ref, + min(date_part('year'::text, vm_observations.dateobs)) AS yearmin, + max(date_part('year'::text, vm_observations.dateobs)) AS yearmax, + count(vm_observations.id_observation) AS nb_obs + FROM atlas.vm_observations + GROUP BY vm_observations.cd_ref + ), tx_ref AS ( + SELECT tx_1.cd_ref, + tx_1.regne, + tx_1.phylum, + tx_1.classe, + tx_1.ordre, + tx_1.famille, + tx_1.cd_taxsup, + tx_1.lb_nom, + tx_1.lb_auteur, + tx_1.nom_complet, + tx_1.nom_valide, + tx_1.nom_vern, + tx_1.nom_vern_eng, + tx_1.group1_inpn, + tx_1.group2_inpn, + tx_1.nom_complet_html, + tx_1.id_rang + FROM atlas.vm_taxref tx_1 + WHERE (tx_1.cd_ref IN ( SELECT obs_min_taxons.cd_ref + FROM obs_min_taxons)) AND tx_1.cd_nom = tx_1.cd_ref + ), my_taxons AS ( + SELECT DISTINCT n.cd_ref, + pat.valeur_attribut AS patrimonial, + pr.valeur_attribut AS protection_stricte + FROM tx_ref n + LEFT JOIN taxonomie.cor_taxon_attribut pat ON pat.cd_ref = n.cd_ref AND pat.id_attribut = 1 + LEFT JOIN taxonomie.cor_taxon_attribut pr ON pr.cd_ref = n.cd_ref AND pr.id_attribut = 2 + WHERE (n.cd_ref IN ( SELECT obs_min_taxons.cd_ref + FROM obs_min_taxons)) + ) + SELECT tx.cd_ref, + tx.regne, + tx.phylum, + tx.classe, + tx.ordre, + tx.famille, + tx.cd_taxsup, + tx.lb_nom, + tx.lb_auteur, + tx.nom_complet, + tx.nom_valide, + tx.nom_vern, + tx.nom_vern_eng, + tx.group1_inpn, + tx.group2_inpn, + tx.nom_complet_html, + tx.id_rang, + t.patrimonial, + t.protection_stricte, + omt.yearmin, + omt.yearmax, + omt.nb_obs + FROM tx_ref tx + LEFT JOIN obs_min_taxons omt ON omt.cd_ref = tx.cd_ref + LEFT JOIN my_taxons t ON t.cd_ref = tx.cd_ref +WITH DATA; + +CREATE UNIQUE INDEX vm_taxons_cd_ref_idx + ON atlas.vm_taxons + USING btree + (cd_ref); + +CREATE MATERIALIZED VIEW atlas.vm_taxons_plus_observes AS + SELECT count(*) AS nb_obs, + obs.cd_ref, + tax.lb_nom, + tax.group2_inpn, + tax.nom_vern, + m.id_media, + m.url, + m.chemin, + m.id_type + FROM atlas.vm_observations obs + JOIN atlas.vm_taxons tax ON tax.cd_ref = obs.cd_ref + LEFT JOIN atlas.vm_medias m ON m.cd_ref = obs.cd_ref AND m.id_type = 1 + WHERE date_part('day'::text, obs.dateobs) >= date_part('day'::text, 'now'::text::date - 15) AND date_part('month'::text, obs.dateobs) = date_part('month'::text, 'now'::text::date - 15) OR date_part('day'::text, obs.dateobs) <= date_part('day'::text, 'now'::text::date + 15) AND date_part('month'::text, obs.dateobs) = date_part('day'::text, 'now'::text::date + 15) + GROUP BY obs.cd_ref, tax.lb_nom, tax.nom_vern, m.url, m.chemin, tax.group2_inpn, m.id_type, m.id_media + ORDER BY (count(*)) DESC + LIMIT 12 +WITH DATA; + +CREATE UNIQUE INDEX vm_taxons_plus_observes_cd_ref_idx + ON atlas.vm_taxons_plus_observes + USING btree + (cd_ref); + +CREATE MATERIALIZED VIEW atlas.vm_search_taxon AS + SELECT tx.cd_nom, + tx.cd_ref, + COALESCE((tx.lb_nom::text || ' | '::text) || tx.nom_vern::text, tx.lb_nom::text) AS nom_search + FROM atlas.vm_taxref tx + JOIN atlas.vm_taxons t ON t.cd_ref = tx.cd_ref +WITH DATA; + +CREATE UNIQUE INDEX vm_search_taxon_cd_nom_idx + ON atlas.vm_search_taxon + USING btree + (cd_nom); + +CREATE INDEX vm_search_taxon_cd_ref_idx + ON atlas.vm_search_taxon + USING btree + (cd_ref); + +CREATE INDEX vm_search_taxon_nom_search_idx + ON atlas.vm_search_taxon + USING btree + (nom_search COLLATE pg_catalog."default"); + +CREATE MATERIALIZED VIEW atlas.vm_mois AS + WITH _01 AS ( + SELECT vm_observations.cd_ref, + count(*) AS nb + FROM atlas.vm_observations + WHERE date_part('month'::text, vm_observations.dateobs) = '1'::double precision + GROUP BY vm_observations.cd_ref + ), _02 AS ( + SELECT vm_observations.cd_ref, + count(*) AS nb + FROM atlas.vm_observations + WHERE date_part('month'::text, vm_observations.dateobs) = '2'::double precision + GROUP BY vm_observations.cd_ref + ), _03 AS ( + SELECT vm_observations.cd_ref, + count(*) AS nb + FROM atlas.vm_observations + WHERE date_part('month'::text, vm_observations.dateobs) = '3'::double precision + GROUP BY vm_observations.cd_ref + ), _04 AS ( + SELECT vm_observations.cd_ref, + count(*) AS nb + FROM atlas.vm_observations + WHERE date_part('month'::text, vm_observations.dateobs) = '4'::double precision + GROUP BY vm_observations.cd_ref + ), _05 AS ( + SELECT vm_observations.cd_ref, + count(*) AS nb + FROM atlas.vm_observations + WHERE date_part('month'::text, vm_observations.dateobs) = '5'::double precision + GROUP BY vm_observations.cd_ref + ), _06 AS ( + SELECT vm_observations.cd_ref, + count(*) AS nb + FROM atlas.vm_observations + WHERE date_part('month'::text, vm_observations.dateobs) = '6'::double precision + GROUP BY vm_observations.cd_ref + ), _07 AS ( + SELECT vm_observations.cd_ref, + count(*) AS nb + FROM atlas.vm_observations + WHERE date_part('month'::text, vm_observations.dateobs) = '7'::double precision + GROUP BY vm_observations.cd_ref + ), _08 AS ( + SELECT vm_observations.cd_ref, + count(*) AS nb + FROM atlas.vm_observations + WHERE date_part('month'::text, vm_observations.dateobs) = '8'::double precision + GROUP BY vm_observations.cd_ref + ), _09 AS ( + SELECT vm_observations.cd_ref, + count(*) AS nb + FROM atlas.vm_observations + WHERE date_part('month'::text, vm_observations.dateobs) = '9'::double precision + GROUP BY vm_observations.cd_ref + ), _10 AS ( + SELECT vm_observations.cd_ref, + count(*) AS nb + FROM atlas.vm_observations + WHERE date_part('month'::text, vm_observations.dateobs) = '10'::double precision + GROUP BY vm_observations.cd_ref + ), _11 AS ( + SELECT vm_observations.cd_ref, + count(*) AS nb + FROM atlas.vm_observations + WHERE date_part('month'::text, vm_observations.dateobs) = '11'::double precision + GROUP BY vm_observations.cd_ref + ), _12 AS ( + SELECT vm_observations.cd_ref, + count(*) AS nb + FROM atlas.vm_observations + WHERE date_part('month'::text, vm_observations.dateobs) = '12'::double precision + GROUP BY vm_observations.cd_ref + ) + SELECT DISTINCT o.cd_ref, + COALESCE(a.nb::integer, 0) AS _01, + COALESCE(b.nb::integer, 0) AS _02, + COALESCE(c.nb::integer, 0) AS _03, + COALESCE(d.nb::integer, 0) AS _04, + COALESCE(e.nb::integer, 0) AS _05, + COALESCE(f.nb::integer, 0) AS _06, + COALESCE(g.nb::integer, 0) AS _07, + COALESCE(h.nb::integer, 0) AS _08, + COALESCE(i.nb::integer, 0) AS _09, + COALESCE(j.nb::integer, 0) AS _10, + COALESCE(k.nb::integer, 0) AS _11, + COALESCE(l.nb::integer, 0) AS _12 + FROM atlas.vm_observations o + LEFT JOIN _01 a ON a.cd_ref = o.cd_ref + LEFT JOIN _02 b ON b.cd_ref = o.cd_ref + LEFT JOIN _03 c ON c.cd_ref = o.cd_ref + LEFT JOIN _04 d ON d.cd_ref = o.cd_ref + LEFT JOIN _05 e ON e.cd_ref = o.cd_ref + LEFT JOIN _06 f ON f.cd_ref = o.cd_ref + LEFT JOIN _07 g ON g.cd_ref = o.cd_ref + LEFT JOIN _08 h ON h.cd_ref = o.cd_ref + LEFT JOIN _09 i ON i.cd_ref = o.cd_ref + LEFT JOIN _10 j ON j.cd_ref = o.cd_ref + LEFT JOIN _11 k ON k.cd_ref = o.cd_ref + LEFT JOIN _12 l ON l.cd_ref = o.cd_ref + WHERE o.cd_ref IS NOT NULL + ORDER BY o.cd_ref +WITH DATA; + +CREATE UNIQUE INDEX vm_mois_cd_ref_idx + ON atlas.vm_mois + USING btree + (cd_ref); + +-- Altitude classes - Should be updated with altitudes for your territory + +CREATE MATERIALIZED VIEW atlas.vm_altitudes AS + WITH alt1 AS ( + SELECT vm_observations.cd_ref, + count(*) AS nb + FROM atlas.vm_observations + WHERE vm_observations.altitude_retenue < 499 + GROUP BY vm_observations.cd_ref + ), alt2 AS ( + SELECT vm_observations.cd_ref, + count(*) AS nb + FROM atlas.vm_observations + WHERE vm_observations.altitude_retenue >= 500 AND vm_observations.altitude_retenue <= 999 + GROUP BY vm_observations.cd_ref + ), alt3 AS ( + SELECT vm_observations.cd_ref, + count(*) AS nb + FROM atlas.vm_observations + WHERE vm_observations.altitude_retenue >= 1000 AND vm_observations.altitude_retenue <= 1499 + GROUP BY vm_observations.cd_ref + ), alt4 AS ( + SELECT vm_observations.cd_ref, + count(*) AS nb + FROM atlas.vm_observations + WHERE vm_observations.altitude_retenue >= 1500 AND vm_observations.altitude_retenue <= 1999 + GROUP BY vm_observations.cd_ref + ), alt5 AS ( + SELECT vm_observations.cd_ref, + count(*) AS nb + FROM atlas.vm_observations + WHERE vm_observations.altitude_retenue >= 2000 AND vm_observations.altitude_retenue <= 2499 + GROUP BY vm_observations.cd_ref + ), alt6 AS ( + SELECT vm_observations.cd_ref, + count(*) AS nb + FROM atlas.vm_observations + WHERE vm_observations.altitude_retenue >= 2500 AND vm_observations.altitude_retenue <= 2999 + GROUP BY vm_observations.cd_ref + ), alt7 AS ( + SELECT vm_observations.cd_ref, + count(*) AS nb + FROM atlas.vm_observations + WHERE vm_observations.altitude_retenue >= 3000 AND vm_observations.altitude_retenue <= 3499 + GROUP BY vm_observations.cd_ref + ), alt8 AS ( + SELECT vm_observations.cd_ref, + count(*) AS nb + FROM atlas.vm_observations + WHERE vm_observations.altitude_retenue >= 3500 AND vm_observations.altitude_retenue <= 3999 + GROUP BY vm_observations.cd_ref + ), alt9 AS ( + SELECT vm_observations.cd_ref, + count(*) AS nb + FROM atlas.vm_observations + WHERE vm_observations.altitude_retenue >= 4000 AND vm_observations.altitude_retenue <= 4102 + GROUP BY vm_observations.cd_ref + ) + SELECT DISTINCT o.cd_ref, + COALESCE(a1.nb::integer, 0) AS _0_500, + COALESCE(a2.nb::integer, 0) AS _500_1000, + COALESCE(a3.nb::integer, 0) AS _1000_1500, + COALESCE(a4.nb::integer, 0) AS _1500_2000, + COALESCE(a5.nb::integer, 0) AS _2000_2500, + COALESCE(a6.nb::integer, 0) AS _2500_3000, + COALESCE(a7.nb::integer, 0) AS _3000_3500, + COALESCE(a8.nb::integer, 0) AS _3500_4000, + COALESCE(a9.nb::integer, 0) AS _4000_4103 + FROM atlas.vm_observations o + LEFT JOIN alt1 a1 ON a1.cd_ref = o.cd_ref + LEFT JOIN alt2 a2 ON a2.cd_ref = o.cd_ref + LEFT JOIN alt3 a3 ON a3.cd_ref = o.cd_ref + LEFT JOIN alt4 a4 ON a4.cd_ref = o.cd_ref + LEFT JOIN alt5 a5 ON a5.cd_ref = o.cd_ref + LEFT JOIN alt6 a6 ON a6.cd_ref = o.cd_ref + LEFT JOIN alt7 a7 ON a7.cd_ref = o.cd_ref + LEFT JOIN alt8 a8 ON a8.cd_ref = o.cd_ref + LEFT JOIN alt9 a9 ON a9.cd_ref = o.cd_ref + WHERE o.cd_ref IS NOT NULL + ORDER BY o.cd_ref +WITH DATA; + +REINDEX INDEX atlas.vm_altitudes_cd_ref_idx; + +-- Create a function to cast taxonkey +CREATE OR REPLACE FUNCTION atlas.cast_taxonkey(my_taxonkey character varying(254)) + RETURNS integer AS +$BODY$ + DECLARE + the_taxonkey integer; + BEGIN + the_taxonkey = my_taxonkey::integer; + return the_taxonkey; + EXCEPTION + WHEN others + THEN + raise notice 'Error taxonkey'; + return null; + END; +$BODY$ +LANGUAGE plpgsql VOLATILE +COST 100; + +-- Cast insee column (municipality ID) to integer (instead of float) +DROP MATERIALIZED VIEW atlas.vm_communes; + +CREATE MATERIALIZED VIEW atlas.vm_communes AS + SELECT c.insee::integer, + c.commune_maj, + c.the_geom, + st_asgeojson(st_transform(c.the_geom, 4326)) AS commune_geojson + FROM atlas.l_communes c + JOIN atlas.t_layer_territoire t ON st_contains(st_buffer(t.the_geom, 200::double precision), c.the_geom) +WITH DATA; + +-- Intersect observations with municipalities polygons +UPDATE synthese.syntheseff s SET insee = c.insee +FROM atlas.vm_communes c +WHERE ST_Intersects(s.the_geom_point, c.the_geom); + +-- And include municipalities ID in observations materialized view +REFRESH MATERIALIZED VIEW CONCURRENTLY atlas.vm_observations; + +-- Translate main ranks into English +UPDATE atlas.bib_taxref_rangs SET nom_rang = 'Domain' +WHERE id_rang = 'Dumm'; +UPDATE atlas.bib_taxref_rangs SET nom_rang = 'Kingdom' +WHERE id_rang = 'KD'; +UPDATE atlas.bib_taxref_rangs SET nom_rang = 'Family' +WHERE id_rang = 'FM'; +UPDATE atlas.bib_taxref_rangs SET nom_rang = 'Subfamily' +WHERE id_rang = 'SBFM'; +UPDATE atlas.bib_taxref_rangs SET nom_rang = 'Order' +WHERE id_rang = 'OR'; +UPDATE atlas.bib_taxref_rangs SET nom_rang = 'Suborder' +WHERE id_rang = 'SBOR'; +UPDATE atlas.bib_taxref_rangs SET nom_rang = 'Class' +WHERE id_rang = 'CL'; +UPDATE atlas.bib_taxref_rangs SET nom_rang = 'Genus' +WHERE id_rang = 'GN'; +UPDATE atlas.bib_taxref_rangs SET nom_rang = 'Subgenus' +WHERE id_rang = 'SSGN'; +UPDATE atlas.bib_taxref_rangs SET nom_rang = 'Species' +WHERE id_rang = 'ES'; +UPDATE atlas.bib_taxref_rangs SET nom_rang = 'Subspecies' +WHERE id_rang = 'SSES'; + +-- GRANT SELECT to your database reader user on ALL TABLES +-- Replace with the user you fill in the file settings.ini ('user_pg' setting) + +GRANT USAGE ON SCHEMA atlas TO ; + +GRANT SELECT ON TABLE atlas.vm_altitudes TO ; +GRANT SELECT ON TABLE atlas.vm_communes TO ; +GRANT SELECT ON TABLE atlas.vm_observations TO ; +GRANT SELECT ON TABLE atlas.vm_cor_taxon_attribut TO ; +GRANT SELECT ON TABLE atlas.vm_medias TO ; +GRANT SELECT ON TABLE atlas.vm_observations TO ; +GRANT SELECT ON TABLE atlas.vm_observations_mailles TO ; +GRANT SELECT ON TABLE atlas.vm_search_taxon TO ; +GRANT SELECT ON TABLE atlas.vm_taxons TO ; +GRANT SELECT ON TABLE atlas.vm_taxons_plus_observes TO ; +GRANT SELECT ON TABLE atlas.vm_taxref TO ; +GRANT SELECT ON TABLE atlas.vm_mois TO ; +GRANT SELECT ON TABLE atlas.vm_altitudes TO ; +GRANT SELECT ON TABLE atlas.bib_altitudes TO ; +GRANT EXECUTE ON FUNCTION atlas.find_all_taxons_childs(integer) TO ; +GRANT SELECT ON TABLE atlas.bib_taxref_rangs TO ; +GRANT SELECT ON TABLE atlas.t_mailles_territoire TO ; diff --git a/data/script_gbif/README.rst b/data/script_gbif/README.rst new file mode 100644 index 00000000..210ed257 --- /dev/null +++ b/data/script_gbif/README.rst @@ -0,0 +1,9 @@ + +Ce script permet d'importer les médias Commons à partir des code_taxon GBIF présents dans Wikidata. + +:: + + virtualenv -p /usr/bin/python3 venv #Python 3 n'est pas requis + source venv/bin/activate + pip install lxml psycopg2 requests SPARQLWrapper xmltodict + deactivate \ No newline at end of file diff --git a/data/script_gbif/config.py b/data/script_gbif/config.py new file mode 100644 index 00000000..6f3f42d9 --- /dev/null +++ b/data/script_gbif/config.py @@ -0,0 +1,19 @@ +""" + FICHIER DE CONFIGURATION A ADAPTER A VOTRE BDD et aux CDREF que vous souhaitez enrichir de medias +""" +SQLALCHEMY_DATABASE_URI = "postgresql://geonatusercp:monpassachanger@localhost:5432/geonatureatlascp" + +QUERY_SELECT_CITATION = """SELECT "datasetKey", id_synthese + FROM gbif.gbifjam + JOIN synthese.syntheseff ON synthese.syntheseff.id_synthese = gbif.gbifjam."gbifID" + WHERE synthese.syntheseff.observateurs IS NULL + ; + """ + +QUERY_SELECT_CDREF = """SELECT DISTINCT cd_ref + FROM taxonomie.bib_noms + LEFT OUTER JOIN taxonomie.t_medias USING(cd_ref) + WHERE id_media IS NULL +""" + +# QUERY_SELECT_CDREF = """SELECT cd_ref from atlas.vm_taxons_plus_observes LIMIT 100""" diff --git a/data/script_gbif/import_gbif_citation.py b/data/script_gbif/import_gbif_citation.py new file mode 100644 index 00000000..c9959a10 --- /dev/null +++ b/data/script_gbif/import_gbif_citation.py @@ -0,0 +1,127 @@ +# coding: utf8 + + +''' + Script permettant l'import de sources récupérées via l'API GBIF +''' +import requests +import psycopg2 + + +import config + +# ################ +# CONSTANTES +API_URL = "http://api.gbif.org/v1/dataset/{}" + +SOURCE = "GBIF" + +QUERY_UPDATE_SOURCES = """ + update synthese.syntheseff + SET observateurs = %s + WHERE id_synthese = %s +""" +class Source(): + + def __init__( + self, + source + ): + self.source = source + + def __repr__(self): + return "source: {}".format( + self.source + ) + +# ################ +# FONCTIONS + +def runquery(cursor, sql, params, trap=False): + ''' + Fonction permettant d'executer une requete + trap : Indique si les erreurs sont ou pas retournées + ''' + try: + result = cursor.execute( + sql, + params + ) + return result + except Exception as exp: + print(exp) + if trap: + return None + raise exp + + +def process_source(cur, id_synthese, source, trap=False): + ''' + Fonction qui gère l'enregistrement de la source + dans la base + ''' + # s_obj = Source( + # source = source + # ) + + try: + result = cursor.execute( + QUERY_UPDATE_SOURCES, + (source, id_synthese) + ) + return result + except Exception as exp: + print(exp) + if trap: + return None + raise exp + + print('update') + # runquery( + # cur, + # QUERY_UPDATE_SOURCES, + # ( + # s_obj.source, + # id_synthese + # ), + # True + # ) + DB_CONNEXION.commit() + + +# ################ +# SCRIPT +try: + DB_CONNEXION = psycopg2.connect(config.SQLALCHEMY_DATABASE_URI) + print('connexion ok') +except Exception as exp: + print("Connexion à la base impossible") + quit() + +try: + cursor = DB_CONNEXION.cursor() + rows = runquery(cursor, config.QUERY_SELECT_CITATION, None, False) + rows = cursor.fetchall() +except Exception as exp: + print("Problème lors de la récupération de la liste des id_synthese") + quit() + + +for r in rows: + url = API_URL.format(r[0]) + print(r[0]) + print(r[1]) + req = None + try: + req = requests.get(url) + except Exception as e: + print(e) + if req and req.status_code == 200 : + data = req.json() + if 'citation' in data: + process_source(cursor, r[1], data['citation']['text'], True) + else: + print (" Pas de source pour cette occurence ") + + +DB_CONNEXION.close() diff --git a/data/script_gbif/import_wikidata.py b/data/script_gbif/import_wikidata.py new file mode 100644 index 00000000..b0bc9dbb --- /dev/null +++ b/data/script_gbif/import_wikidata.py @@ -0,0 +1,127 @@ +import requests +import psycopg2 +from lxml import etree +import xmltodict +import config + +from SPARQLWrapper import SPARQLWrapper, JSON + + +def getLicence(licences): + licence = [] + if isinstance(licences, dict): + return licences['name'] + else: + for i in licences: + licence.append(i['name']) + return '; '.join(licence) + + +def main(dbconnexion, cd_refs, refreshAtlas=True, simulate=True): + # DbMedia Query + cur = dbconnexion.cursor() + query = """SELECT ?item ?itemLabel ?nomSc ?image ?identifiant_GBIF WHERE { + ?item wdt:P225 ?nomSc. + ?item wdt:P18 ?image. + ?item wdt:P846 '%s' + } LIMIT 200""" + sparql = SPARQLWrapper("https://query.wikidata.org/sparql", + agent='Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36' + ) + + + sqlI = """INSERT INTO taxonomie.t_medias + (cd_ref, titre, url,is_public, id_type, auteur, source, licence) + VALUES (%s, '%s', '%s', true, 2, '%s (Wikimedia Commons - %s)', 'Wikimedia Commons', '%s') + """ + + # VALUES (%s, '%s', '%s', true, 2, '%s', 'Wikimedia Commons', '%s') + for cd_ref in cd_refs: + try: + sparql.setQuery(query % cd_ref[0]) + sparql.setReturnFormat(JSON) + results = sparql.query().convert() + for result in results["results"]["bindings"]: + if (result['image']['value']): + print(' -- INSERT IMAGE') + # Recuperation des donnees sur commons + url = "https://tools.wmflabs.org/magnus-toolserver/commonsapi.php?image=%s" % result['image']['value'].split('Special:FilePath/', 1 )[1] + r = requests.get(url) + a = xmltodict.parse(r.content) + try: + aut = 'Commons' + if 'author' in a['response']['file']: + if len(a['response']['file']['author']) < 500: + aut = a['response']['file']['author'] + licence = getLicence(a['response']['licenses']['license']) + sql = sqlI % ( + cd_ref[0], + a['response']['file']['name'], + result['image']['value'], + aut, + licence, + licence + ) + + if simulate is False: + cur.execute(sql) + dbconnexion.commit() + else: + print (sql) + except Exception as e: + print(' ERREOR') + print(e) + dbconnexion.rollback() + pass + except Exception as e: + print(e) + pass + if simulate is False: + cur.execute(""" + UPDATE taxonomie.t_medias SET id_type = 1 + WHERE id_media IN ( + SELECT max(id_media) + FROM taxonomie.t_medias t + LEFT OUTER JOIN (SELECT cd_ref FROM taxonomie.t_medias WHERE id_type = 1) e + ON t.cd_ref = e.cd_ref + WHERE e.cd_ref IS NULL + GROUP BY t.cd_ref + ); + """) + if refreshAtlas: + cur.execute("REFRESH MATERIALIZED VIEW atlas.vm_medias;") + cur.execute("REFRESH MATERIALIZED VIEW atlas.vm_taxons_plus_observes;") + + dbconnexion.commit() + + +try: + conn = psycopg2.connect(config.SQLALCHEMY_DATABASE_URI) +except Exception as e: + print("Connexion à la base impossible") + raise + +try: + cur = conn.cursor() + # sql = """SELECT DISTINCT cd_ref + # FROM taxonomie.bib_noms + # LEFT OUTER JOIN taxonomie.t_medias USING(cd_ref) + # WHERE id_media IS NULL + # """ + # sql = """ + # SELECT DISTINCT tax.cd_ref + # FROM synthese.syntheseff s + # JOIN taxonomie.taxref tax ON tax.cd_nom = s.cd_nom + # LEFT JOIN taxonomie.t_medias medias ON medias.cd_ref = tax.cd_ref + # WHERE medias.url IS NULL + # LIMIT 100 + # """ + # sql = """SELECT cd_ref from atlas.vm_taxons_plus_observes LIMIT 100""" + cur.execute(config.QUERY_SELECT_CDREF) + rows = cur.fetchall() +except Exception as e: + print("Problème lors de la récupération de la liste des cd_ref") + raise + + +main(conn, rows, False, False) diff --git a/docs/en/01-install-host.rst b/docs/en/01-install-host.rst new file mode 100644 index 00000000..5fb742b4 --- /dev/null +++ b/docs/en/01-install-host.rst @@ -0,0 +1,20 @@ +Install host +============ + +You can install GeoNature-atlas locally to test it or on a remote host to make it available on internet. + +The installation scripts are designed for Debian (8 or 9) and Ubuntu (18). Other linux distributions can work, but you will have to adapt +installation scripts. + +Login in SSH with ``root`` user to prepare host and launch these commands with a terminal. + +.. code-block:: console + + # Install unzip and sudo + apt-get install unzip + apt-get install sudo + # Create a linux user (geonatureatlas in our example) and add it to sudo group + adduser geonatureatlas + adduser geonatureatlas sudo + +Logout from ``root`` user and we'll now work only with your dedicated user (``geonatureatlas`` in our example). diff --git a/docs/en/02-install-software-database.rst b/docs/en/02-install-software-database.rst new file mode 100644 index 00000000..53516d91 --- /dev/null +++ b/docs/en/02-install-software-database.rst @@ -0,0 +1,47 @@ +Install GeoNature-atlas and its database +======================================== + +Download and unzip the source code from the actual dedicated branch: + +.. code-block:: console + + cd /home/geonatureatlas + wget https://github.com/PnX-SI/GeoNature-atlas/archive/multilingue.zip + unzip multilingue.zip + +Rename the application folder: + +.. code-block:: console + + mv GeoNature-atlas-multilingue atlas + +Launch the environment script that will install PostgreSQL, PostGIS 2, Apache 2 and Python 2.7. + +.. code-block:: console + + cd /home/geonatureatlas/atlas + ./install_env.sh + +Install the database + +.. code-block:: console + + # Copy the example setting file + cp main/configuration/settings.ini.sample main/configuration/settings.ini + +Edit database setting file ``main/configuration/settings.ini``. + +You can change PostgreSQL database owner and user names and their passwords. They will be created by the database installation script. + +- Upload your territory shapefile as ``data/ref/territoire.shp`` (or fill its path in ``limit_shp``) +- Upload your municipalities shapefile as ``data/ref/communes.shp`` (or fill its path in ``communes_shp``) +- Upload your grids shapefile as ``data/ref/custom_maille.shp`` (or fill its path in ``chemin_custom_maille``) +- ``geonature_source=false`` +- ``metropole=false`` +- ``install_taxonomie = true`` + +Once done, launch the database creation script: + +.. code-block:: console + + sudo ./install_db.sh diff --git a/docs/en/03-open-database-connection.rst b/docs/en/03-open-database-connection.rst new file mode 100644 index 00000000..e301f172 --- /dev/null +++ b/docs/en/03-open-database-connection.rst @@ -0,0 +1,40 @@ +Open database connection +======================== + +To access and manage GeoNature-atlas database we'll use pgAdmin software (https://www.pgadmin.org). + +By default a PostgreSQL database only accept connections from its local host. +To manage the database from your local computer we'll have to open database connections. + +Edit ``postgresql.conf`` file so that PostgreSQL would listen from all IP : + +.. code-block:: console + + sudo nano /etc/postgresql/*/main/postgresql.conf + +Replace ``listen_adress = 'localhost'`` by ``listen_adress = '*'``. +Don't forget to uncomment this line (with removing the ``#``). + +To define IP that can connect to the database we'll edit ``pg_hba.conf`` file: + +.. code-block:: console + + sudo nano /etc/postgresql/*/main/pg_hba.conf + +To give access to the database from a specific IP (recommanded), add this line to the ``pg_hba.conf`` file: + +.. code-block:: + + host all all MY_IP/0 md5 + +Or if you want to give access to all IP, add this line to the ``pg_hba.conf`` file: + +.. code-block:: + + host all all 0.0.0.0/0 md5 + +Restart PostgreSQL to apply changes: + +.. code-block:: console + + sudo /etc/init.d/postgresql restart diff --git a/initAtlas.py b/initAtlas.py index 022b30a7..caa35903 100644 --- a/initAtlas.py +++ b/initAtlas.py @@ -1,7 +1,11 @@ import os import sys -from flask import Flask, render_template +from flask import Flask, render_template, request from flask_sqlalchemy import SQLAlchemy +from flask_babel import Babel, gettext, ngettext +from flask_babel import Babel +from main.configuration.config import LANGUAGES + from werkzeug.serving import run_simple @@ -41,6 +45,20 @@ def __call__(self, environ, start_response): def create_app(): # renvoie une instance de app l appli Flask app = Flask(__name__, template_folder=APP_DIR) + app.config['BABEL_DEFAULT_LOCALE'] = './translations/'+config.BABEL_DEFAULT_LOCALE+'/LC_MESSAGES/messages.po' + + babel = Babel(app) + + #Recuperation de la langue du navigateur + @babel.localeselector + def get_locale(): + return request.accept_languages.best_match(LANGUAGES.keys()) + + @app.errorhandler(404) + def page_not_found(e): + # redirection vers la page d'erreur + return render_template('templates/404.html'), 404 + app.debug = config.modeDebug @@ -49,6 +67,7 @@ def create_app(): app.register_blueprint(main_blueprint) from main.atlasAPI import api + app.register_blueprint(api, url_prefix='/api') compress.init_app(app) @@ -57,12 +76,13 @@ def create_app(): return app - + app = create_app() - if __name__ == '__main__': - from flask_script import Manager - # Manager(app).run() - run_simple('localhost', 8080, app, use_reloader=True) + #from flask_script import Manager + #Manager(app).run() + #run_simple('localhost', 8080, app, use_reloader=True) + app.run(port=8080, debug=True, threaded = True) + \ No newline at end of file diff --git a/install_app.sh b/install_app.sh index 6511a930..f6836a3e 100755 --- a/install_app.sh +++ b/install_app.sh @@ -70,8 +70,8 @@ fi if [ ! -f ./static/custom/images/favicon.ico ]; then cp ./static/images/sample.favicon.ico ./static/custom/images/favicon.ico fi -if [ ! -f ./static/custom/images/accueil-intro.jpg ]; then - cp ./static/images/sample.accueil-intro.jpg ./static/custom/images/accueil-intro.jpg +if [ ! -f ./static/custom/images/home-intro.jpg ]; then + cp ./static/images/sample.home-intro.jpg ./static/custom/images/home-intro.jpg fi if [ ! -f ./static/custom/images/logo-structure.png ]; then cp ./static/images/sample.logo-structure.png ./static/custom/images/logo-structure.png diff --git a/main/atlasRoutes.py b/main/atlasRoutes.py index 3b41b740..7e1a82d3 100644 --- a/main/atlasRoutes.py +++ b/main/atlasRoutes.py @@ -1,7 +1,11 @@ # -*- coding:utf-8 -*- -from flask import render_template, redirect, abort +from flask import render_template, redirect, abort, request +from flask_babel import gettext, ngettext + +from jinja2.exceptions import TemplateNotFound + from configuration import config from modeles.repositories import ( vmTaxonsRepository, vmObservationsRepository, vmAltitudesRepository, @@ -24,7 +28,6 @@ 'TAXHUB_URL': config.TAXHUB_URL if hasattr(config, 'TAXHUB_URL') else None } - @main.route( '/espece/'+config.REMOTE_MEDIAS_PATH+'', methods=['GET', 'POST'] @@ -69,7 +72,6 @@ def indexMedias(image): def index(): session = utils.loadSession() connection = utils.engine.connect() - if config.AFFICHAGE_MAILLE: observations = vmObservationsMaillesRepository.lastObservationsMailles( connection, config.NB_DAY_LAST_OBS, config.ATTR_MAIN_PHOTO @@ -88,6 +90,7 @@ def index(): customStatMedias = vmObservationsRepository.genericStatMedias( connection, config.RANG_STAT ) + configuration = base_configuration.copy() configuration.update({ @@ -104,9 +107,11 @@ def index(): 'AFFICHAGE_INTRODUCTION': config.AFFICHAGE_INTRODUCTION }) + + + connection.close() session.close() - return render_template( 'templates/index.html', observations=observations, @@ -115,7 +120,8 @@ def index(): stat=stat, customStat=customStat, customStatMedias=customStatMedias, - configuration=configuration + configuration=configuration, + ) @@ -163,7 +169,8 @@ def ficheEspece(cd_ref): 'ZOOM_LEVEL_POINT': config.ZOOM_LEVEL_POINT, 'LIMIT_CLUSTER_POINT': config.LIMIT_CLUSTER_POINT, 'FICHE_ESPECE': True, - 'MAP': config.MAP + 'MAP': config.MAP, + 'URL_REFERENTIEL_SPECIES_SHEET' : config.URL_REFERENTIEL_SPECIES_SHEET.format(cd_ref) }) connection.close() @@ -188,6 +195,7 @@ def ficheEspece(cd_ref): taxonDescription=taxonDescription, observers=observers, configuration=configuration + ) @@ -305,7 +313,7 @@ def ficheGroupe(groupe): def photos(): session = utils.loadSession() connection = utils.engine.connect() - + local = request.accept_languages.best_match(config.LANGUAGES.keys()) groups = vmTaxonsRepository.getINPNgroupPhotos(connection) communesSearch = vmCommunesRepository.getAllCommunes(session) configuration = base_configuration @@ -316,21 +324,40 @@ def photos(): 'templates/galeriePhotos.html', communesSearch=communesSearch, groups=groups, - configuration=configuration + configuration=configuration, + local=local ) @main.route('/', methods=['GET', 'POST']) def get_staticpages(page): session = utils.loadSession() + #On récupère la langue du navigateur + local = request.accept_languages.best_match(config.LANGUAGES.keys()) if (page not in config.STATIC_PAGES): abort(404) static_page = config.STATIC_PAGES[page] communesSearch = vmCommunesRepository.getAllCommunes(session) configuration = base_configuration session.close() - return render_template( - static_page['template'], - communesSearch=communesSearch, - configuration=configuration - ) + + translate_template_location = static_page['template']+'_'+local+'.html' + # on essaye de renvoyer le template traduit + + try: + return render_template( + translate_template_location, + communesSearch=communesSearch, + configuration=configuration + ) + # On essaye de renvoyer l'ancienne template + except (TemplateNotFound): + try: + return render_template( + static_page['template']+'.html', + communesSearch=communesSearch, + configuration=configuration + ) + # s'il existe pas on renvoie un 404 + except TemplateNotFound: + abort(404) \ No newline at end of file diff --git a/main/configuration/config.py.sample b/main/configuration/config.py.sample index 0a0ef2a6..951d1966 100644 --- a/main/configuration/config.py.sample +++ b/main/configuration/config.py.sample @@ -1,149 +1,163 @@ # -*- coding:utf-8 -*- -# Mettre l'application en mode debug ou pas +# Developpers only - Use debug mode modeDebug = False -# Connexion de l'application à la BDD -# Remplacer user, monpassachanger, IPADRESSE (localhost si la BDD est sur le même serveur que l'application), -# eventuellement le port de la BDD et le nom de la BDD avec l'utilisateur qui a des droits de lecture sur les vues de l'atlas (user_pg dans settings.ini) -database_connection = "postgresql://user:monpassachanger@IPADRESSE:5432/databaseName" +# Application database connection +# Replace user, mypasswordtochange, host (localhost if the database is on the same host as the application), +# eventually the database port and database name with reader user (user_pg in settings.ini) +database_connection = "postgresql://user:mypasswordtochange@host:5432/databaseName" ################################# ################################# -### Customisation application ### +### Application customisation ### ################################# ################################# -# Nom de la structure -STRUCTURE = "Nom de la structure" -STRUCTURE = unicode(STRUCTURE, 'utf-8') # Fonction permettant d'encoder ce nom en utf-8, à ne pas modifier +# Organisation name +STRUCTURE = "Organisation name" +STRUCTURE = unicode(STRUCTURE, 'utf-8') # Function used to encode the name in UTF-8, not to be changed -# Nom de l'application -NOM_APPLICATION = "Nom de l application" -NOM_APPLICATION = unicode(NOM_APPLICATION, 'utf-8') # Fonction permettant d'encoder ce nom en utf-8, à ne pas modifier +# Application name +NOM_APPLICATION = "Application name" +NOM_APPLICATION = unicode(NOM_APPLICATION, 'utf-8') # Function used to encode the name in UTF-8, not to be changed -# URL de l'application depuis la racine du domaine -# ex "/atlas" pour une URL: http://mon-domaine/atlas OU "" si l'application est accessible à la racine du domaine +# Application URL from domaine root +# Example : "/atlas" if your URL is http://my-domain/atlas OR "" if the application is accessible on root of domain URL_APPLICATION = "" -# Code de suivi des statistiques Google Analytics (si AFFICHAGE_FOOTER = True) +# Google Analytics tracking code (only if AFFICHAGE_FOOTER = True and if you want Google Analytics statistics) ID_GOOGLE_ANALYTICS = "UA-xxxxxxx-xx" -# Utiliser et afficher le glossaire (static/custom/glossaire.json.sample) +# Use and display glossary (static/custom/glossaire.json.sample) GLOSSAIRE = False ########################### -###### Cartographie ####### +###### Multilingual ####### ########################### -# Clé IGN si vous utilisez l'API Geoportail pour afficher les fonds cartographiques +# Available languages +LANGUAGES = { + 'en': 'English', + 'fr': 'French' +} + +# Default language to use if browser language is not available +BABEL_DEFAULT_LOCALE= 'fr' + +########################## +###### Cartography ####### +########################## + +# IGN key if you use French Geoportail API to display basemaps IGNAPIKEY = 'myIGNkey'; -# Configuration des cartes (centre du territoire, couches CARTE et ORTHO, échelle par défaut...) +# Maps configuration (territory center, CARTE (map) and ORTHO (photo) layers, default scale...) MAP = { 'LAT_LONG': [44.7952, 6.2287], 'FIRST_MAP': { - 'url' : 'http://gpp3-wxs.ign.fr/'+IGNAPIKEY+'/wmts?LAYER=GEOGRAPHICALGRIDSYSTEMS.MAPS.SCAN-EXPRESS.STANDARD&EXCEPTIONS=text/xml&FORMAT=image/jpeg&SERVICE=WMTS&VERSION=1.0.0&REQUEST=GetTile&STYLE=normal&TILEMATRIXSET=PM&&TILEMATRIX={z}&TILECOL={x}&TILEROW={y}', - 'attribution' : '© IGN', - 'tileName' : 'IGN' + 'url' : '//{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png', + 'attribution' : '© OpenStreetMap', + 'tileName' : 'OSM' }, 'SECOND_MAP' : {'url' :'https://gpp3-wxs.ign.fr/'+IGNAPIKEY+'/geoportail/wmts?LAYER=ORTHOIMAGERY.ORTHOPHOTOS&EXCEPTIONS=text/xml&FORMAT=image/jpeg&SERVICE=WMTS&VERSION=1.0.0&REQUEST=GetTile&STYLE=normal&TILEMATRIXSET=PM&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}', 'attribution' : '© IGN', 'tileName' : 'Ortho IGN' }, - 'ZOOM' : 10, - # Pas du slider sur les annees d'observations: 1 = pas de 1 an sur le slider + 'ZOOM' : 9, + # Slider steps for observations years (1 = 1 year step on slider) 'STEP': 1, - # Couleur et épaisseur des limites du territoire + # Color and thickness of territory border 'BORDERS_COLOR': '#000000', 'BORDERS_WEIGHT': 3 } -# Affichage des observations par maille ou point -# True = maille / False = point +# Observations display by grids or points +# True = grids / False = points AFFICHAGE_MAILLE = False -# Niveau de zoom à partir duquel on passe à l'affichage en point (si AFFICHAGE_MAILLE = False) +# Zoom level from which it switches to point display (only if AFFICHAGE_MAILLE = False) ZOOM_LEVEL_POINT = 11 -# Limite du nombre d'observations à partir duquel on passe à l'affichage en cluster +# Observations numbers limit from which it uses clusters LIMIT_CLUSTER_POINT = 1000 -# Carte de la page d'accueil: observations des 'x' derniers jours. Bien mettre en anglais et non accordé -NB_DAY_LAST_OBS = '7 day' -# Texte à afficher pour décrire la cartographie des 'dernières observations' -TEXT_LAST_OBS = u'Les observations des agents ces 7 derniers jours |' +# Homepage map : observations from 'x' latest days. +# To fill in English and without plurial, to define how long you want to display latest observations on homepage map +NB_DAY_LAST_OBS = '20 day' +# Text to display as title of this block. NO MORE USED ? In translations files now ??? +TEXT_LAST_OBS = u'Observations during the latest 20 days |' -# Carte de la fiche commune: nombre des 'x' dernières observations affichées +# Municipalties pages map : Number of 'x' latest observations displayed on default map NB_LAST_OBS=100 -########################### -###### PAGE ACCUEIL ####### -########################### +######################## +###### HOME PAGE ####### +######################## -# Bloc d'introduction presentant l'atlas. Affichage True/False +# Introduction block presenting the atlas(static/custom/templates/introduction.html). Display block ? True or False AFFICHAGE_INTRODUCTION = False -# Afficher le Footer sur toutes les pages (static/custom/templates/footer.html) +# Display Footer on all pages (static/custom/templates/footer.html). Display footer ? True or False AFFICHAGE_FOOTER = False -# Bloc de statistiques globales. Affichage True/False +# Global statistic block. Display block ? True or False AFFICHAGE_STAT_GLOBALES = True -# Bloc avec carte et liste des dernières observations. Affichage True/False +# Latest observations map and list block. Display block ? True or False AFFICHAGE_DERNIERES_OBS = True -# Bloc avec espèces à voir en ce moment. Affichage True/False +# Species to see currently block. Display block ? True or False AFFICHAGE_EN_CE_MOMENT = True -## BLOC STAT PAR RANG : Parametre pour le bloc statistique 2 de la page d'accueil (statistiques par rang remontant 2 espèces aléatoirement ayant au moins une photo) -# Ce bloc peut être affiché ou non et peut être affiché sur 2, 3 ou 4 colonnes. Il est ainsi possible de mettre autant de blocs que souhaité (2, 3, 4, 6, 8...) -# Mettre dans RANG_STAT le couple 'rang taxonomique' - 'nom du taxon correspondant au rang' pour avoir des statistique sur ce rang - -# Fonctionne à tous les niveaux de rang présents dans la table taxref - +## Statistics by taxonomic rank block : Setting for the second statistic block on homepage (statistics by rank displaying 2 random species that has at least one photo) +# This block can be displayed or not. And can be displayed on 2, 3 or 4 columns. It is possible to display as many blocks as wanted(2, 3, 4, 6, 8...) +# Fill in RANG_STAT the duo 'taxonomic rank' - 'taxon name of the rank rang' to have statistics about this rank +# Works at any level of ranks available in taxref taxonomie.table -# Exemple RANG_STAT = [{'ordre': ['Lepidoptera']}, {'classe': ['Insecta', 'Arachnida']}] -# RANG_STAT_FR ['Papillon', 'Insecte et Araignées'] +# Example RANG_STAT = [{'ordre': ['Lepidoptera']}, {'classe': ['Insecta', 'Arachnida']}] +# RANG_STAT_FR ['Butterfly', 'Insects and Spiders'] AFFICHAGE_RANG_STAT = True COLONNES_RANG_STAT = 3 RANG_STAT = [{'phylum': ["Arthropoda", "Mollusca"]}, {'phylum': ["Chordata"]}, {'regne': ["Plantae"]}] -RANG_STAT_FR = ['Faune invertébrée', 'Faune vertébrée', 'Flore'] +RANG_STAT_FR = ['Invertebrate fauna', 'Vertebrate fauna', 'Flora'] -# Fonction à ne pas modifier +# Function that shouldnt be changed for i in range(len(RANG_STAT_FR)): RANG_STAT_FR[i]=unicode( RANG_STAT_FR[i], 'utf-8') ############################ -####### FICHE ESPECE ####### +####### SPECIES PAGE ####### ############################ -# Rang taxonomique qui fixe jusqu'à quel taxon remonte la filiation taxonomique (hierarchie dans la fiche d'identite : Famille, Ordre etc... ) +# Taxonomic rank that set until which rank is displayed the taxonomic filitation (hierarchy in species identity block : Family, Order etc... ) LIMIT_RANG_TAXONOMIQUE_HIERARCHIE = 13 -# Rang taxonomique qui fixe la limite de l'affichage de la fiche espece ou de la liste -# 35 = ESPECE -# On prend alors tout ce qui est inferieur ou egal a l'espece pour faire des fiches et ce qui est superieur pour les listes +# Taxonomic rank that set the switch from species pages display to species list page display +# 35 = SPECIES (see atlas.bib_taxref_rangs table) +# If 35, all rank below or equal will be displayed as a detailled species page. All ranks above will be displayed as species list page LIMIT_FICHE_LISTE_HIERARCHY = 28 -# URL d'accès aux photos et autres médias (URL racine). Par exemple l'url d'accès à Taxhub -# Cette url sera cachée aux utilisateurs de l'atlas +# URL to access to photos and other medias (Roots URL). As an example the TaxHub URL +# This URL will be hidden to web browsers by a rewriting rule REMOTE_MEDIAS_URL = "http://mondomaine.fr/taxhub/" -# Racine du chemin des fichiers médias stockés dans le champ "chemin" de "atlas.vm_medias" -# Seule cette partie de l'url sera visible pour les utilisateurs de l'atlas +# Root of path of media files savec in "chemin" column of "atlas.vm_medias" +# Only this part of the URL will be displayed to web browers REMOTE_MEDIAS_PATH = "static/medias/" -# URL de TaxHub (pour génération à la volée des vignettes des images). -# Si le service Taxhub n'est pas utilisé, commenter la variable -TAXHUB_URL = "http://mondomaine.fr/taxhub" +# TaxHub URL (If TaxHub is used to generate dynamic images thumbnails). +# If this TaxHub service is not used, comment this setting +TAXHUB_URL = "http://mydomain.com/taxhub" -#### ID DES ATTRIBUTS DESCRIPTIFS DES TAXONS DE LA TABLE vm_cor_taxon_attribut +#### Types ID of attributes describing taxons in atlas.vm_cor_taxon_attribut ATTR_DESC = 100 ATTR_COMMENTAIRE = 101 ATTR_MILIEU = 102 ATTR_CHOROLOGIE = 103 -#### ID DES TYPES DE MEDIAS DE LA TABLE vm_medias +#### Types ID of medias from atlas.vm_medias ATTR_MAIN_PHOTO = 1 ATTR_OTHER_PHOTO = 2 ATTR_LIEN = 3 @@ -154,20 +168,27 @@ ATTR_YOUTUBE = 7 ATTR_DAILYMOTION = 8 ATTR_VIMEO = 9 -############################################ -#### FICHE COMMUNE ET RANG TAXONOMIQUE ##### -############################################ +# Links to INPN species pages. Can be changed to link to another Species website (such as GBIF) +# The URL is automatically generated with taxon ID (cd_nom column) +# To be changed only if you don't use French taxonomic referential (taxref) +URL_REFERENTIEL_SPECIES_SHEET = "https://inpn.mnhn.fr/espece/cd_nom/{}" +# Example for GBIF +# URL_REFERENTIEL_SPECIES_SHEET = "https://www.gbif.org/species/{}" + +################################################### +#### MUNICIPALITIES and TAXONOMIC RANKS PAGES ##### +################################################### -# Permet d'afficher ou non les colonnes Protection et/ou Patrimonialité/Enjeux dans les listes de taxons -# Se basent sur les champs "atlas.vm_taxons.protection_stricte"` (oui/non) et "atlas.vm_taxons.patrimonial" +# Allows to display or not the columns Protection and/or Patrimoniality/Stakes in taxons lists +# Based on fields "atlas.vm_taxons.protection_stricte" (oui/non) and "atlas.vm_taxons.patrimonial" -# Afficher ou non la colonne Protection dans les listes de taxons (basé sur le champs "protection_stricte") +# Display column Protection in taxons lists (based on field "protection_stricte") PROTECTION = True -# Afficher ou non la colonne Patrimonialité dans les listes de taxons (basé sur le champs "patrimonial") et la customiser -# Pour masquer cette colonne, passer uniquement le paramètre à "False" +# Display column Patrimonialité in taxons lists (based on field "patrimonial") and to customize it +# To hide this column, set this parameter to "False" # PATRIMONIALITE = False -# Pour customiser l'affichage de cette colonne (label affiché, valeurs du champs et leur affichage) : +# To customize the display of this column (displayed label, field values and their display) : PATRIMONIALITE = { 'label': "Patrimonial", 'config': { @@ -178,12 +199,12 @@ PATRIMONIALITE = { } } -############################# -#### Pages statistiques ##### -############################# +####################### +#### Static pages ##### +####################### -# Permet de lister les pages statiques souhaitées et de les afficher dynamiquement dans le menu sidebar -# Les pictos se limitent au Glyphicon proposés par Bootstrap (https://getbootstrap.com/docs/3.3/components/) +# Allow to list static pages wanted and to display them dynamically in the sidebar menu +# Pictograms are using Glyphicon (https://www.glyphicons.com/) STATIC_PAGES = { 'presentation': {'title': u"Présentation de l'atlas", 'picto': 'glyphicon-question-sign', 'order': 0, 'template': 'static/custom/templates/presentation.html'} } diff --git a/main/configuration/settings.ini.sample b/main/configuration/settings.ini.sample index 370a2345..aa561e1c 100644 --- a/main/configuration/settings.ini.sample +++ b/main/configuration/settings.ini.sample @@ -1,135 +1,146 @@ app_name=atlas -##################### -### Gunicorn settings -##################### +######################### +### Gunicorn settings ### +######################### gun_num_workers=4 gun_host=0.0.0.0 gun_port=8080 -#################### -### Python settings -#################### +####################### +### Python settings ### +####################### venv_dir=venv -# -# GeoNature-atlas -# PostgreSQL database settings -#................................. +#################################### +### PostgreSQL database settings ### +#################################### -# Effacer la base de données existante lors de l'installation +# Drop eventual existing database during installation drop_apps_db=false -# Host de la base de données de l'application +# Database host (leave localhost if the database is installed on the same server as the application) +# If the database is installed on another host, the automatic installation script install_db.sh will not work as it has not enough permissions db_host=localhost -# Port pour base de données de l'application +# Database host db_port=5432 -# Nom de la base de données de l'application +# Database name db_name=geonatureatlas -# Nom de l'utilisateur BDD, utilisé par l'application, lecteur des vues matérialisées uniquement +# Database reader username, used by web application, with read only on material views user_pg=geonatatlas -# Nom du propriétaire de la BDD, utilisé pour créer et mettre à jour la BDD +# Database owner username, used to create and update database owner_atlas=geonatuser -# Password de l'utilisateur de l'application -user_pg_pass=monpassachanger +# Database reader user password +user_pg_pass=mypasswordtochange -# Password du propriétaire de la BDD -owner_atlas_pass=monpassachanger +# Database owner user password +owner_atlas_pass=mypasswordtochange -# GeoNature-atlas est-il connecté à une BDD GeoNature ? -geonature_source=true -# Version de geonature utilisée 1 ou 2 +# Is GeoNature-atlas connected to a GeoNature database +geonature_source=false + +# If TRUE : + +# GeoNature version (1 or 2) geonature_version=2 -# Est-ce que l'atlas est installé dans la même base de données que geonature ou non -# true : base de données distante + +# Is GeoNature-atlas database in the same database as GeoNature ? +# If true : remote database that will be accessed with Foreign Data Wrapper (FDW) geonature_fdw=true -################################################ -##### CONNEXION A LA BDD GEONATURE SOURCE ###### -################################################ -# Necessaire uniquement si on veut se connecter à la BDD source GeoNature en foreign data wrapper -# Si vous n'utilisez pas GeoNature, vous pouvez vous inspirer du fichier data/atlas_geonature.sql pour vous connecter à une autre BDD mère +################################################# +##### GEONATURE database connection SOURCE ###### +################################################# + +# Only if geonature_source=true +# Only required if you want to connected to a GeoNature database with Foreign Data Wrapper +# If you have a remote database with your observations which is not GeoNature, +# and want to connect GeoNature-atlas to it, you can inspire yourself from data/atlas_geonature.sql to connect to another mother database -# Host de la BDD GeoNature source +# GeoNature source database host db_source_host=localhost -# Port de la BDD GeoNature source +# GeoNature source database port db_source_port=5432 -# Nom de la BDD GeoNature source +# GeoNature source database name db_source_name=geonaturedb -# Nom de l'utilisateur atlas dans la BDD GeoNature source (lecture seule) +# GeoNature source database username (read only) atlas_source_user=geonatuser -# Pass de l'utilisateur atlas dans la BDD GeoNature source (lecture seule) +# GeoNature source database username password (read only) atlas_source_pass=monpassachanger +####################### +### GEOGRAPHIC data ### +####################### - -##################################################################### -### Données GEOGRAPHIQUE ### -##################################################################### - -# L'atlas est il en lien avec le référentiel géographique modèle géonature v2 +# GeoNature-atlas is it connected to GeoNature 2 geographical referentiel (ref_geo) ? use_ref_geo_gn2=true -########### Si ref_geo = true ############ +##### If use_ref_geo = true ##### type_maille="'M1'" type_territoire="'PEC'" +##### If use_ref_geo = False ###### +## MUNICIPALITIES ## -########### Si ref_geo = False ############### COMMUNES #### - -# Creer la table des communes à partir d'un shapefile ? -# Si false, modifiez la creation de 'atlas.vm_communes' dans data/atlas.sql +# Create municipalities table from a shapefile ? +# If false, change the content of 'atlas.vm_communes' in data/atlas.sql import_commune_shp=true -# Chemin et nom des colonnes du SHP des communes du territoire. Laisser tel quel (en modifiant uniquement MYUSERLINUX) pour utiliser les communes du PnEcrins par défaut +# Path and column name of the municipalities SHP file +# Leave it so Laisser tel quel (just changing MYUSERLINUX) if you want to use Ecrins national park municipalities dataset communes_shp=/home/MYUSERLINUX/atlas/data/ref/communes.shp +# Municipalities ID column name colonne_insee=insee +# Municipalities name column name colonne_nom_commune=nom_com -### TERRITOIRE #### +### TERRITORY #### -# Chemin vers le SHP de l'emprise du territoire +# Path to territory SHP file limit_shp=/home/MYUSERLINUX/atlas/data/ref/territoire.shp -##### MAILLES ##### +##### GRIDS ##### -# Mon territoire se situe en métropole ? Dans ce cas, on utilise les mailles fournies par l'INPN -metropole=true +# Is my territory in French metropolis ? +# In this case, it will automatically use grids provided by INPN (French national museum) +metropole=false -# Choisissez alors la taille de vos mailles à utiliser (en km) / Valeurs possibles 1, 5 ou 10 +# If metropole=true, choose the size of the grids you want to use (in km) / Values available : 1, 5 or 10 taillemaille=5 -# Si 'metropole=false', rajoutez dans le dossier /data/ref un SHP des mailles de votre territoire et renseignez son chemin +# If 'metropole=false', upload a SHP file in /data/ref folder with grids you want to use and fill its path chemin_custom_maille=/home/MYUSERLINUX/atlas/data/ref/custom_maille.shp -##################################################################### -### Données TAXONOMIQUE ### -###################################################################### Installer le schéma taxonomie de TaxHub dans la BDD de GeoNature-atlas ? -install_taxonomie=false +###################### +### TAXONOMIC data ### +###################### + +# Install "taxonomie" database schema from TaxHub into GeoNature-atlas database ? +install_taxonomie=true -# Version de TaxHub à utiliser pour installer le schéma taxonomie -# GeoNature-atlas 1.3.0 est compatible avec les versions de Taxhub inférieure ou égale à 1.3.2 -# Numéro de version conseillée et testée : 1.3.2 +# TaxHub version to use to install "taxonomie" schema +# GeoNature-atlas 1.3.0 is compatible with TaxHub version lower or equal to 1.3.2 +# Recommanded and tested version : 1.3.2 taxhub_release=1.3.2 -#### ID DES TYPES DES ATTRIBUTS DESCRIVANT LES TAXONS DANS atlas.vm_cor_taxon_attribut -- -## !! si changement: modifier également dans main/configuration/config.py +#### Types ID of attributes describing taxons in atlas.vm_cor_taxon_attribut +## If you change these id, change also in main/configuration/config.py file attr_desc=100 attr_commentaire=101 attr_milieu=102 attr_chorologie=103 -# Paramètre pour la vue atlas.vm_taxons_plus_observes -# Especes les plus observées sur la periode 'moins X jour, plus X jours par rapport à la date du jour, toutes années confondues' -# 15 jours par défaut +# atlas.vm_taxons_plus_observes view settings +# Most observed species in period 'minus X days, plus X days compared to today, all years' +# 15 days by default time=15 diff --git a/main/modeles/repositories/vmMoisRepository.py b/main/modeles/repositories/vmMoisRepository.py index 0aa76c89..a649e3cc 100644 --- a/main/modeles/repositories/vmMoisRepository.py +++ b/main/modeles/repositories/vmMoisRepository.py @@ -2,6 +2,7 @@ # -*- coding:utf-8 -*- from sqlalchemy.sql import text +from flask.ext.babel import gettext def getMonthlyObservationsChilds(connection, cd_ref): @@ -21,16 +22,16 @@ def getMonthlyObservationsChilds(connection, cd_ref): mesMois = connection.execute(text(sql), thiscdref=cd_ref) for inter in mesMois: return [ - {'mois': "Janvier", 'value': inter._01}, - {'mois': "Fevrier", 'value': inter._02}, - {'mois': "Mars", 'value': inter._03}, - {'mois': "Avril", 'value': inter._04}, - {'mois': "Mai", 'value': inter._05}, - {'mois': "Juin", 'value': inter._06}, - {'mois': "Juillet", 'value': inter._07}, - {'mois': "Aout", 'value': inter._08}, - {'mois': "Septembre", 'value': inter._09}, - {'mois': "Octobre", 'value': inter._10}, - {'mois': "Novembre", 'value': inter._11}, - {'mois': "Decembre", 'value': inter._12} + {'mois': gettext('graph.janv'), 'value': inter._01}, + {'mois': gettext('graph.fev'), 'value': inter._02}, + {'mois': gettext('graph.mar'), 'value': inter._03}, + {'mois': gettext('graph.avr'), 'value': inter._04}, + {'mois': gettext('graph.mai'), 'value': inter._05}, + {'mois': gettext('graph.jui'), 'value': inter._06}, + {'mois': gettext('graph.juil'), 'value': inter._07}, + {'mois': gettext('graph.aou'), 'value': inter._08}, + {'mois': gettext('graph.sep'), 'value': inter._09}, + {'mois': gettext('graph.oct'), 'value': inter._10}, + {'mois': gettext('graph.nov'), 'value': inter._11}, + {'mois': gettext('graph.dec'), 'value': inter._12} ] \ No newline at end of file diff --git a/main/modeles/utils.py b/main/modeles/utils.py index 0b8dbb52..f1d07c34 100644 --- a/main/modeles/utils.py +++ b/main/modeles/utils.py @@ -25,8 +25,8 @@ def serializeQuery( data, columnDef): return rows -def deleteAccent(string): - return unicodedata.normalize('NFD', string).encode('ascii', 'ignore') +def deleteAccent(string=u''): + return unicodedata.normalize('NFD', u'').encode('ascii', 'ignore') def findPath(row): if row.chemin == None and row.url == None: diff --git a/requirements.txt b/requirements.txt index 1ecfe8f4..ca62d11a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,3 +12,4 @@ GeoAlchemy2==0.3.0 psycopg2==2.7.3.2 gunicorn==19.7.1 Flask-Script==2.0.6 +flask_babel==0.12.2 \ No newline at end of file diff --git a/static/custom/templates/introduction.html.sample b/static/custom/templates/introduction.html.sample index 2c743e01..2697330c 100644 --- a/static/custom/templates/introduction.html.sample +++ b/static/custom/templates/introduction.html.sample @@ -16,7 +16,7 @@

- {{configuration.NOM_APPLICATION}} + {{configuration.NOM_APPLICATION}}
diff --git a/static/custom/templates/presentation_en.html b/static/custom/templates/presentation_en.html new file mode 100644 index 00000000..ccc8cffb --- /dev/null +++ b/static/custom/templates/presentation_en.html @@ -0,0 +1,440 @@ + + + + + + Presentation of the atlas | {{configuration.NOM_APPLICATION}} - {{configuration.STRUCTURE}} + + + + + + + + + + + + + + + + + + + {% include 'templates/navbar.html' %} + + +
+ + + + + + + + +
+
+ + +

Biodiv'Ecrins, the atlas of flora and fauna of the Ecrins National Park

+

+ The National Park has been collecting fauna and flora data on its territory for more than 40 years, which are used to better understand biodiversity, to monitor the evolution of certain fragile or heritage species ... To act intelligently to safeguard this natural heritage. requires to know him and understand it. +

+

+ Biodiv'Ecrins puts at your disposal all the data collected by the Ecrins National Park since its creation in 1973. +

+

+ Everyday, its agents make observations in the framework of their missions with a real concern to enrich the knowledge on the alpine biodiversity.They are displayed in real time on this atlas.You can thus follow the state of the knowledge on this territory." +

+
+
+

+ +

+

+ Inauguration of Biodiv'Ecrins on November 29, 2016 during the press conference organized by the Ministry of the Environment, at the National Museum of Natural History (MNHN) in Paris. +

+

+ This meeting is associated with the publication of the first law enforcement decree for the recovery of biodiversity, nature and landscapes which, in its article 7, strengthens the national policy on the inventory of natural heritage and opening the data. +

+

+ Read the article on the website of the Ecrins National Park
+ Download the press release
+ Download the photos +

+
+
+ +
+ + +
+
+ Generic placeholder image +

Species Sheets

+

Find the record of each species with their map of the observations, their altitudinal and monthly distribution, as well as descriptions, photos, videos, audios and complementary links

+

Example »

+
+
+ Generic placeholder image +

Municipality sheets

+

Discover the species observed in each commune of the national park and post their observations on the map of the town.

+

Example »

+
+
+ Generic placeholder image +

Pictures gallery

+

Discover the photographs of the various species, made mainly by the agents of the National Park during their missions in the field.

+

Browse »

+
+
+ + + + +
+ + +
+ +

Wildlife.
Big and small animals. +

+

+ With some surprises always possible, the vertebrate fauna is now well identified in the Ecrins National Park. + These are mammals, birds, reptiles and amphibians. +

+

+ This is not the case for invertebrate fauna. These are the strange little beasts that are insects, snails, centipedes or even spiders, beetles and crayfish ... A quantity of species as impressive as full of scientific promise. +

+

+ + « The National Park database is not an inventory. + It gathers information collected under different scientific protocols with different objectives. + In fact, the large number of ibex sightings does not mean that it is the species most present in the massif but of a highly followed species, especially in the context of reintroductions ! » + +

+

+ -Ludovic Imberdis, 'Wildlife' project manager at the Écrins National Park +

+

+ To know more : http://www.ecrins-parcnational.fr/thematique/faune-sauvage. +

+
+ + +
+ +
+ +

Wild flora.
Species on all floors. +

+

+ +

+ More than 2000 species of plants are presented in this atlas. + If the inventory of the plant world continues in the Ecrins, the National Park also keeps track of emblematic species (such as the blue thistle and the Venus hoof) and participates in many research programs on the natural environments and species of high altitude. +

+

+ Some plants present remarkable life stories, ranging from heirs to old farming practices (hay meadows, extensive grain crops) to high mountain explorers. +

+

+ + « The immense interest of an online atlas is to share and make live an exceptional knowledge of the wild world present in the Ecrins.
+ Such a tool restores the sometimes hackneyed term of 'biodiversity', elegantly describing and illustrating the abundant diversity of species observed and studied.» +
+

+

+ - Cédric Dentant, botanist, project manager flora and environment in the Ecrins National Park +

+

+ To know more : http://www.ecrins-parcnational.fr/thematique/flore. +

+ +
+ + + +
+
+ +

A scientific strategy.
For knowledge and protection. +

+

+ The preservation of species, habitats and natural resources is based on the collection of observations, the shaping of knowledge and the contribution to scientific research. +

+

+ + Which species frequent the massif, how do they interact, how do their populations evolve, or what are the consequences for these species of the territory's human activities? + It is to answer such questions that different scientific protocols are implemented. + Many of the raw observations related to these protocols are synthesized in this atlas. + +

+

+ The richness of the fauna and flora of the Ecrins is due to the diversity of climatic and geological influences, to the altitudinal amplitude - ranging from about 800 m to 4102 m - and to the different reliefs of the massif. + So, the Provencal vole and the ocellated lizard, southern species, are present in the territory of the Ecrins in the same way as the snow vole and ptarmigan, relicts of the last glaciations. + The diversity of ecological conditions is suitable for many plants, ranging from robust larch steep slopes to microscopic chlamydomonas of fir trees ! +

+

+ To preserve this exceptional natural heritage, at the origin of the creation of the National Park, it is necessary to know it well. The various inventory, monitoring and study programs undertaken in the territory all pursue this objective. +

+

+ To learn more, see the action of the National Park in terms of fauna and flora :
+ http://www.ecrins-parcnational.fr/thematique/faune-sauvage
+ http://www.ecrins-parcnational.fr/thematique/flore +

+
+ + +
+ +
+
+

GeoNature-atlas.
In the constellation of the opensource.

+

+ Biodiv'Ecrins uses the tool GeoNature-atlas developed by the Ecrins National Park and published under a free license. It is thus freely transferable to other structures wishing to share their naturalistic observations based on the INPN's national standards. +

+

+ Download it presentation sheet of GeoNature-atlas to know more. +

+

+ It is part of a set of tools developed by the National Park and its partners, in order to capture, manage and process data from different protocols (http://geonature.fr). +

+

+ +

+

+ + « Our tools are thought from the outset to be able to be deployed by other structures in different contexts. + For this, the focus is on generic developments and on the publication of the freely licensed tool for ease of use by others. ». + +

+

+ - Camille Monchicourt, head of the information system at the Ecrins National Park +

+

+ Indeed the Ecrins National Park has undertaken for the past ten years, to migrate its information system to open source tools.
+ Free software (whose source code is open, accessible and modifiable by whomever it wishes) allows greater modularity and interoperability of tools and data, in addition to facilitating pooling and reducing licensing costs. +

+

+ This is why the national park also wished that the tools that it develops for its own needs are also published under free license.
+ In 2011, the Ecrins National Park designed and published under free license the application Geotrek
to manage and enhance the trails. Today, it is used by some forty structures in France that have made it evolve in turn, leading to significant pooling of public resources. + To learn more, read 'Geotrek, the advent of a community of users'. +

+

+ * Opensource software is a computer program whose source code is distributed under a "free" license, allowing anyone to read, modify or redistribute this software. +

+
+
+ +
+ + +
+
+

Observer networks.
Bundles of knowledge.

+

+ The National Park is part of a naturalist data collection network. + It contributes to the enrichment of thematic databases available to both specialists and the public. +

+

+ By multiplying the exchange conventions, the National Park values ​​and expands the use of the data acquired by its agents. +

+

+ According to the websites, it is possible to CONSULT information, DOWNLOAD syntheses or even to PARTICIPATE in the observations. +

+

+ +

+

+ National Inventory of Natural Heritage (MNHN) +

+

+ On the site dedicated to the MNHN (National Museum of Natural History), we find more than 300 000 data on wildlife in the Ecrins National Park among 30 million collected throughout the national territory and agglomerated in this national inventory . +
+ The National Museum uses this information to synthesize at national and international levels. +
+ This approach makes it possible to include environmental issues in national and European policies. +

+

+ To learn more, read National Park observations are online. +

+

+ To download organized data +

+

+ SILENE PACA +

+

+ Silene, ISNL platform (Information System on Nature and Landscapes), is the data portal of the Provence-Alpes-Côte d'Azur region.}
+ On this site which allows to enter and to consult a mass of very important data, syntheses of the inheritances flora and fauna of the region by commune and by mesh are available +

+

+ See also the counterpart for the Rhône-Alpes region : The Flora and Habitats Information Center (FHIC). +

+

+ National Alpine Botanical Conservatory (NABC) +

+

+ The site of the National Alpine Botanical Conservatory offers for its entire range of approval (Alps and Ain: 04-05-01) data relating to flora and habitats. + The Park is an important contributor. +

+

+ See as well SI National Flora et Tela Botanica. +

+

+ To participate ! +

+

+ Anyone can, if he wishes, become a contributor by transmitting his observations of mammals, but also other species, on different naturalistic platforms and in particular, for the Ecrins, on the two participatory sites of the LPO. +
+ faune-paca.org et faune-isere.org +

+

+ It is also a way to supplement the knowledge of the National Park since there is a data exchange agreement with the LPO. +
+ This is also the case with the Group chiroptera of Provence. +

+

+ For flora, an online atlas for the Hautes-Alpes department also welcomes contributions : bdflore05.org. + As for wildlife, a convention has been initiated and is actively involved in regularly exchanging observational data. +
Side Isère, the association Gentiana animates a permanent inventory of the flora of the department : gentiana.org. +

+
+
+ +
+ + + +
+ + {% if configuration.AFFICHAGE_FOOTER %} + {% include 'static/custom/templates/footer.html' %} + {% endif %} +
+ + + + + + + + \ No newline at end of file diff --git a/static/custom/templates/presentation_fr.html b/static/custom/templates/presentation_fr.html new file mode 100644 index 00000000..73c6c760 --- /dev/null +++ b/static/custom/templates/presentation_fr.html @@ -0,0 +1,441 @@ + + + + + + Présentation de l'atlas | {{configuration.NOM_APPLICATION}} - {{configuration.STRUCTURE}} + + + + + + + + + + + + + + + + + + + {% include 'templates/navbar.html' %} + + +
+ + + + + + + + +
+
+ + +

Biodiv'Ecrins, l'atlas de la flore et de la faune du Parc national des Ecrins

+

+ Le Parc national recueille des données faune et flore sur son territoire depuis plus de 40 ans. Celles-ci sont utilisées pour mieux connaître la biodiversité, suivre les évolutions de certaines espèces fragiles ou patrimoniales… Car agir intelligemment pour la sauvegarde de ce patrimoine naturel requiert de le connaître et le comprendre. +

+

+ Biodiv'Ecrins met à votre disposition l'ensemble des données collectées par le Parc national des Écrins depuis sa création en 1973. +

+

+ Chaque jour, ses agents font des observations dans le cadre de leurs missions avec un véritable souci d'enrichissement des connaissances sur la biodiversité alpine. Elles sont affichées en temps réel sur cet atlas. Vous pouvez ainsi suivre l'état des connaissances sur ce territoire. +

+
+
+

+ +

+

+ Inauguration de Biodiv'Ecrins le 29 novembre 2016 lors de la conférence de presse organisée par le Ministère de l'Environnement, au Musée national d'histoire naturelle (MNHN) à Paris. +

+

+ Ce rendez-vous est associé à la publication du premier décret d'application de la loi pour la reconquête de la biodiversité, de la nature et des paysages qui, dans son article 7, renforce la politique nationale en matière d'inventaire du patrimoine naturel et d'ouverture des données. +

+

+ Lire l'article sur le site internet du Parc national des Ecrins
+ Télécharger le communiqué de presse
+ Télécharger les photos +

+
+
+ +
+ + +
+
+ Generic placeholder image +

Fiches espèces

+

Retrouvez la fiche de chaque espèce avec leur carte des observations, leur répartition altitudinale et mensuelle, ainsi que des descriptions, photos, vidéos, audios et liens complémentaires

+

Exemple »

+
+
+ Generic placeholder image +

Fiches communes

+

Découvrez les espèces observées sur chaque commune du parc national et affichez leurs observations sur la carte de la commune.

+

Exemple »

+
+
+ Generic placeholder image +

Galerie photos

+

Découvrez les photographies des différentes espèces, réalisées principalement par les agents du Parc national lors de leurs missions sur le terrain.

+

Parcourir »

+
+
+ + + + +
+ + +
+ +

Faune sauvage.
Grandes et petites bêtes. +

+

+ A quelques surprises près toujours possibles, la faune des vertébrés est aujourd'hui bien identifiée dans le Parc national des Écrins. + Il s'agit des mammifères, oiseaux, reptiles et amphibiens. +

+

+ Il n'en va pas de même pour la faune des invertébrés. Il s'agit de ces étranges petites bêtes que sont les insectes, les escargots, les millepattes ou encore les araignées, coléoptères et écrevisses... Une quantité d'espèces aussi impressionnante que pleine de promesses scientifiques. +

+

+ + « La base de données du Parc national n'est pas un inventaire. + Elle rassemble des informations collectées dans le cadre de différents protocoles scientifiques avec des objectifs différents. + De fait, le nombre important d'observations de bouquetins ne veut pas dire qu'il s'agit de l'espèce la plus présente dans le massif mais bien d'une espèces très suivie, notamment dans le cadre des réintroductions ! » + +

+

+ - Ludovic Imberdis, chargé de mission « faune » au Parc national des Écrins +

+

+ Pour en savoir plus : http://www.ecrins-parcnational.fr/thematique/faune-sauvage. +

+
+ + +
+ +
+ +

Flore sauvage.
Des espèces à tous les étages. +

+

+ +

+ Plus de 2000 espèces de plantes sont présentées dans cet atlas. + Si l'inventaire du monde végétal se poursuit dans les Écrins, le Parc national assure également le suivi d'espèces emblématiques (comme le chardon bleu et le sabot de Vénus) et participe à de nombreux programmes de recherche sur les milieux et espèces naturels de haute altitude. +

+

+ Certaines plantes présentent des histoires de vie remarquables, allant des héritières de pratiques agricoles anciennes (prairies de fauche, cultures extensives de céréales) aux exploratrices de la haute montagne. +

+

+ + « L'immense intérêt d'un atlas en ligne est de partager et faire vivre une connaissance exceptionnelle du monde sauvage présent dans les Ecrins.
+ Un tel outil redonne corps au terme parfois éculé de 'biodiversité', décrivant et illustrant avec élégance la foisonnante diversité des espèces observées et étudiées. » +
+

+

+ - Cédric Dentant, botaniste, chargé de mission flore et milieux au Parc national des Écrins +

+

+ Pour en savoir plus : http://www.ecrins-parcnational.fr/thematique/flore. +

+ +
+ + + +
+
+ +

Une stratégie scientifique.
Une stratégie scientifique. +

+

+ La préservation des espèces, des habitats et des ressources naturelles s'appuie sur le recueil d'observations, le façonnage des connaissances et la contribution à la recherche scientifique. +

+

+ + Quelles espèces fréquentent le massif, comment elles interagissent, comment évoluent leurs populations, ou encore quelles sont les conséquences sur ces espèces des activités humaines du territoire ? + C'est pour répondre à ce type de questions que différents protocoles scientifiques sont mis en œuvre. + Un grand nombre des observations brutes liées à ces protocoles sont synthétisées dans cet atlas. + +

+

+ La richesse de la faune et de la flore des Écrins tient à la diversité des influences climatiques, géologiques, à l'amplitude altitudinale – s'échelonnant d'environ 800 m à 4102 m –, et aux différents modelés des reliefs du massif. + Ainsi, le campagnol provençal et le lézard ocellé, espèces méridionales, sont présents dans le territoire des Ecrins au même titre que le campagnol des neiges et le lagopède alpin, relictes des dernières glaciations. + La diversité des conditions écologiques convient à nombre de plantes, allant du robuste mélèze des pentes abruptes à la microscopique chlamydomonas des névés ! +

+

+ Pour conserver ce patrimoine naturel d'exception, à l'origine de la création du Parc national, il convient de bien le connaître. Les différents programmes d'inventaire, de suivi ou d'études engagés sur le territoire poursuivent tous cet objectif. +

+

+ Pour en savoir plus, voir l'action du Parc national en termes de faune et de flore :
+ http://www.ecrins-parcnational.fr/thematique/faune-sauvage
+ http://www.ecrins-parcnational.fr/thematique/flore +

+
+ + +
+ +
+
+

GeoNature-atlas.
Dans la constellation de l'opensource.

+

+ Biodiv'Ecrins utilise l'outil GeoNature-atlas développé par le Parc national des Écrins et publié sous licence libre. Il est ainsi transférable librement à d'autres structures qui souhaitent partager leurs observations naturalistes en se basant sur les référentiels nationaux de l'INPN. +

+

+ Téléchargez la fiche de présentation de GeoNature-atlas pour en savoir plus. +

+

+ Il fait partie d'un ensemble d'outils développé par le Parc national et ses partenaires, pour pouvoir saisir, gérer et traiter les données des différents protocoles (http://geonature.fr). +

+

+ +

+

+ + « Nos outils sont pensés, dès le départ, pour pouvoir être déployés par d’autres structures dans des contextes différents. + Pour cela, l’accent est mis sur des développements génériques et sur la publication de l’outil sous licence libre pour en faciliter l’utilisation par d’autres ». + +

+

+ - Camille Monchicourt, responsable du système d’informations au Parc national des Ecrins +

+

+ En effet le Parc national des Ecrins a entrepris depuis une dizaine d'années, de migrer son système d'informations vers des outils open source.
+ Les logiciels libres (dont le code source est ouvert, accessible et modifiable par qui le souhaite) permettent une plus grande modularité et interopérabilité des outils et des données, en plus de faciliter la mutualisation et de réduire les coûts liés aux licences. +

+

+ C'est pourquoi le parc national a aussi souhaité que les outils qu'il développe pour ses propres besoins soient eux-aussi publiés sous licence libre.
+ En 2011, le Parc national des Ecrins a conçu et publié sous licence libre l'application Geotrek
pour gérer et valoriser les sentiers. Elle est aujourd'hui utilisée par une quarantaine de structures en France qui l'ont faite évoluer à leur tour, entrainant ainsi d'importantes mutualisations des ressources publiques. + Pour en savoir plus, lire "Geotrek, l’avènement d'une communauté d'utilisateurs". +

+

+ * Un logiciel Opensource est un programme informatique dont le code source est distribué sous une licence dite « libre », permettant à quiconque de lire, modifier ou redistribuer ce logiciel. +

+
+
+ +
+ + +
+
+

Réseaux d'observateurs.
Faisceaux de connaissances.

+

+ Le Parc national fait partie d'un réseau de collecte de données naturalistes. + Il contribue ainsi à enrichir des bases de données thématiques mises à disposition tant des spécialistes que du public. +

+

+ En multipliant les conventions d'échanges, le Parc national valorise et élargit l'utilisation des données acquises par ses agents. +

+

+ Selon les sites internet, il est possible de CONSULTER les informations, de TÉLÉCHARGER des synthèses voire de PARTICIPER aux observations. +

+

+ +

+

+ Inventaire National du Patrimoine Naturel (INPN) +

+

+ Sur le site consacré à l'INPN (Muséum national d'histoire naturelle), on retrouve plus de 300 000 données sur la faune du Parc national des Écrins parmi les 30 millions collectées sur l'ensemble du territoire national et agglomérées dans cet inventaire national. +
+ Le Muséum national utilise ces informations pour réaliser des synthèses aux échelles nationales et internationales. +
+ Cette démarche permet d'inscrire les enjeux environnementaux dans les politiques nationales et européennes. +

+

+ Pour en savoir plus, lire Les observations du Parc national sont en ligne. +

+

+ Pour télécharger des données organisées +

+

+ SILENE PACA +

+

+ Silene, plate-forme SINP (Système d'information sur la nature et les paysages), est le portail de données de la région Provence-Alpes-Côte d'Azur.
+ Sur ce site qui permet de saisir et de consulter une masse de données très importante, des synthèses des patrimoines flore et faune de la région par commune et par maille sont disponibles. +

+

+ Voir aussi l'homologue pour la région Rhône-Alpes: Le pôle d'information flore et habitats (PIFH). +

+

+ Conservatoire botanique national alpin (CBNA) +

+

+ Le site du Conservatoire botanique national alpin offre pour toute son aire d'agrément (Alpes et Ain : 04-05-01) les données relatives à la flore et aux habitats. + Le Parc en est un contributeur important. +

+

+ Voir aussi le SI Flore national et Tela Botanica. +

+

+ Pour participer ! +

+

+ Chacun peut, s'il le souhaite, devenir contributeur en transmettant ses observations de mammifères, mais aussi d'autres espèces, sur différentes plateformes naturalistes et notamment, pour les Écrins, sur les deux sites participatifs de la LPO. +
+ faune-paca.org et faune-isere.org +

+

+ C'est aussi une façon de compléter les connaissances du Parc national puisqu'il existe une convention d'échanges de données avec la LPO. +
+ C'est également le cas avec avec leGroupe chiroptères de Provence. +

+

+ Pour la flore, un atlas en ligne pour le département des Hautes-Alpes accueille également les contributions : bdflore05.org. + De même que pour la faune, une convention a été engagée et vit activement pour régulièrement échanger les données d'observation. +
Côté Isère, l'association Gentiana anime un inventaire permanent de la flore du département :gentiana.org. +

+
+
+ +
+ + + +
+ + +
+ + {% if configuration.AFFICHAGE_FOOTER %} + {% include 'static/custom/templates/footer.html' %} + {% endif %} + + + + + + + \ No newline at end of file diff --git a/static/images/logo_gbif.png b/static/images/logo_gbif.png new file mode 100644 index 00000000..58e36957 Binary files /dev/null and b/static/images/logo_gbif.png differ diff --git a/static/images/picto_Arthropoda.png b/static/images/picto_Arthropoda.png new file mode 100644 index 00000000..593e2f3d Binary files /dev/null and b/static/images/picto_Arthropoda.png differ diff --git a/static/images/picto_Chordata.png b/static/images/picto_Chordata.png new file mode 100644 index 00000000..b14b09f5 Binary files /dev/null and b/static/images/picto_Chordata.png differ diff --git a/static/images/picto_Cnidaria.png b/static/images/picto_Cnidaria.png new file mode 100644 index 00000000..6b5fce02 Binary files /dev/null and b/static/images/picto_Cnidaria.png differ diff --git a/static/images/picto_Default.png b/static/images/picto_Default.png new file mode 100644 index 00000000..c07cf2d4 Binary files /dev/null and b/static/images/picto_Default.png differ diff --git a/static/images/picto_Echinodermata.png b/static/images/picto_Echinodermata.png new file mode 100644 index 00000000..537a5292 Binary files /dev/null and b/static/images/picto_Echinodermata.png differ diff --git a/static/images/picto_Mollusca.png b/static/images/picto_Mollusca.png new file mode 100644 index 00000000..5b9b3191 Binary files /dev/null and b/static/images/picto_Mollusca.png differ diff --git a/static/images/picto_Tracheophyta.png b/static/images/picto_Tracheophyta.png new file mode 100644 index 00000000..5fff4ea3 Binary files /dev/null and b/static/images/picto_Tracheophyta.png differ diff --git a/static/images/sample.accueil-intro.jpg b/static/images/sample.home-intro.jpg similarity index 100% rename from static/images/sample.accueil-intro.jpg rename to static/images/sample.home-intro.jpg diff --git a/static/mapGenerator.js b/static/mapGenerator.js index cbddecc3..d5fa67a1 100644 --- a/static/mapGenerator.js +++ b/static/mapGenerator.js @@ -115,11 +115,11 @@ function onEachFeaturePoint(feature, layer){ // popup Maille function onEachFeatureMaille(feature, layer){ - popupContent = "Nombre d'observation(s): "+ feature.properties.nb_observations+"
Dernière observation: "+ feature.properties.last_observation+ " " ; + popupContent = "" +feature.properties.nb_observations+ " observation(s)
Dernière observation: "+ feature.properties.last_observation+ " " ; layer.bindPopup(popupContent) } - +nbObs + "observation(s)" // Style maille function getColor(d) { return d > 100 ? '#800026' : @@ -147,7 +147,7 @@ function generateLegendMaille(){ var div = L.DomUtil.create('div', 'info legend'), grades = [0, 1, 2, 5, 10, 20, 50, 100], - labels = [" Nombre
d'observations

"]; + labels = [" Observation(s)
"]; // loop through our density intervals and generate a label with a colored square for each interval for (var i = 0; i < grades.length; i++) { @@ -604,7 +604,7 @@ function generateSliderOnMap(){ $(sliderContainer).css("margin-left", "200px"); $(sliderContainer).css("text-align", "center"); $(sliderContainer).append("

" - +"

Nombre d'observation(s): "+nb_obs+"

"); + +"

"+nb_obs+" observation(s)

"); L.DomEvent.disableClickPropagation(sliderContainer); return sliderContainer; } diff --git a/static/mapMailles.js b/static/mapMailles.js index 5d087354..637ec288 100644 --- a/static/mapMailles.js +++ b/static/mapMailles.js @@ -40,7 +40,7 @@ $.ajax({ myGeoJson.features.forEach(function(l){ nbObs += l.properties.nb_observations }) - $("#nbObs").html("Nombre d'observation(s): "+ nbObs); + $("#nbObs").html( nbObs + " observation(s)"); @@ -58,7 +58,7 @@ $.ajax({ nbObs += l.properties.nb_observations }) - $("#nbObs").html("Nombre d'observation(s): "+ nbObs); + $("#nbObs").html( nbObs + " observation(s)"); }); diff --git a/static/mapPoint.js b/static/mapPoint.js index f250e2b6..0799b8ab 100644 --- a/static/mapPoint.js +++ b/static/mapPoint.js @@ -57,7 +57,7 @@ $.ajax({ nbObs += l.properties.nb_observations }) - $("#nbObs").html("Nombre d'observation(s): "+ nbObs); + $("#nbObs").html(nbObs + " observation(s)"); }); @@ -109,7 +109,7 @@ $.ajax({ nbObs += l.properties.nb_observations }) - $("#nbObs").html("Nombre d'observation(s): "+ nbObs); + $("#nbObs").html(nbObs + " observation(s)"); }); } diff --git a/templates/404.html b/templates/404.html new file mode 100644 index 00000000..8a54ebc2 --- /dev/null +++ b/templates/404.html @@ -0,0 +1,127 @@ + + + + + {{ _('404.title') }} + + + + + + + + + + + + + + + + + + + + + + + + + +