diff --git a/.gitignore b/.gitignore index fedbe0fc..5c2bd0bd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,40 +1,45 @@ *.pyc -tests/* -config/settings.ini -config/config.py +.htpasswd log/* -static/conf/custom.js +atlas/static/conf/custom.js atlas/debug.py -data/ref/emprise_territoire.* -static/territoire.json -static/images/ancien -atlas/configuration/config.py -atlas/configuration/settings.ini robots.txt .htaccess venv/* venv3/* -data/ref/communes.shp -data/ref/communes.shx -data/ref/communes.dbf -data/ref/communes.prj +atlas/configuration/config.py +atlas/configuration/settings.ini + +atlas/static/conf/custom.js +atlas/static/territoire.json +atlas/static/images/ancien +atlas/static/node_modules +atlas/static/territoire.json +atlas/static/images/ancie +n +atlas/static/custom/territoire.json +atlas/static/custom/glossaire.json +atlas/static/custom/custom.css +atlas/static/custom/maps-custom.js static/custom/territoire.json static/custom/glossaire.json static/custom/custom.css static/custom/maps-custom.js -static/custom/images/logo-structure.png -static/custom/images/accueil-intro.jpg +atlas/static/custom/images/logo-structure.png +atlas/static/custom/images/accueil-intro.jpg static/custom/images/favicon.ico -static/custom/images/logo_patrimonial.png +atlas/static/custom/images/logo_patrimonial.png -static/custom/templates/presentation.html -static/custom/templates/footer.html -static/custom/templates/introduction.html -static/custom/templates/credits.html -static/custom/templates/mentions-legales.html +atlas/static/custom/templates/bandeaulogoshome.html +atlas/static/custom/templates/presentation.html +atlas/static/custom/templates/footer.html +atlas/static/custom/templates/introduction.html +atlas/static/custom/templates/credits.html +atlas/static/custom/templates/mentions-legales.html +data/ref/emprise_territoire.* data/ref/communes.dbf data/ref/communes.prj data/ref/communes.shp @@ -45,7 +50,15 @@ data/ref/territoire.prj data/ref/territoire.shp data/ref/territoire.shx +data/ref/L93* +data/ref/mailles* + # Pycharm .idea/ .vscode + +.coverage +.tox +*.swp +*.swo diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 00000000..c49cd55d --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,5 @@ +include VERSION +include README.txt +include LICENCE.txt +include requirements.in +include tox.ini diff --git a/README.rst b/README.rst index 27b05c5c..5df0eb04 100644 --- a/README.rst +++ b/README.rst @@ -40,6 +40,10 @@ Atlas en ligne utilisant GeoNature-atlas : - `Société Herpétologique de France `_ - `Picardie Nature `_ - `Métropole clermontoise `_ +- `PNR Forêt d'Orient `_ +- `Archipel des Mascareignes `_ + +Archipel des Mascareignes Technologies ------------ diff --git a/VERSION b/VERSION index 9df886c4..bc80560f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.4.2 +1.5.0 diff --git a/atlas-service.conf b/atlas-service.conf deleted file mode 100644 index ff29c0ce..00000000 --- a/atlas-service.conf +++ /dev/null @@ -1,6 +0,0 @@ -[program:atlas] -command = APP_PATH/gunicorn_start.sh -autostart=true -autorestart=true -stdout_logfile = APP_PATH/log/errors_atlas.log -redirect_stderr = true diff --git a/initAtlas.py b/atlas/app.py similarity index 66% rename from initAtlas.py rename to atlas/app.py index 09bc94ed..fad45d28 100644 --- a/initAtlas.py +++ b/atlas/app.py @@ -1,18 +1,12 @@ import os -import sys -from flask import Flask, render_template -from flask_sqlalchemy import SQLAlchemy - -from werkzeug.serving import run_simple -from atlas.configuration import config -from atlas.utils import format_number -from sqlalchemy import create_engine, MetaData, Table +from flask import Flask, request, session, redirect, url_for, g from flask_compress import Compress +from flask_sqlalchemy import SQLAlchemy +from flask_babel import Babel, format_date, gettext, ngettext, get_locale -from atlas.configuration.config_parser import read_and_validate_conf -from atlas.configuration.config_schema import AtlasConfig, SecretSchemaConf -from atlas.configuration import config +from atlas.env import config, secret_conf +from atlas.utils import format_number db = SQLAlchemy() compress = Compress() @@ -45,21 +39,27 @@ def __call__(self, environ, start_response): def create_app(): """ - renvoie une instance de l'app Flask + renvoie une instance de l'app Flask """ - - # validation de la configuration - # configuration publique - valid_config = read_and_validate_conf(config, AtlasConfig) - app = Flask(__name__, template_folder=APP_DIR) # push the config in app config at 'PUBLIC' key - app.config.update(valid_config) - - app.debug = valid_config["modeDebug"] + app.config.update(config) + babel = Babel(app) + + @babel.localeselector + def get_locale(): + # if MULTILINGUAL, valid language is in g via before_request_hook + if config["MULTILINGUAL"]: + return g.lang_code + return config["DEFAULT_LANGUAGE"] + + app.debug = secret_conf["modeDebug"] + app.config["SECRET_KEY"] = secret_conf["SECRET_KEY"] with app.app_context() as context: from atlas.atlasRoutes import main as main_blueprint + if config["MULTILINGUAL"]: + app.register_blueprint(main_blueprint, url_prefix="/") app.register_blueprint(main_blueprint) from atlas.atlasAPI import api @@ -68,12 +68,12 @@ def create_app(): compress.init_app(app) app.wsgi_app = ReverseProxied( - app.wsgi_app, script_name=valid_config["URL_APPLICATION"] + app.wsgi_app, script_name=config["URL_APPLICATION"] ) @app.context_processor def inject_config(): - return dict(configuration=valid_config) + return dict(configuration=config) @app.template_filter("pretty") def pretty(val): @@ -82,11 +82,11 @@ def pretty(val): return app -app = create_app() if __name__ == "__main__": # validation de la configuration secrète - secret_conf = read_and_validate_conf(config, SecretSchemaConf) + app = create_app() app.run( - host="0.0.0.0", port=secret_conf["GUNICORN_PORT"], debug=app.config["modeDebug"] + host="0.0.0.0", + port=secret_conf["GUNICORN_PORT"], + debug=secret_conf["modeDebug"], ) - diff --git a/atlas/atlasAPI.py b/atlas/atlasAPI.py index 28f2c01e..8f0c478e 100644 --- a/atlas/atlasAPI.py +++ b/atlas/atlasAPI.py @@ -1,16 +1,15 @@ # -*- coding:utf-8 -*- from flask import jsonify, Blueprint, request, current_app -from werkzeug.wrappers import Response -from . import utils -from .modeles.repositories import ( + +from atlas import utils +from atlas.modeles.repositories import ( vmSearchTaxonRepository, vmObservationsRepository, vmObservationsMaillesRepository, vmMedias, vmCommunesRepository, ) -from .configuration import config api = Blueprint("api", __name__) @@ -31,6 +30,7 @@ def searchCommuneAPI(): search = request.args.get("search", "") limit = request.args.get("limit", 50) results = vmCommunesRepository.getCommunesSearch(session, search, limit) + session.close() return jsonify(results) if not current_app.config['AFFICHAGE_MAILLE']: @@ -70,6 +70,8 @@ def getObservationsMailleAPI(cd_ref, year_min=None, year_max=None): return jsonify(observations) + + if not current_app.config['AFFICHAGE_MAILLE']: @api.route("/observationsPoint/", methods=["GET"]) def getObservationsPointAPI(cd_ref): @@ -78,6 +80,29 @@ def getObservationsPointAPI(cd_ref): session.close() return jsonify(observations) + + +@api.route("/observations/", methods=["GET"]) +def getObservationsGenericApi(cd_ref: int): + """[summary] + + Args: + cd_ref (int): [description] + + Returns: + [type]: [description] + """ + session = utils.loadSession() + observations = vmObservationsMaillesRepository.getObservationsMaillesChilds( + session, + cd_ref, + year_min=request.args.get("year_min"), + year_max=request.args.get("year_max"), + ) if current_app.config['AFFICHAGE_MAILLE'] else vmObservationsRepository.searchObservationsChilds(session, cd_ref) + session.close() + return jsonify(observations) + + if not current_app.config['AFFICHAGE_MAILLE']: @api.route("/observations//", methods=["GET"]) def getObservationsCommuneTaxonAPI(insee, cd_ref): @@ -133,4 +158,4 @@ def test(): current_app.config["ATTR_OTHER_PHOTO"], ) connection.close() - return jsonify(photos) + return jsonify(photos) \ No newline at end of file diff --git a/atlas/atlasRoutes.py b/atlas/atlasRoutes.py index 5a96a238..6cdc4d6f 100644 --- a/atlas/atlasRoutes.py +++ b/atlas/atlasRoutes.py @@ -1,8 +1,26 @@ # -*- coding:utf-8 -*- +from urllib.parse import urlparse +from urllib.parse import urlunparse + +from datetime import datetime, timedelta + +from flask import Blueprint, g +from flask import ( + render_template, + redirect, + abort, + current_app, + make_response, + request, + url_for, + session, +) -from flask import render_template, redirect, abort, current_app -from .configuration import config -from .modeles.repositories import ( +from atlas import utils +from atlas.env import config +from atlas.modeles.entities import vmTaxons, vmCommunes +from atlas.modeles.repositories import ( + vmOrganismsRepository, vmTaxonsRepository, vmObservationsRepository, vmAltitudesRepository, @@ -14,11 +32,36 @@ vmCorTaxonAttribut, vmTaxonsMostView, ) -from . import utils -from flask import Blueprint -main = Blueprint("main", __name__) +# Adding functions for multilingual url process if MULTILINGUAL = True +main = Blueprint("main", __name__) # , url_prefix='/') +if config["MULTILINGUAL"]: + + @main.url_defaults + def add_language_code(endpoint, values): + if "lang_code" in values: + return + values["lang_code"] = g.lang_code + + @main.url_value_preprocessor + def pull_lang_code(endpoint, values): + g.lang_code = values.pop("lang_code", None) + + @main.before_request + def redirect_default_language(): + if g.lang_code is None: + if "language" in session: + default_lang_code = session["language"] + else: + default_lang_code = request.accept_languages.best_match( + config["AVAILABLE_LANGUAGES"].keys(), config["DEFAULT_LANGUAGE"] + ) + view_args = request.view_args + view_args["lang_code"] = default_lang_code + return redirect(url_for(request.endpoint, **view_args)) + else: + session["language"] = g.lang_code @main.route( @@ -33,6 +76,52 @@ def especeMedias(image): ) +# Activating organisms sheets routes +if config["ORGANISM_MODULE"]: + + @main.route("/organism/", methods=["GET", "POST"]) + def ficheOrganism(id_organism): + db_session = utils.loadSession() + connection = utils.engine.connect() + + infos_organism = vmOrganismsRepository.statOrganism(connection, id_organism) + + stat = vmObservationsRepository.statIndex(connection) + + mostObsTaxs = vmOrganismsRepository.topObsOrganism(connection, id_organism) + update_most_obs_taxons = [] + for taxon in mostObsTaxs: + taxon_info = vmTaxrefRepository.searchEspece(connection, taxon["cd_ref"]) + photo = vmMedias.getFirstPhoto( + connection, taxon["cd_ref"], current_app.config["ATTR_MAIN_PHOTO"] + ) + taxon = {**taxon, **taxon_info["taxonSearch"]} + taxon["photo"] = photo + update_most_obs_taxons.append(taxon) + stats_group = vmOrganismsRepository.getTaxonRepartitionOrganism( + connection, id_organism + ) + + connection.close() + db_session.close() + + return render_template( + "templates/organismSheet/_main.html", + nom_organism=infos_organism["nom_organism"], + adresse_organism=infos_organism["adresse_organism"], + cp_organism=infos_organism["cp_organism"], + ville_organism=infos_organism["ville_organism"], + tel_organism=infos_organism["tel_organism"], + url_organism=infos_organism["url_organism"], + url_logo=infos_organism["url_logo"], + nb_taxons=infos_organism["nb_taxons"], + nb_obs=infos_organism["nb_obs"], + stat=stat, + mostObsTaxs=update_most_obs_taxons, + stats_group=stats_group, + ) + + @main.route( "/commune/" + current_app.config["REMOTE_MEDIAS_PATH"] + "", methods=["GET", "POST"], @@ -84,45 +173,65 @@ def indexMedias(image): def index(): session = utils.loadSession() connection = utils.engine.connect() - - if current_app.config["AFFICHAGE_MAILLE"]: - observations = vmObservationsMaillesRepository.lastObservationsMailles( - connection, - current_app.config["NB_DAY_LAST_OBS"], - current_app.config["ATTR_MAIN_PHOTO"], - ) + if current_app.config["AFFICHAGE_DERNIERES_OBS"]: + if current_app.config["AFFICHAGE_MAILLE"]: + current_app.logger.debug("start AFFICHAGE_MAILLE") + observations = vmObservationsMaillesRepository.lastObservationsMailles( + connection, + str(current_app.config["NB_DAY_LAST_OBS"]) + " day", + current_app.config["ATTR_MAIN_PHOTO"], + ) + current_app.logger.debug("end AFFICHAGE_MAILLE") + else: + current_app.logger.debug("start AFFICHAGE_PRECIS") + observations = vmObservationsRepository.lastObservations( + connection, + str(current_app.config["NB_DAY_LAST_OBS"]) + " day", + current_app.config["ATTR_MAIN_PHOTO"], + ) + current_app.logger.debug("end AFFICHAGE_PRECIS") else: - observations = vmObservationsRepository.lastObservations( - connection, - current_app.config["NB_DAY_LAST_OBS"], - current_app.config["ATTR_MAIN_PHOTO"], - ) + observations = [] + current_app.logger.debug("start mostViewTaxon") mostViewTaxon = vmTaxonsMostView.mostViewTaxon(connection) + current_app.logger.debug("end mostViewTaxon") stat = vmObservationsRepository.statIndex(connection) - customStat = vmObservationsRepository.genericStat( - connection, current_app.config["RANG_STAT"] - ) - customStatMedias = vmObservationsRepository.genericStatMedias( - connection, current_app.config["RANG_STAT"] - ) + current_app.logger.debug("start customStat") + + if current_app.config["AFFICHAGE_RANG_STAT"]: + customStat = vmObservationsRepository.genericStat( + connection, current_app.config["RANG_STAT"] + ) + current_app.logger.debug("end customStat") + current_app.logger.debug("start customStatMedia") + customStatMedias = vmObservationsRepository.genericStatMedias( + connection, current_app.config["RANG_STAT"] + ) + current_app.logger.debug("end customStatMedia") + else: + customStat = [] + customStatMedias = [] + + lastDiscoveries = vmObservationsRepository.getLastDiscoveries(connection) connection.close() session.close() return render_template( - "templates/index.html", + "templates/home/_main.html", observations=observations, mostViewTaxon=mostViewTaxon, stat=stat, customStat=customStat, customStatMedias=customStatMedias, + lastDiscoveries=lastDiscoveries, ) @main.route("/espece/", methods=["GET", "POST"]) def ficheEspece(cd_ref): - session = utils.loadSession() + db_session = utils.loadSession() connection = utils.engine.connect() cd_ref = int(cd_ref) @@ -131,7 +240,7 @@ def ficheEspece(cd_ref): months = vmMoisRepository.getMonthlyObservationsChilds(connection, cd_ref) synonyme = vmTaxrefRepository.getSynonymy(connection, cd_ref) communes = vmCommunesRepository.getCommunesObservationsChilds(connection, cd_ref) - taxonomyHierarchy = vmTaxrefRepository.getAllTaxonomy(session, cd_ref) + taxonomyHierarchy = vmTaxrefRepository.getAllTaxonomy(db_session, cd_ref) firstPhoto = vmMedias.getFirstPhoto( connection, cd_ref, current_app.config["ATTR_MAIN_PHOTO"] ) @@ -163,11 +272,13 @@ def ficheEspece(cd_ref): ) observers = vmObservationsRepository.getObservers(connection, cd_ref) + organisms = vmOrganismsRepository.getListOrganism(connection, cd_ref) + connection.close() - session.close() + db_session.close() return render_template( - "templates/ficheEspece.html", + "templates/speciesSheet/_main.html", taxon=taxon, listeTaxonsSearch=[], observations=[], @@ -183,6 +294,7 @@ def ficheEspece(cd_ref): articles=articles, taxonDescription=taxonDescription, observers=observers, + organisms=organisms, ) @@ -195,25 +307,30 @@ def ficheCommune(insee): commune = vmCommunesRepository.getCommuneFromInsee(connection, insee) if current_app.config["AFFICHAGE_MAILLE"]: observations = vmObservationsMaillesRepository.lastObservationsCommuneMaille( - connection, current_app.config["NB_LAST_OBS"], insee + connection, current_app.config["NB_LAST_OBS"], str(insee) ) else: observations = vmObservationsRepository.lastObservationsCommune( connection, current_app.config["NB_LAST_OBS"], insee ) + surroundingAreas = [] + observers = vmObservationsRepository.getObserversCommunes(connection, insee) session.close() connection.close() return render_template( - "templates/ficheCommune.html", + "templates/areaSheet/_main.html", + sheetType="commune", + surroundingAreas=surroundingAreas, listTaxons=listTaxons, - referenciel=commune, + areaInfos=commune, observations=observations, observers=observers, DISPLAY_EYE_ON_LIST=True, + insee=insee, ) @@ -231,7 +348,7 @@ def ficheRangTaxonomie(cd_ref): session.close() return render_template( - "templates/ficheRangTaxonomique.html", + "templates/taxoRankSheet/_main.html", listTaxons=listTaxons, referenciel=referenciel, taxonomyHierarchy=taxonomyHierarchy, @@ -253,7 +370,7 @@ def ficheGroupe(groupe): connection.close() return render_template( - "templates/ficheGroupe.html", + "templates/groupSheet/_main.html", listTaxons=listTaxons, referenciel=groupe, groups=groups, @@ -271,8 +388,12 @@ def photos(): session.close() connection.close() - return render_template("templates/galeriePhotos.html", groups=groups) + return render_template("templates/photoGalery/_main.html", groups=groups) +if config["AFFICHAGE_RECHERCHE_AVANCEE"]: + @main.route("/recherche", methods=["GET"]) + def advanced_search(): + return render_template("templates/core/advanced_search.html", ) @main.route("/", methods=["GET", "POST"]) def get_staticpages(page): @@ -283,3 +404,56 @@ def get_staticpages(page): session.close() return render_template(static_page["template"]) + +@main.route("/sitemap.xml", methods=["GET"]) +def sitemap(): + """Generate sitemap.xml iterating over static and dynamic routes to make a list of urls and date modified""" + pages = [] + ten_days_ago = datetime.now() - timedelta(days=10) + session = utils.loadSession() + connection = utils.engine.connect() + url_root = request.url_root + if url_root[-1] == "/": + url_root = url_root[:-1] + for rule in current_app.url_map.iter_rules(): + # check for a 'GET' request and that the length of arguments is = 0 and if you have an admin area that the rule does not start with '/admin' + if ( + "GET" in rule.methods + and len(rule.arguments) == 0 + and not rule.rule.startswith("/api") + ): + pages.append([url_root + rule.rule, ten_days_ago]) + + # get dynamic routes for blog + species = session.query(vmTaxons.VmTaxons).order_by(vmTaxons.VmTaxons.cd_ref).all() + for species in species: + url = url_root + url_for("main.ficheEspece", cd_ref=species.cd_ref) + modified_time = ten_days_ago + pages.append([url, modified_time]) + + municipalities = ( + session.query(vmCommunes.VmCommunes).order_by(vmCommunes.VmCommunes.insee).all() + ) + for municipalitie in municipalities: + url = url_root + url_for("main.ficheCommune", insee=municipalitie.insee) + modified_time = ten_days_ago + pages.append([url, modified_time]) + + sitemap_template = render_template( + "templates/sitemap.xml", + pages=pages, + url_root=url_root, + last_modified=ten_days_ago, + ) + response = make_response(sitemap_template) + response.headers["Content-Type"] = "application/xml" + return response + + +@main.route("/robots.txt", methods=["GET"]) +def robots(): + robots_template = render_template("static/custom/templates/robots.txt") + response = make_response(robots_template) + response.headers["Content-type"] = "text/plain" + + return response diff --git a/atlas/babel.cfg b/atlas/babel.cfg new file mode 100644 index 00000000..5f1ff3f0 --- /dev/null +++ b/atlas/babel.cfg @@ -0,0 +1,4 @@ +[python: **.py] +[jinja2: **/templates/**/**.html] +[jinja2: **/static/custom/templates/**.sample] +extensions=jinja2.ext.autoescape,jinja2.ext.with_ \ No newline at end of file diff --git a/atlas/configuration/config.py.example b/atlas/configuration/config.py.example index 6069c5a2..39b660fd 100644 --- a/atlas/configuration/config.py.example +++ b/atlas/configuration/config.py.example @@ -1,5 +1,9 @@ # -*- coding:utf-8 -*- +######################################### +## Exemple de fichier de configuration ## +######################################### + # Mettre l'application en mode debug ou pas modeDebug = False @@ -27,6 +31,53 @@ NOM_APPLICATION = "Nom de l application" # ex "/atlas" pour une URL: http://mon-domaine/atlas OU "" si l'application est accessible à la racine du domaine URL_APPLICATION = "" +################################# +################################# +###### Modules activation ####### +################################# +################################# + +# Enable organism module : organism sheet + organism participation on species sheet +ORGANISM_MODULE = False + +########################### +###### Multilingual ####### +########################### + +# Default language, also used when multilingual is disabled +DEFAULT_LANGUAGE = 'fr' + +# Activate multilingual +MULTILINGUAL = False + +# Available languages +# Don't delete, even if you disable MULTILINGUAL +# You need to add your own default language (DEFAULT_LANGUAGE) here if it's not present +# Check documentation to add another language +LANGUAGES = { + 'en': { + 'name' : 'English', + 'flag_icon' : 'flag-icon-gb', + 'months' : ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'] + }, + 'fr': { + 'name' : 'Français', + 'flag_icon' : 'flag-icon-fr', + 'months' : ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Decembre'] + }, + 'it': { + 'name' : 'Italiano', + 'flag_icon' : 'flag-icon-it', + 'months' : ['Gennaio', 'Febbraio', 'Marzo', 'Aprile', 'Maggio', 'Giugno', 'Luglio', 'Agosto', 'Settembre', 'Ottobre', 'Novembre', 'Dicembre'] + } +} + +##################### +##################### +### Configuration ### +##################### +##################### + # Code de suivi des statistiques Google Analytics (si AFFICHAGE_FOOTER = True) ID_GOOGLE_ANALYTICS = "UA-xxxxxxx-xx" @@ -57,7 +108,16 @@ MAP = { 'STEP': 1, # Couleur et épaisseur des limites du territoire 'BORDERS_COLOR': '#000000', - 'BORDERS_WEIGHT': 3 + 'BORDERS_WEIGHT': 3, + # Permet de générer un masque autour du territoire + # Pour activer mettre fill à True + 'MASK_STYLE': { + "fill": False, + "fillColor": '#020202', + "fillOpacity": 0.3 + }, + 'ENABLE_SLIDER': True, + 'ENABLE_SCALE': True } # Affichage des observations par maille ou point @@ -71,11 +131,12 @@ ZOOM_LEVEL_POINT = 11 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' +NB_DAY_LAST_OBS = '7' + # Texte à afficher pour décrire la cartographie des 'dernières observations' TEXT_LAST_OBS = 'Les observations des agents ces 7 derniers jours |' -# Carte de la fiche commune: nombre des 'x' dernières observations affichées +# Carte de la fiche commune : nombre des 'x' dernières observations affichées NB_LAST_OBS=100 ########################### @@ -83,10 +144,10 @@ NB_LAST_OBS=100 ########################### # Bloc d'introduction presentant l'atlas. Affichage True/False -AFFICHAGE_INTRODUCTION = False +AFFICHAGE_INTRODUCTION = True # Afficher le Footer sur toutes les pages (static/custom/templates/footer.html) -AFFICHAGE_FOOTER = False +AFFICHAGE_FOOTER = True # Bloc de statistiques globales. Affichage True/False AFFICHAGE_STAT_GLOBALES = True @@ -97,6 +158,9 @@ AFFICHAGE_DERNIERES_OBS = True # Bloc avec espèces à voir en ce moment. Affichage True/False AFFICHAGE_EN_CE_MOMENT = True +# Bloc dernières espèces découvertes. Affichage True/False +AFFICHAGE_NOUVELLES_ESPECES = 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 - @@ -107,10 +171,9 @@ AFFICHAGE_EN_CE_MOMENT = True AFFICHAGE_RANG_STAT = True COLONNES_RANG_STAT = 3 -RANG_STAT = [{'phylum': ["Arthropoda", "Mollusca", "Annelida", "Cnidaria", "Platyhelminthes"]]}, {'phylum': ["Chordata"]}, {'regne': ["Plantae"]}] +RANG_STAT = [{'phylum': ["Arthropoda", "Mollusca", "Annelida", "Cnidaria", "Platyhelminthes"]}, {'phylum': ["Chordata"]}, {'regne': ["Plantae"]}] RANG_STAT_FR = ['Faune invertébrée', 'Faune vertébrée', 'Flore'] - ############################ ####### FICHE ESPECE ####### ############################ @@ -126,6 +189,7 @@ 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 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 REMOTE_MEDIAS_PATH = "static/medias/" @@ -133,7 +197,8 @@ 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 REDIMENSIONNEMENT_IMAGE = False -# si redimmentionnement image = True, indiquer l'URL de taxhub + +# si REDIMENSIONNEMENT_IMAGE = True, indiquer l'URL de TaxHub TAXHUB_URL = "http://mondomaine.fr/taxhub" #### ID DES ATTRIBUTS DESCRIPTIFS DES TAXONS DE LA TABLE vm_cor_taxon_attribut @@ -153,7 +218,7 @@ ATTR_YOUTUBE = 7 ATTR_DAILYMOTION = 8 ATTR_VIMEO = 9 -# coupe le nom_vernaculaire à la 1ere virgule sur les fiches espèces +# Coupe le nom_vernaculaire à la 1ere virgule sur les fiches espèces SPLIT_NOM_VERN = True ############################################ @@ -169,6 +234,7 @@ 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_PATRIMONIALITE = False + # Pour customiser l'affichage de cette colonne (label affiché, valeurs du champs et leur affichage) : PATRIMONIALITE = { 'label': "Patrimonial", @@ -180,12 +246,26 @@ PATRIMONIALITE = { } } +############################# +#### Lien custom du logo #### +############################# + +CUSTOM_LOGO_LINK='https://monadressecustom.org' + ############################# #### Pages statistiques ##### ############################# # 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/) +# Les pictos se limitent à font-awesome 5) STATIC_PAGES = { - 'presentation': {'title': "Présentation de l'atlas", 'picto': 'glyphicon-question-sign', 'order': 0, 'template': 'static/custom/templates/presentation.html'} + 'presentation': {'title': "Présentation de l'atlas", 'picto': 'fa-question-circle', 'order': 0, 'template': 'static/custom/templates/presentation.html'} } + +########################### +########################### +#### Security Config ##### +########################### +########################### + +SECRET_KEY = '282799166744079489444397' diff --git a/atlas/configuration/config.py.sample b/atlas/configuration/config.py.sample index 441e1d77..f0765c0c 100644 --- a/atlas/configuration/config.py.sample +++ b/atlas/configuration/config.py.sample @@ -1,5 +1,9 @@ # -*- coding:utf-8 -*- +############################## +## Fichier de configuration ## +############################## + # 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) @@ -19,11 +23,54 @@ NOM_APPLICATION = "Nom de l application" # 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 -URL_APPLICATION = "/atlas" +URL_APPLICATION = "" + +################################# +################################# +###### Modules activation ####### +################################# +################################# + +# Enable organism module : organism sheet + organism participation on species sheet +ORGANISM_MODULE = False + +########################### +###### Multilingual ####### +########################### + +# Default language, also used when multilingual is disabled +DEFAULT_LANGUAGE = 'fr' + +# Activate multilingual +MULTILINGUAL = False + +# Available languages +# Don't delete, even if you disable MULTILINGUAL +# You need to add your own default language (DEFAULT_LANGUAGE) here if it's not present +# Check documentation to add another language +LANGUAGES = { + 'en': { + 'name' : 'English', + 'flag_icon' : 'flag-icon-gb', + 'months' : ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'] + }, + 'fr': { + 'name' : 'Français', + 'flag_icon' : 'flag-icon-fr', + 'months' : ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Decembre'] + }, + 'it': { + 'name' : 'Italiano', + 'flag_icon' : 'flag-icon-it', + 'months' : ['Gennaio', 'Febbraio', 'Marzo', 'Aprile', 'Maggio', 'Giugno', 'Luglio', 'Agosto', 'Settembre', 'Ottobre', 'Novembre', 'Dicembre'] + } +} +########################### ########################### ###### Cartographie ####### ########################### +########################### # Configuration des cartes (centre du territoire, couches CARTE et ORTHO, échelle par défaut...) MAP = { @@ -45,3 +92,11 @@ MAP = { 'BORDERS_WEIGHT': 3, 'ENABLE_SLIDER': True } + +########################### +########################### +#### Security Config ##### +########################### +########################### + +SECRET_KEY = 'INSERT_A_RANDOM_SECRET_KEY' diff --git a/atlas/configuration/config_parser.py b/atlas/configuration/config_parser.py index 31c22e01..b99307b4 100644 --- a/atlas/configuration/config_parser.py +++ b/atlas/configuration/config_parser.py @@ -2,27 +2,15 @@ Utils pour lire le fichier de conf et le valider selon le schéma Marshmallow """ -from pathlib import Path - - -def read_and_validate_conf(config_module, config_schema): - conf_dict = { +def read_config_file(config_module): + return { var: getattr(config_module, var) for var in remove_reserved_word(config_module) } - configs_py, configerrors = config_schema().load(conf_dict) - if configerrors: - raise Exception( - "Erreur dans le fichier de configuraiton: {}".format(configerrors) - ) - return configs_py def remove_reserved_word(config_module): return [var for var in dir(config_module) if not var.startswith("__")] -def read_and_validation_from_dict(config_dict, config_schema): - configs_py, configerrors = config_schema().load(conf_dict) - if configerrors: - raise Exception(configerrors) - return configs_py +def valid_config_from_dict(config_dict, config_schema): + return config_schema().load(config_dict) \ No newline at end of file diff --git a/atlas/configuration/config_schema.py b/atlas/configuration/config_schema.py index 86f0f412..ccd05277 100644 --- a/atlas/configuration/config_schema.py +++ b/atlas/configuration/config_schema.py @@ -4,8 +4,9 @@ validates_schema, ValidationError, validates_schema, + EXCLUDE, ) -from marshmallow.validate import OneOf, Regexp +from marshmallow.validate import Regexp MAP_1 = { @@ -19,83 +20,157 @@ "attribution": "© OpenStreetMap-contributors, SRTM | Style: © OpenTopoMap (CC-BY-SA)", } +LANGUAGES = { + "en": { + "name": "English", + "flag_icon": "flag-icon-gb", + "months": [ + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December", + ], + }, + "fr": { + "name": "Français", + "flag_icon": "flag-icon-fr", + "months": [ + "Janvier", + "Février", + "Mars", + "Avril", + "Mai", + "Juin", + "Juillet", + "Août", + "Septembre", + "Octobre", + "Novembre", + "Decembre", + ], + }, + "it": { + "name": "Italiano", + "flag_icon": "flag-icon-it", + "months": [ + "Gennaio", + "Febbraio", + "Marzo", + "Aprile", + "Maggio", + "Giugno", + "Luglio", + "Agosto", + "Settembre", + "Ottobre", + "Novembre", + "Dicembre", + ], + }, +} + class SecretSchemaConf(Schema): + class Meta: + unknown = EXCLUDE + database_connection = fields.String( required=True, validate=Regexp( "^postgresql:\/\/.*:.*@[^:]+:\w+\/\w+$", - 0, - """Database uri is invalid ex: - postgresql://monuser:monpass@server:port/db_name""", + error="Database uri is invalid ex: postgresql://monuser:monpass@server:port/db_name", ), ) - GUNICORN_PORT = fields.Integer(missing=8080) + GUNICORN_PORT = fields.Integer(load_default=8080) + modeDebug = fields.Boolean(load_default=False) + SECRET_KEY = fields.String(required=True) class MapConfig(Schema): - LAT_LONG = fields.List(fields.Float(), missing=[44.7952, 6.2287]) - MIN_ZOOM = fields.Integer(missing=1) + LAT_LONG = fields.List(fields.Float(), load_default=[44.7952, 6.2287]) + MIN_ZOOM = fields.Integer(load_default=1) MAX_BOUNDS = fields.List( - fields.List(fields.Float()), missing=[[-180, -90], [180, 90]] + fields.List(fields.Float()), load_default=[[-180, -90], [180, 90]] + ) + FIRST_MAP = fields.Dict(load_default=MAP_1) + SECOND_MAP = fields.Dict(load_default=MAP_2) + ZOOM = fields.Integer(load_default=10) + STEP = fields.Integer(load_default=1) + BORDERS_COLOR = fields.String(load_default="#000000") + BORDERS_WEIGHT = fields.Integer(load_default=3) + ENABLE_SLIDER = fields.Boolean(load_default=True) + ENABLE_SCALE = fields.Boolean(load_default=True) + MASK_STYLE = fields.Dict( + load_default={"fill": False, "fillColor": "#020202", "fillOpacity": 0.3} ) - FIRST_MAP = fields.Dict(missing=MAP_1) - SECOND_MAP = fields.Dict(missing=MAP_2) - ZOOM = fields.Integer(missing=10) - STEP = fields.Integer(missing=1) - BORDERS_COLOR = fields.String(missing="#000000") - BORDERS_WEIGHT = fields.Integer(missing=3) - ENABLE_SLIDER = fields.Boolean(missing=True) class AtlasConfig(Schema): - modeDebug = fields.Boolean(missing=False) - STRUCTURE = fields.String(missing="Nom de la structure") - NOM_APPLICATION = fields.String(missing="Nom de l'application") - URL_APPLICATION = fields.String(missing="") - ID_GOOGLE_ANALYTICS = fields.String(missing="UA-xxxxxxx-xx") - GLOSSAIRE = fields.Boolean(missing=False) - IGNAPIKEY = fields.String(missing="") - AFFICHAGE_INTRODUCTION = fields.Boolean(missing=True) - AFFICHAGE_FOOTER = fields.Boolean(missing=False) - AFFICHAGE_STAT_GLOBALES = fields.Boolean(missing=True) - AFFICHAGE_DERNIERES_OBS = fields.Boolean(missing=True) - AFFICHAGE_EN_CE_MOMENT = fields.Boolean(missing=True) - AFFICHAGE_RANG_STAT = fields.Boolean(missing=True) + class Meta: + unknown = EXCLUDE + + STRUCTURE = fields.String(load_default="Nom de la structure") + NOM_APPLICATION = fields.String(load_default="Nom de l'application") + CUSTOM_LOGO_LINK = fields.String(load_default="") + URL_APPLICATION = fields.String(load_default="") + DEFAULT_LANGUAGE = fields.String(load_default="fr") + MULTILINGUAL = fields.Boolean(load_default=False) + ID_GOOGLE_ANALYTICS = fields.String(load_default="UA-xxxxxxx-xx") + ORGANISM_MODULE = fields.Boolean(load_default="False") + GLOSSAIRE = fields.Boolean(load_default=False) + IGNAPIKEY = fields.String(load_default="") + AFFICHAGE_INTRODUCTION = fields.Boolean(load_default=True) + AFFICHAGE_LOGOS_HOME = fields.Boolean(load_default=True) + AFFICHAGE_FOOTER = fields.Boolean(load_default=True) + AFFICHAGE_STAT_GLOBALES = fields.Boolean(load_default=True) + AFFICHAGE_DERNIERES_OBS = fields.Boolean(load_default=True) + AFFICHAGE_EN_CE_MOMENT = fields.Boolean(load_default=True) + AFFICHAGE_RANG_STAT = fields.Boolean(load_default=True) + AFFICHAGE_NOUVELLES_ESPECES = fields.Boolean(load_default=True) + AFFICHAGE_RECHERCHE_AVANCEE = fields.Boolean(load_default=False) + RANG_STAT = fields.List( fields.Dict, - missing=[ + load_default=[ {"phylum": ["Arthropoda", "Mollusca"]}, {"phylum": ["Chordata"]}, {"regne": ["Plantae"]}, ], ) RANG_STAT_FR = fields.List( - fields.String, missing=["Faune invertébrée", "Faune vertébrée", "Flore"] + fields.String, load_default=["Faune invertébrée", "Faune vertébrée", "Flore"] ) - LIMIT_RANG_TAXONOMIQUE_HIERARCHIE = fields.Integer(missing=13) - LIMIT_FICHE_LISTE_HIERARCHY = fields.Integer(missing=28) - REMOTE_MEDIAS_URL = fields.String(missing="http://mondomaine.fr/taxhub/") - REMOTE_MEDIAS_PATH = fields.String(missing="static/medias/") - REDIMENSIONNEMENT_IMAGE = fields.Boolean(missing=False) - TAXHUB_URL = fields.String(required=False, missing=None) - ATTR_DESC = fields.Integer(missing=100) - ATTR_COMMENTAIRE = fields.Integer(missing=101) - ATTR_MILIEU = fields.Integer(missing=102) - ATTR_CHOROLOGIE = fields.Integer(missing=103) - ATTR_MAIN_PHOTO = fields.Integer(missing=1) - ATTR_OTHER_PHOTO = fields.Integer(missing=2) - ATTR_LIEN = fields.Integer(missing=3) - ATTR_PDF = fields.Integer(missing=4) - ATTR_AUDIO = fields.Integer(missing=5) - ATTR_VIDEO_HEBERGEE = fields.Integer(missing=6) - ATTR_YOUTUBE = fields.Integer(missing=7) - ATTR_DAILYMOTION = fields.Integer(missing=8) - ATTR_VIMEO = fields.Integer(missing=9) - PROTECTION = fields.Boolean(missing=False) - DISPLAY_PATRIMONIALITE = fields.Boolean(missing=False) + LIMIT_RANG_TAXONOMIQUE_HIERARCHIE = fields.Integer(load_default=13) + LIMIT_FICHE_LISTE_HIERARCHY = fields.Integer(load_default=28) + REMOTE_MEDIAS_URL = fields.String(load_default="http://mondomaine.fr/taxhub/") + REMOTE_MEDIAS_PATH = fields.String(load_default="static/medias/") + REDIMENSIONNEMENT_IMAGE = fields.Boolean(load_default=False) + TAXHUB_URL = fields.String(required=False, load_default=None) + ATTR_DESC = fields.Integer(load_default=100) + ATTR_COMMENTAIRE = fields.Integer(load_default=101) + ATTR_MILIEU = fields.Integer(load_default=102) + ATTR_CHOROLOGIE = fields.Integer(load_default=103) + ATTR_MAIN_PHOTO = fields.Integer(load_default=1) + ATTR_OTHER_PHOTO = fields.Integer(load_default=2) + ATTR_LIEN = fields.Integer(load_default=3) + ATTR_PDF = fields.Integer(load_default=4) + ATTR_AUDIO = fields.Integer(load_default=5) + ATTR_VIDEO_HEBERGEE = fields.Integer(load_default=6) + ATTR_YOUTUBE = fields.Integer(load_default=7) + ATTR_DAILYMOTION = fields.Integer(load_default=8) + ATTR_VIMEO = fields.Integer(load_default=9) + PROTECTION = fields.Boolean(load_default=False) + DISPLAY_PATRIMONIALITE = fields.Boolean(load_default=False) PATRIMONIALITE = fields.Dict( - missing={ + load_default={ "label": "Patrimonial", "config": { "oui": { @@ -106,39 +181,35 @@ class AtlasConfig(Schema): } ) STATIC_PAGES = fields.Dict( - missing={ + load_default={ "presentation": { "title": "Présentation de l'atlas", - "picto": "glyphicon-question-sign", + "picto": "fa-question-circle", "order": 0, "template": "static/custom/templates/presentation.html", } } ) - AFFICHAGE_MAILLE = fields.Boolean(missing=False) - ZOOM_LEVEL_POINT = fields.Integer(missing=11) - LIMIT_CLUSTER_POINT = fields.Integer(missing=1000) - NB_DAY_LAST_OBS = fields.String(missing="7 day") - NB_LAST_OBS = fields.Integer(missing=100) + AFFICHAGE_MAILLE = fields.Boolean(load_default=False) + ZOOM_LEVEL_POINT = fields.Integer(load_default=11) + LIMIT_CLUSTER_POINT = fields.Integer(load_default=1000) + NB_DAY_LAST_OBS = fields.String(load_default="7") + NB_LAST_OBS = fields.Integer(load_default=100) TEXT_LAST_OBS = fields.String( - missing="Les observations des agents ces 7 derniers jours |" + load_default="Les observations des agents ces 7 derniers jours |" ) - TYPE_DE_REPRESENTATION_MAILLE = fields.String( - validate=OneOf(["LAST_OBS", "NB_OBS"]) - ) - - MAP = fields.Nested(MapConfig, missing=dict()) - # Specify how communes are ordered - # if true by length else by name - ORDER_COMMUNES_BYLENGTH = fields.Boolean(missing=False) + ANONYMIZE = fields.Boolean(load_default=False) + MAP = fields.Nested(MapConfig, load_default=dict()) # coupe le nom_vernaculaire à la 1ere virgule sur les fiches espèces - SPLIT_NOM_VERN = fields.Integer(missing=True) + SPLIT_NOM_VERN = fields.Integer(load_default=True) + INTERACTIVE_MAP_LIST = fields.Boolean(load_default=True) + AVAILABLE_LANGUAGES = fields.Dict(load_default=LANGUAGES) @validates_schema - def validate_url_taxhub(self, data): + def validate_url_taxhub(self, data, **kwargs): """ - TAXHHUB_URL doit être rempli si REDIMENSIONNEMENT_IMAGE = True + TAXHHUB_URL doit être rempli si REDIMENSIONNEMENT_IMAGE = True """ if data["REDIMENSIONNEMENT_IMAGE"] and data["TAXHUB_URL"] is None: raise ValidationError( @@ -146,4 +217,3 @@ def validate_url_taxhub(self, data): "Le champ TAXHUB_URL doit être rempli si REDIMENSIONNEMENT_IMAGE = True" } ) - diff --git a/atlas/configuration/settings.ini.sample b/atlas/configuration/settings.ini.sample index 56e4b845..32b9747a 100644 --- a/atlas/configuration/settings.ini.sample +++ b/atlas/configuration/settings.ini.sample @@ -27,17 +27,27 @@ owner_atlas=geonatadmin # Password du propriétaire de la BDD owner_atlas_pass=monpassachanger -# GeoNature-atlas est-il connecté à une BDD GeoNature ? +################################################# +##### Configuration de GN-atlas avec un GN ###### +################################################# + +# GeoNature-atlas est-il connecté à une BDD GeoNature ? Si oui, renseignez true geonature_source=true -# Version de GeoNature utilisée 1 ou 2 -geonature_version=2 -# Est-ce que l'atlas utilise une BDD GeoNature distante (en FDW) ou non (local) ? -# true : base de données distante -geonature_fdw=true + +# L'atlas est-il en lien avec le référentiel géographique de GeoNature (ref_geo) ? +# ATTENTION : Doit être égal à true si geonature_source=true, +# ATTENTION : Doit être égal à false si geonature_source=false +use_ref_geo_gn2=true + +# Souhaitez-vous installer le schéma taxonomie de TaxHub dans la BDD de GeoNature-atlas ? +# false si vous souhaitez utiliser celui de GeoNature en FDW +# ATTENTION : Doit être true si geonature_source=false +install_taxonomie=false ################################################ ##### 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 @@ -57,14 +67,10 @@ atlas_source_user=geonatatlas # Pass de l'utilisateur atlas dans la BDD GeoNature source (lecture seule) atlas_source_pass=monpassachanger - ############################# ### Données GEOGRAPHIQUES ### ############################# -# L'atlas est-il en lien avec le référentiel géographique de GeoNature v2 (ref_geo) ? -use_ref_geo_gn2=true - ########### Si ref_geo = true ############ # Voir la colonne type_code de la table ref_geo.bib_areas_type @@ -78,7 +84,7 @@ type_territoire="'PEC'" #### COMMUNES #### # Creer la table des communes à partir d'un shapefile ? -# Si false, modifiez la creation de 'atlas.vm_communes' dans data/atlas.sql +# Si false, modifiez la creation de 'atlas.vm_communes' dans data/atlas/atlas.vm_communes.sql import_commune_shp=true # Chemin et nom des colonnes du SHP des communes du territoire. Laisser tel quel (en modifiant uniquement MYUSERLINUX) @@ -112,9 +118,6 @@ altitudes=(0 500 1000 1500 2000 2500 3000 3500 4000) ### Données TAXONOMIQUES ### ############################ -# Installer le schéma taxonomie de TaxHub dans la BDD de GeoNature-atlas ? (false si geonature_source=true car le schéma taxonomie est installé en FDW) -install_taxonomie=false - # Version de TaxHub à utiliser pour installer le schéma taxonomie # GeoNature-atlas 1.4.0 est compatible avec les versions de Taxhub superieur ou égale à 1.3.2 # Numéro de version conseillée et testée : 1.6.3 @@ -138,11 +141,6 @@ time=15 # Ne modifier que si vous savez ce que vous faites -####################### -### Supervisor settings -####################### - -app_name=atlas ##################### ### Gunicorn settings @@ -151,6 +149,7 @@ app_name=atlas gun_num_workers=4 gun_host=0.0.0.0 gun_port=8080 +gun_timeout=60 #################### ### Python settings diff --git a/atlas/env.py b/atlas/env.py new file mode 100644 index 00000000..91e9b12c --- /dev/null +++ b/atlas/env.py @@ -0,0 +1,9 @@ +from atlas.configuration.config_parser import valid_config_from_dict, read_config_file +from atlas.configuration.config_schema import AtlasConfig, SecretSchemaConf + +from atlas.configuration import config + + +config_dict = read_config_file(config) +config = valid_config_from_dict(config_dict, AtlasConfig) +secret_conf = valid_config_from_dict(config_dict, SecretSchemaConf) \ No newline at end of file diff --git a/atlas/messages.pot b/atlas/messages.pot new file mode 100644 index 00000000..e8a6e205 --- /dev/null +++ b/atlas/messages.pot @@ -0,0 +1,459 @@ +# Translations template for PROJECT. +# Copyright (C) 2021 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# FIRST AUTHOR , 2021. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PROJECT VERSION\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2021-12-02 15:28+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.9.1\n" + +#: static/custom/templates/bandeaulogoshome.html:5 +#: static/custom/templates/bandeaulogoshome.html.sample:5 +msgid "home.partners" +msgstr "" + +#: static/custom/templates/footer.html.sample:2 templates/home/_main.html:3 +msgid "home" +msgstr "" + +#: static/custom/templates/footer.html.sample:5 +#: static/custom/templates/footer.html.sample:24 +msgid "credits" +msgstr "" + +#: static/custom/templates/footer.html.sample:7 +#: static/custom/templates/footer.html.sample:41 +msgid "legal" +msgstr "" + +#: static/custom/templates/footer.html.sample:12 +msgid "atlas.fauna.flora" +msgstr "" + +#: static/custom/templates/footer.html.sample:12 +#: static/custom/templates/introduction.html:7 +#: static/custom/templates/introduction.html.sample:7 +msgid "from1" +msgstr "" + +#: static/custom/templates/footer.html.sample:14 +msgid "powered.by" +msgstr "" + +#: static/custom/templates/footer.html.sample:14 +msgid "developed.by" +msgstr "" + +#: static/custom/templates/footer.html.sample:15 +msgid "ecrins.national.park" +msgstr "" + +#: static/custom/templates/introduction.html:6 +#: static/custom/templates/introduction.html.sample:6 +msgid "welcome.message" +msgstr "" + +#: static/custom/templates/introduction.html:7 +#: static/custom/templates/introduction.html.sample:7 +msgid "from2" +msgstr "" + +#: static/custom/templates/introduction.html:7 +#: static/custom/templates/introduction.html.sample:7 +msgid "from3" +msgstr "" + +#: static/custom/templates/introduction.html:7 +#: static/custom/templates/introduction.html.sample:7 +msgid "from4" +msgstr "" + +#: static/custom/templates/introduction.html:7 +#: static/custom/templates/introduction.html.sample:7 +msgid "from5" +msgstr "" + +#: static/custom/templates/introduction.html:11 +#: static/custom/templates/introduction.html.sample:11 +msgid "home.introduction.message" +msgstr "" + +#: static/custom/templates/presentation.html.sample:4 +msgid "atlas.presentation" +msgstr "" + +#: templates/areaSheet/_main.html:6 templates/areaSheet/_main.html:59 +msgid "municipality.of" +msgstr "" + +#: templates/areaSheet/_main.html:70 +msgid "last.obs.municipality" +msgstr "" + +#: templates/areaSheet/_main.html:73 +msgid "last.obs.zone" +msgstr "" + +#: templates/areaSheet/surrounding_areas.html:10 +msgid "associate.zone" +msgstr "" + +#: templates/areaSheet/surrounding_areas.html:23 +msgid "check.area.sheet" +msgstr "" + +#: templates/core/advanced_search.html:4 +#: templates/core/advanced_search.html:382 templates/core/sideBar.html:20 +msgid "advanced_search" +msgstr "" + +#: templates/core/advanced_search.html:350 +msgid "information" +msgstr "" + +#: templates/core/advanced_search.html:351 +#: templates/core/advanced_search.html:361 +msgid "close" +msgstr "" + +#: templates/core/advanced_search.html:357 +msgid "asearch.information" +msgstr "" + +#: templates/core/advanced_search.html:373 +msgid "page.information" +msgstr "" + +#: templates/core/advanced_search.html:385 +#: templates/core/advanced_search.html:408 +msgid "asearch.max" +msgstr "" + +#: templates/core/advanced_search.html:392 +msgid "asearch.search.species" +msgstr "" + +#: templates/core/advanced_search.html:395 +msgid "asearch.search.start" +msgstr "" + +#: templates/core/advanced_search.html:419 +msgid "asearch.remove.selection" +msgstr "" + +#: templates/core/advanced_search.html:427 templates/core/listTaxons.html:88 +#: templates/home/lastObs.html:44 templates/home/mostViewNow.html:33 +#: templates/home/newSpecies.html:45 templates/home/taxoRank.html:57 +#: templates/organismSheet/topSpecies.html:67 +msgid "species.sheet" +msgstr "" + +#: templates/core/advanced_search.html:429 templates/core/listTaxons.html:87 +#: templates/core/tabTaxons.html:85 templates/organismSheet/topSpecies.html:66 +#: templates/speciesSheet/identityCard.html:173 +msgid "check.species.sheet" +msgstr "" + +#: templates/core/extended_areas_search.html:13 +msgid "search.other.zones.type" +msgstr "" + +#: templates/core/listTaxons.html:14 +msgid "filter.species" +msgstr "" + +#: templates/core/listTaxons.html:23 +msgid "display.municipality.obs" +msgstr "" + +#: templates/core/listTaxons.html:81 templates/core/statHierarchy.html:7 +#: templates/home/globalStats.html:12 +#: templates/organismSheet/topSpecies.html:61 +#: templates/speciesSheet/map.html:15 +msgid "observation" +msgstr "" + +#: templates/core/listTaxons.html:82 templates/core/statHierarchy.html:7 +#: templates/core/tabTaxons.html:19 templates/home/globalStats.html:12 +#: templates/organismSheet/statsInfos.html:11 +#: templates/organismSheet/topSpecies.html:61 +#: templates/speciesSheet/identityCard.html:131 +#: templates/speciesSheet/map.html:15 +#: templates/speciesSheet/otherInformations.html:137 +msgid "observations" +msgstr "" + +#: templates/core/listTaxons.html:83 +msgid "last.obs.in" +msgstr "" + +#: templates/core/loaderSpinner.html:3 +msgid "loading" +msgstr "" + +#: templates/core/navbar.html:34 templates/home/globalStats.html:28 +#: templates/photoGalery/_main.html:76 +msgid "search.species" +msgstr "" + +#: templates/core/navbar.html:47 templates/home/globalStats.html:47 +msgid "search.city" +msgstr "" + +#: templates/core/sideBar.html:3 +msgid "back.to.home" +msgstr "" + +#: templates/core/sideBar.html:25 templates/home/globalStats.html:59 +#: templates/photoGalery/_main.html:5 templates/photoGalery/_main.html:50 +msgid "gallery.title" +msgstr "" + +#: templates/core/statHierarchy.html:12 templates/home/globalStats.html:21 +#: templates/home/taxoRank.html:28 templates/organismSheet/statsInfos.html:21 +msgid "species" +msgstr "" + +#: templates/core/statHierarchy.html:17 templates/speciesSheet/map.html:25 +#: templates/speciesSheet/otherInformations.html:29 +msgid "observers" +msgstr "" + +#: templates/core/statHierarchy.html:17 templates/speciesSheet/map.html:25 +#: templates/speciesSheet/otherInformations.html:29 +msgid "observer" +msgstr "" + +#: templates/core/tabTaxons.html:7 +msgid "group" +msgstr "" + +#: templates/core/tabTaxons.html:8 templates/speciesSheet/identityCard.html:124 +msgid "scientific.name" +msgstr "" + +#: templates/core/tabTaxons.html:9 templates/speciesSheet/identityCard.html:123 +msgid "common.name" +msgstr "" + +#: templates/core/tabTaxons.html:16 +msgid "obs.number.s" +msgstr "" + +#: templates/core/tabTaxons.html:17 templates/speciesSheet/map.html:33 +msgid "last.obs" +msgstr "" + +#: templates/core/tabTaxons.html:21 +#: templates/speciesSheet/identityCard.html:132 +msgid "sheet" +msgstr "" + +#: templates/core/tabTaxons.html:60 templates/speciesSheet/identityCard.html:62 +#: templates/speciesSheet/identityCard.html:154 +msgid "this.taxon.has.a.protected.status" +msgstr "" + +#: templates/core/tabTaxons.html:80 +msgid "display.city.infos" +msgstr "" + +#: templates/home/globalStats.html:4 +msgid "home.insomefigures" +msgstr "" + +#: templates/home/globalStats.html:13 +msgid "home.seelatestobs" +msgstr "" + +#: templates/home/globalStats.html:39 templates/speciesSheet/map.html:20 +#: templates/speciesSheet/otherInformations.html:10 +#: templates/speciesSheet/otherInformations.html:14 +msgid "municipalities" +msgstr "" + +#: templates/home/globalStats.html:39 templates/speciesSheet/map.html:20 +#: templates/speciesSheet/otherInformations.html:10 +#: templates/speciesSheet/otherInformations.html:14 +msgid "municipality" +msgstr "" + +#: templates/home/globalStats.html:58 +msgid "photos" +msgstr "" + +#: templates/home/globalStats.html:58 +msgid "photo" +msgstr "" + +#: templates/home/mostViewNow.html:5 +msgid "see.at.the.moment" +msgstr "" + +#: templates/home/mostViewNow.html:7 +msgid "species.most.obs.last.15.days" +msgstr "" + +#: templates/home/newSpecies.html:10 +msgid "new.species.observed" +msgstr "" + +#: templates/home/taxoRank.html:8 +msgid "species.to.discover" +msgstr "" + +#: templates/organismSheet/blocInfos.html:4 +msgid "other.informations" +msgstr "" + +#: templates/organismSheet/groupChart.html:3 +msgid "part.graph" +msgstr "" + +#: templates/organismSheet/identityCard.html:21 +msgid "Adresse" +msgstr "" + +#: templates/organismSheet/identityCard.html:22 +msgid "Téléphone" +msgstr "" + +#: templates/organismSheet/mapObs.html:5 +msgid "map.observations" +msgstr "" + +#: templates/organismSheet/statsInfos.html:4 +msgid "organism.stats" +msgstr "" + +#: templates/organismSheet/statsInfos.html:16 +msgid "atlas.participation" +msgstr "" + +#: templates/organismSheet/topSpecies.html:5 +msgid "top.species" +msgstr "" + +#: templates/organismSheet/topSpecies.html:62 +msgid "from.organism.observations" +msgstr "" + +#: templates/photoGalery/_main.html:64 templates/photoGalery/_main.html:65 +msgid "all.groups" +msgstr "" + +#: templates/photoGalery/_main.html:70 +msgid "order.photos" +msgstr "" + +#: templates/speciesSheet/audioVideo.html:7 +msgid "Video" +msgstr "" + +#: templates/speciesSheet/blocInfos.html:11 +msgid "species.infos" +msgstr "" + +#: templates/speciesSheet/blocInfos.html:14 +#: templates/speciesSheet/descriptionMedia.html:16 +#: templates/speciesSheet/otherInformations.html:69 +msgid "description" +msgstr "" + +#: templates/speciesSheet/blocInfos.html:17 +msgid "read.more" +msgstr "" + +#: templates/speciesSheet/blocInfos.html:19 +msgid "environment" +msgstr "" + +#: templates/speciesSheet/blocInfos.html:20 +msgid "repartition" +msgstr "" + +#: templates/speciesSheet/blocInfos.html:21 +msgid "synonyms" +msgstr "" + +#: templates/speciesSheet/blocInfos.html:27 +#: templates/speciesSheet/blocInfos.html:39 +#: templates/speciesSheet/blocInfos.html:46 +msgid "not.resigned.for.the.moment" +msgstr "" + +#: templates/speciesSheet/blocInfos.html:53 +msgid "no.synonym.for.this.taxon" +msgstr "" + +#: templates/speciesSheet/charts.html:3 +msgid "alt.classes.obs" +msgstr "" + +#: templates/speciesSheet/charts.html:7 +msgid "monthly.obs" +msgstr "" + +#: templates/speciesSheet/descriptionMedia.html:12 +#: templates/speciesSheet/otherInformations.html:42 +msgid "author" +msgstr "" + +#: templates/speciesSheet/identityCard.html:95 +msgid "check.species.sheet.inpn" +msgstr "" + +#: templates/speciesSheet/identityCard.html:126 +msgid "protection" +msgstr "" + +#: templates/speciesSheet/map.html:29 +msgid "first.obs" +msgstr "" + +#: templates/speciesSheet/otherInformations.html:22 +msgid "organisms" +msgstr "" + +#: templates/speciesSheet/otherInformations.html:22 +msgid "organism" +msgstr "" + +#: templates/speciesSheet/otherInformations.html:41 +msgid "title" +msgstr "" + +#: templates/speciesSheet/otherInformations.html:71 +msgid "date" +msgstr "" + +#: templates/speciesSheet/otherInformations.html:137 +msgid "organism.participation" +msgstr "" + +#: templates/speciesSheet/otherInformations.html:138 +msgid "organism.prospection" +msgstr "" + +#: templates/speciesSheet/otherInformations.html:144 +msgid "check.organism.sheet" +msgstr "" + +#: templates/speciesSheet/otherInformations.html:145 +msgid "organism.sheet" +msgstr "" + +#: templates/taxoRankSheet/_main.html:47 +msgid "species.obs.for.tax" +msgstr "" + diff --git a/atlas/modeles/__init__.py b/atlas/modeles/__init__.py index 141f740d..d3f5a12f 100644 --- a/atlas/modeles/__init__.py +++ b/atlas/modeles/__init__.py @@ -1,2 +1 @@ -from . import entities -from . import repositories \ No newline at end of file + diff --git a/atlas/modeles/entities/synthese.py b/atlas/modeles/entities/synthese.py index f359880a..db8200f7 100644 --- a/atlas/modeles/entities/synthese.py +++ b/atlas/modeles/entities/synthese.py @@ -1,5 +1,4 @@ # coding: utf-8 from sqlalchemy import MetaData - metadata = MetaData() diff --git a/atlas/modeles/entities/tBibTaxrefRang.py b/atlas/modeles/entities/tBibTaxrefRang.py index 623dd51e..b2bfec7f 100644 --- a/atlas/modeles/entities/tBibTaxrefRang.py +++ b/atlas/modeles/entities/tBibTaxrefRang.py @@ -1,19 +1,16 @@ # coding: utf-8 -from sqlalchemy import BigInteger, Boolean, Column, ForeignKey, Integer, String, Table, Text -from geoalchemy2 import Geometry -from sqlalchemy.orm import relationship +from sqlalchemy import Column, Integer, String, Table from sqlalchemy.ext.declarative import declarative_base -from ...utils import engine - Base = declarative_base() metadata = Base.metadata + class TBibTaxrefRang(Base): __table__ = Table( - 'bib_taxref_rangs', metadata, - Column('id_rang', String(4), nullable=False, primary_key=True), - Column('nom_rang', String(20), nullable=False), - Column('tri_rang', Integer), - schema='atlas' -) + 'bib_taxref_rangs', metadata, + Column('id_rang', String(4), nullable=False, primary_key=True), + Column('nom_rang', String(20), nullable=False), + Column('tri_rang', Integer), + schema='atlas' + ) diff --git a/atlas/modeles/entities/tCommunes.py b/atlas/modeles/entities/tCommunes.py index 03b2e1a2..8e528695 100644 --- a/atlas/modeles/entities/tCommunes.py +++ b/atlas/modeles/entities/tCommunes.py @@ -1,11 +1,8 @@ # coding: utf-8 -from sqlalchemy import BigInteger, Boolean, Column, ForeignKey, Integer, String from geoalchemy2 import Geometry -from sqlalchemy.orm import relationship +from sqlalchemy import Column, String from sqlalchemy.ext.declarative import declarative_base - - Base = declarative_base() metadata = Base.metadata @@ -17,4 +14,4 @@ class LCommune(Base): insee = Column(String(5), primary_key=True) commune_maj = Column(String(50)) commune_min = Column(String(50)) - the_geom = Column(Geometry) \ No newline at end of file + the_geom = Column(Geometry) diff --git a/atlas/modeles/entities/tGrid.py b/atlas/modeles/entities/tGrid.py new file mode 100644 index 00000000..fc362b0a --- /dev/null +++ b/atlas/modeles/entities/tGrid.py @@ -0,0 +1,22 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +from geoalchemy2.types import Geometry +from sqlalchemy import ( + Column, + Integer, + Text, +) +from sqlalchemy.ext.declarative import declarative_base + +Base = declarative_base() +metadata = Base.metadata + + +class TGrid(Base): + __tablename__ = "t_mailles_territoire" + __table_args__ = {"schema": "atlas"} + + id_maille = Column(Integer, primary_key=True) + the_geom = Column(Geometry(geometry_type="MULTIPOLYGON", srid=4326)) + geosjon_maille = Column(Text) diff --git a/atlas/modeles/entities/vmAreas.py b/atlas/modeles/entities/vmAreas.py new file mode 100644 index 00000000..765b3c9e --- /dev/null +++ b/atlas/modeles/entities/vmAreas.py @@ -0,0 +1,62 @@ +# coding: utf-8 +from geoalchemy2.types import Geometry +from sqlalchemy import Column, MetaData, String, Table, Integer, Text, ForeignKey +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import relationship + +from atlas.utils import engine + +metadata = MetaData() +Base = declarative_base() + + +class VmBibAreasTypes(Base): + __table__ = Table( + "vm_bib_areas_types", + metadata, + Column("id_type", Integer(), primary_key=True, unique=True), + Column("type_code", String(50)), + Column("type_name", String(250)), + Column("type_desc", Text()), + schema="atlas", + autoload=True, + autoload_with=engine, + extend_existing=True, + ) + areas = relationship("VmAreas") + + +class VmAreas(Base): + __table__ = Table( + "vm_l_areas", + metadata, + Column("id_area", Integer(), primary_key=True, unique=True), + Column("area_code", String(50)), + Column("area_name", String(50)), + Column("id_type", Integer(), ForeignKey("atlas.vm_bib_areas_types.id_type")), + Column("the_geom", Geometry(u"MULTIPOLYGON", 4326), index=True), + Column("area_geojson", Text()), + schema="atlas", + autoload=True, + autoload_with=engine, + extend_existing=True, + ) + + +class VmCorAreaObservation(Base): + __table__ = Table( + "vm_cor_area_observation", + metadata, + Column("id_observation", Integer()), + Column("id_area", Integer()), + schema="atlas", + autoload=True, + autoload_with=engine, + extend_existing=True, + primary_key=False, + ) + __mapper_args__ = {"primary_key": [__table__.c.id_observation, __table__.c.id_area]} + observation = relationship( + "VmObservations", foreign_keys=[__table__.c.id_observation] + ) + area = relationship("VmAreas", foreign_keys=[__table__.c.id_area]) diff --git a/atlas/modeles/entities/vmCommunes.py b/atlas/modeles/entities/vmCommunes.py index 8d2f54e7..43a32b0e 100644 --- a/atlas/modeles/entities/vmCommunes.py +++ b/atlas/modeles/entities/vmCommunes.py @@ -1,20 +1,20 @@ # coding: utf-8 -from sqlalchemy import Boolean, Column, Date, DateTime, Integer, MetaData, String, Table, Text from geoalchemy2.types import Geometry -from sqlalchemy.sql.sqltypes import NullType -from sqlalchemy.orm import mapper +from sqlalchemy import Column, MetaData, String, Table from sqlalchemy.ext.declarative import declarative_base -from ...utils import engine + +from atlas.utils import engine metadata = MetaData() Base = declarative_base() + class VmCommunes(Base): __table__ = Table( - 'vm_communes', metadata, - Column('insee', String(5),primary_key=True, unique=True), - Column('commune_maj', String(50)), - Column('commune_min', String(50)), - Column('the_geom', Geometry(u'MULTIPOLYGON', 2154), index=True), - schema='atlas', autoload=True, autoload_with=engine -) \ No newline at end of file + 'vm_communes', metadata, + Column('insee', String(5), primary_key=True, unique=True), + Column('commune_maj', String(50)), + # Column('commune_min', String(50)), + Column('the_geom', Geometry(u'MULTIPOLYGON', 2154), index=True), + schema='atlas', autoload=True, autoload_with=engine + ) diff --git a/atlas/modeles/entities/vmMedias.py b/atlas/modeles/entities/vmMedias.py new file mode 100644 index 00000000..e2cb44b7 --- /dev/null +++ b/atlas/modeles/entities/vmMedias.py @@ -0,0 +1,29 @@ +# coding: utf-8 +from sqlalchemy import Column, MetaData, String, Table, Integer, ForeignKey, Text, Date +from sqlalchemy.ext.declarative import declarative_base + +from atlas.utils import engine + +metadata = MetaData() +Base = declarative_base() + + +class VmMedias(Base): + __table__ = Table( + "vm_medias", + metadata, + Column("id_media", Integer(), primary_key=True, unique=True), + Column("cd_ref", Integer()), + Column("titre", String(255)), + Column("url", String(255)), + Column("chemin", String(255)), + Column("auteur", String(1000)), + Column("desc_media", Text()), + Column("date_media", Date()), + Column("id_type", Integer()), + Column("licence", String(100)), + Column("source", String(25)), + schema="atlas", + autoload=True, + autoload_with=engine, + ) diff --git a/atlas/modeles/entities/vmMois.py b/atlas/modeles/entities/vmMois.py index 59dabeb9..7a10008e 100644 --- a/atlas/modeles/entities/vmMois.py +++ b/atlas/modeles/entities/vmMois.py @@ -1,31 +1,28 @@ # coding: utf-8 -from sqlalchemy import BigInteger, Column, Date, DateTime, Integer, MetaData, String, Table, Text -from geoalchemy2.types import Geometry -from sqlalchemy.sql.sqltypes import NullType -from sqlalchemy.orm import mapper +from sqlalchemy import Column, Integer, MetaData, Table from sqlalchemy.ext.declarative import declarative_base -from ...utils import engine + +from atlas.utils import engine metadata = MetaData() Base = declarative_base() + class VmMois(Base): __table__ = Table( - 'vm_mois', metadata, - Column('cd_ref', Integer, primary_key=True, unique=True), - Column('_01', Integer), - Column('_02', Integer), - Column('_03', Integer), - Column('_04', Integer), - Column('_05', Integer), - Column('_06', Integer), - Column('_07', Integer), - Column('_08', Integer), - Column('_09', Integer), - Column('_10', Integer), - Column('_11', Integer), - Column('_12', Integer), - schema='atlas', autoload=True, autoload_with=engine -) - - + 'vm_mois', metadata, + Column('cd_ref', Integer, primary_key=True, unique=True), + Column('_01', Integer), + Column('_02', Integer), + Column('_03', Integer), + Column('_04', Integer), + Column('_05', Integer), + Column('_06', Integer), + Column('_07', Integer), + Column('_08', Integer), + Column('_09', Integer), + Column('_10', Integer), + Column('_11', Integer), + Column('_12', Integer), + schema='atlas', autoload=True, autoload_with=engine + ) diff --git a/atlas/modeles/entities/vmObservations.py b/atlas/modeles/entities/vmObservations.py index e84f6322..c15b1bcf 100644 --- a/atlas/modeles/entities/vmObservations.py +++ b/atlas/modeles/entities/vmObservations.py @@ -1,21 +1,17 @@ # coding: utf-8 +from geoalchemy2.types import Geometry from sqlalchemy import ( - Boolean, Column, Date, - DateTime, Integer, MetaData, String, Table, Text, ) -from geoalchemy2.types import Geometry -from sqlalchemy.sql.sqltypes import NullType -from sqlalchemy.orm import mapper from sqlalchemy.ext.declarative import declarative_base -from ...utils import engine +from atlas.utils import engine metadata = MetaData() Base = declarative_base() @@ -31,7 +27,9 @@ class VmObservations(Base): Column("observateurs", String(255)), Column("altitude_retenue", Integer, index=True), Column("cd_ref", Integer, index=True), + Column("the_geom_point", Geometry(geometry_type="POINT", srid=4326)), Column("geojson_point", Text), + Column("diffusion_level"), schema="atlas", autoload=True, autoload_with=engine, @@ -49,10 +47,9 @@ class VmObservationsMailles(Base): Column("id_observation", Integer, primary_key=True, unique=True), Column("id_maille", Integer), Column("the_geom", Geometry), - Column("geojson_maille", String(1000)), + Column("geojson_maille", Text), Column("annee", String(1000)), schema="atlas", autoload=True, autoload_with=engine, ) - diff --git a/atlas/modeles/entities/vmOrganisms.py b/atlas/modeles/entities/vmOrganisms.py new file mode 100644 index 00000000..c767b900 --- /dev/null +++ b/atlas/modeles/entities/vmOrganisms.py @@ -0,0 +1,29 @@ +# -*- coding:utf-8 -*- + +from sqlalchemy import Column, Integer, MetaData, String, Table, Float +from sqlalchemy.ext.declarative import declarative_base + +from atlas.utils import engine + +Base = declarative_base() +metadata = MetaData() + +class VmOrganisms(Base): + __table__=Table( + 'vm_cor_taxon_organism', + metadata, + Column('nb_observations', Integer), + Column('id_organism', Integer, primary_key=True, unique =True), + Column ('nom_organism',String(500)), + Column ('adresse_organism', String (128)), + Column ('cp_organism', String(5)), + Column ('ville_organism', String(100)), + Column ('tel_organism',String(14)), + Column ('email_organism', String(100)), + Column ('url_organism', String(255)), + Column ('url_logo', String(255)), + Column('cd_ref',Integer), + schema="atlas", + autoload=True, + autoload_with=engine + ) \ No newline at end of file diff --git a/atlas/modeles/entities/vmSearchTaxon.py b/atlas/modeles/entities/vmSearchTaxon.py index 9e6adba5..931059a5 100644 --- a/atlas/modeles/entities/vmSearchTaxon.py +++ b/atlas/modeles/entities/vmSearchTaxon.py @@ -7,8 +7,8 @@ Table ) from sqlalchemy.ext.declarative import declarative_base -from ...utils import engine +from atlas.utils import engine metadata = MetaData() Base = declarative_base() @@ -25,4 +25,3 @@ class VmSearchTaxon(Base): autoload=True, autoload_with=engine, ) - diff --git a/atlas/modeles/entities/vmTaxons.py b/atlas/modeles/entities/vmTaxons.py index f6e4a091..fe372d82 100644 --- a/atlas/modeles/entities/vmTaxons.py +++ b/atlas/modeles/entities/vmTaxons.py @@ -1,41 +1,39 @@ - - # -*- coding:utf-8 -*- from sqlalchemy import Column, Integer, MetaData, String, Table, Float -from sqlalchemy.orm import mapper from sqlalchemy.ext.declarative import declarative_base -from ...utils import engine +from atlas.utils import engine Base = declarative_base() metadata = MetaData() + class VmTaxons(Base): __table__ = Table( - 'vm_taxons', metadata, - Column('cd_ref', Integer, primary_key=True, unique=True), - Column('regne', String(20)), - Column('phylum', String(50)), - Column('classe', String(50)), - Column('ordre', String(50)), - Column('famille', String(50)), - Column('cd_taxsup', Integer), - Column('lb_nom', String(100)), - Column('lb_auteur', String(250)), - Column('nom_complet', String(255)), - Column('nom_valide', String(255)), - Column('nom_vern', String(1000)), - Column('nom_vern_eng', String(500)), - Column('group1_inpn', String(50)), - Column('group2_inpn', String(50)), - Column('nom_complet_html', String(500)), - Column('nom_habitat', String(50)), - Column('nom_rang', String(20)), - Column('nom_statut', String(50)), - Column('patrimonial', String(255)), - Column('protection_stricte', String(255)), - Column('yearmin', Float(53)), - Column('yearmax', Float(53)), - schema='atlas', autoload=True, autoload_with=engine -) \ No newline at end of file + 'vm_taxons', metadata, + Column('cd_ref', Integer, primary_key=True, unique=True), + Column('regne', String(20)), + Column('phylum', String(50)), + Column('classe', String(50)), + Column('ordre', String(50)), + Column('famille', String(50)), + Column('cd_taxsup', Integer), + Column('lb_nom', String(100)), + Column('lb_auteur', String(250)), + Column('nom_complet', String(255)), + Column('nom_valide', String(255)), + Column('nom_vern', String(1000)), + Column('nom_vern_eng', String(500)), + Column('group1_inpn', String(50)), + Column('group2_inpn', String(50)), + Column('nom_complet_html', String(500)), + # Column('nom_habitat', String(50)), + # Column('nom_rang', String(20)), + # Column('nom_statut', String(50)), + Column('patrimonial', String(255)), + Column('protection_stricte', String(255)), + Column('yearmin', Float(53)), + Column('yearmax', Float(53)), + schema='atlas', autoload=True, autoload_with=engine + ) diff --git a/atlas/modeles/entities/vmTaxref.py b/atlas/modeles/entities/vmTaxref.py index 2b9e7697..9721db31 100644 --- a/atlas/modeles/entities/vmTaxref.py +++ b/atlas/modeles/entities/vmTaxref.py @@ -1,35 +1,35 @@ # coding: utf-8 from sqlalchemy import Column, Integer, MetaData, String, Table -from sqlalchemy.orm import mapper from sqlalchemy.ext.declarative import declarative_base -from ...utils import engine +from atlas.utils import engine metadata = MetaData() Base = declarative_base() + class VmTaxref(Base): __table__ = Table( - 'vm_taxref', metadata, - Column('cd_nom', Integer, unique=True, primary_key=True), - Column('id_statut', String(1)), - Column('id_habitat', Integer), - Column('id_rang', String(4)), - Column('regne', String(20)), - Column('phylum', String(50)), - Column('classe', String(50)), - Column('ordre', String(50)), - Column('famille', String(50)), - Column('cd_taxsup', Integer), - Column('cd_ref', Integer, index=True), - Column('lb_nom', String(100), index=True), - Column('lb_auteur', String(250)), - Column('nom_complet', String(255), index=True), - Column('nom_valide', String(255), index=True), - Column('nom_vern', String(1000)), - Column('nom_vern_eng', String(500)), - Column('group1_inpn', String(50)), - Column('group2_inpn', String(50)), - Column('nom_complet_html', String(500)), - schema='atlas', autoload=True, autoload_with=engine -) + 'vm_taxref', metadata, + Column('cd_nom', Integer, unique=True, primary_key=True), + Column('id_statut', String(1)), + Column('id_habitat', Integer), + Column('id_rang', String(4)), + Column('regne', String(20)), + Column('phylum', String(50)), + Column('classe', String(50)), + Column('ordre', String(50)), + Column('famille', String(50)), + Column('cd_taxsup', Integer), + Column('cd_ref', Integer, index=True), + Column('lb_nom', String(100), index=True), + Column('lb_auteur', String(250)), + Column('nom_complet', String(255), index=True), + Column('nom_valide', String(255), index=True), + Column('nom_vern', String(1000)), + Column('nom_vern_eng', String(500)), + Column('group1_inpn', String(50)), + Column('group2_inpn', String(50)), + Column('nom_complet_html', String(500)), + schema='atlas', autoload=True, autoload_with=engine + ) diff --git a/atlas/modeles/repositories/tCommunesRepository.py b/atlas/modeles/repositories/tCommunesRepository.py index 8115d6dc..65102aad 100644 --- a/atlas/modeles/repositories/tCommunesRepository.py +++ b/atlas/modeles/repositories/tCommunesRepository.py @@ -1,36 +1,16 @@ - # -*- coding:utf-8 -*- import ast -from sqlalchemy.sql import text - -def getCommuneFromInsee(connection, insee): - sql = """ - SELECT l.commune_maj, l.insee, - st_asgeojson(st_transform(l.the_geom, 4326)) as commune_geojson - FROM layers.l_communes l - WHERE l.insee = :thisInsee - """ - req = connection.execute(text(sql), thisInsee=insee) - communeObj = dict() - for r in req: - communeObj = { - 'communeName': r.commune_maj, - 'insee': r.insee, - 'communeGeoJson': ast.literal_eval(r.commune_geojson) - } - return communeObj - - # return req[0].commune_maj # A supprimer +from sqlalchemy.sql import text def getCommunesObservationsChilds(connection, cd_ref): sql = """ - SELECT distinct(com.insee) as insee, com.commune_maj + SELECT DISTINCT(com.insee) AS insee, com.commune_maj FROM layers.l_communes com JOIN atlas.vm_observations obs ON obs.insee = com.insee - WHERE obs.cd_ref in ( - SELECT * from atlas.find_all_taxons_childs(:thiscdref) + WHERE obs.cd_ref IN ( + SELECT * FROM atlas.find_all_taxons_childs(:thiscdref) ) OR obs.cd_ref = :thiscdref GROUP BY com.commune_maj, com.insee """.encode('UTF-8') diff --git a/atlas/modeles/repositories/vmAltitudesRepository.py b/atlas/modeles/repositories/vmAltitudesRepository.py index d4f5e139..12c34273 100644 --- a/atlas/modeles/repositories/vmAltitudesRepository.py +++ b/atlas/modeles/repositories/vmAltitudesRepository.py @@ -1,4 +1,3 @@ - # -*- coding:utf-8 -*- from sqlalchemy.sql import text diff --git a/atlas/modeles/repositories/vmAreasRepository.py b/atlas/modeles/repositories/vmAreasRepository.py new file mode 100644 index 00000000..ccef9bb4 --- /dev/null +++ b/atlas/modeles/repositories/vmAreasRepository.py @@ -0,0 +1,336 @@ +# -*- coding:utf-8 -*- + +import ast +import json +from datetime import datetime + +from flask import current_app +from sqlalchemy import or_, and_, case +from sqlalchemy.sql.expression import func + +from atlas.modeles import utils +from atlas.modeles.entities.tGrid import TGrid +from atlas.modeles.entities.vmAreas import ( + VmAreas, + VmCorAreaObservation, + VmBibAreasTypes, +) +from atlas.modeles.entities.vmMedias import VmMedias +from atlas.modeles.entities.vmObservations import VmObservations +from atlas.modeles.entities.vmTaxons import VmTaxons +from atlas.modeles.entities.vmTaxref import VmTaxref + + +def area_types(session): + query = session.query( + VmBibAreasTypes.id_type, + VmBibAreasTypes.type_code, + VmBibAreasTypes.type_name, + VmBibAreasTypes.type_desc, + ) + return query.all() + + +def get_id_area(session, type_code, area_code): + try: + query = ( + session.query(VmAreas.id_area) + .join(VmBibAreasTypes, VmBibAreasTypes.id_type == VmAreas.id_type) + .filter( + and_( + VmAreas.area_code.ilike(area_code), + VmBibAreasTypes.type_code.ilike(type_code), + ) + ) + ) + current_app.logger.debug(" query: {}".format(query)) + result = query.one() + return result.id_area + except Exception as e: + current_app.logger.error(" error {}".format(e)) + + +def last_observations_area_maille(session, myLimit, idArea): + q_last_obs = ( + session.query( + # VmObservations.cd_ref.label("cd_ref"), + # VmObservations.dateobs.label("dateobs"), + # VmTaxons.lb_nom.label("lb_nom"), + # VmTaxons.nom_vern.label("nom_vern"), + # VmObservations.the_geom_point.label("the_geom_point"), + VmObservations.cd_ref, + VmObservations.dateobs, + VmTaxons.lb_nom, + VmTaxons.nom_vern, + VmObservations.the_geom_point, + ) + .join( + VmCorAreaObservation, + VmObservations.id_observation == VmCorAreaObservation.id_observation, + ) + .join(VmAreas, VmAreas.id_area == VmCorAreaObservation.id_area) + .join(VmTaxons, VmTaxons.cd_ref == VmObservations.cd_ref) + .filter(VmAreas.id_area == idArea) + .order_by(VmObservations.dateobs.desc()) + .limit(myLimit) + .subquery() + ) + current_app.logger.debug( + " subquery q_last_obs: {}".format(q_last_obs) + ) + + q_mailles_obs = ( + session.query( + TGrid.id_maille, + q_last_obs.c.lb_nom, + q_last_obs.c.cd_ref, + q_last_obs.c.nom_vern, + func.st_asgeojson(TGrid.the_geom).label( + "geojson_maille" + ), + ) + .join(q_last_obs, q_last_obs.c.the_geom_point.st_intersects(TGrid.the_geom)) + .group_by( + q_last_obs.c.lb_nom, + q_last_obs.c.cd_ref, + q_last_obs.c.nom_vern, + TGrid.id_maille, + TGrid.the_geom, + ) + ) + + current_app.logger.debug( + " query q_mailles_obs: {}".format(q_mailles_obs) + ) + current_app.logger.debug( + " start query: {}".format(datetime.now()) + ) + result = q_mailles_obs.all() + current_app.logger.debug( + " start loop: {}".format(datetime.now()) + ) + obsList = list() + for o in result: + if o.nom_vern: + taxon = o.nom_vern + " | " + o.lb_nom + else: + taxon = o.lb_nom + temp = { + "cd_ref": o.cd_ref, + "taxon": taxon, + "geojson_maille": json.loads(o.geojson_maille), + "id_maille": o.id_maille, + } + obsList.append(temp) + current_app.logger.debug( + " end loop: {}".format(datetime.now()) + ) + return obsList + + +def get_observers_area(session, idArea): + q_list_observers = ( + session.query( + func.trim( + func.unnest(func.string_to_array(VmObservations.observateurs, ",")) + ).label("observateurs") + ) + .join( + VmCorAreaObservation, + VmObservations.id_observation == VmCorAreaObservation.id_observation, + ) + .filter(VmCorAreaObservation.id_area == idArea) + ).subquery() + + query = session.query(q_list_observers.c.observateurs).group_by( + q_list_observers.c.observateurs + ) + return query.all() + + +def search_area_by_type(session, search, type_code, limit=50): + query = ( + session.query( + VmAreas.area_code, + func.concat(VmAreas.area_name, " - [code ", VmAreas.area_code, "]"), + ) + .join(VmBibAreasTypes, VmBibAreasTypes.id_type == VmAreas.id_type) + .filter( + and_(VmBibAreasTypes.type_code == type_code), + ( + or_( + VmAreas.area_name.ilike("%" + search + "%"), + VmAreas.area_code.ilike("%" + search + "%"), + ) + ), + ) + ) + print(limit) + query = query.limit(limit) + current_app.logger.debug(" query {}".format(query)) + + areaList = list() + for r in query.all(): + temp = {"label": r[1], "value": r[0]} + areaList.append(temp) + return areaList + + +def get_areas_observations(session, id_area): + query = ( + session.query( + VmObservations.id_observation, + VmTaxref.nom_vern, + VmTaxref.lb_nom, + VmTaxref.group2_inpn, + VmObservations.dateobs, + VmObservations.observateurs, + func.st_asgeojson(VmObservations.the_geom_point).label("geometry"), + ) + .join(VmTaxref, VmTaxref.cd_nom == VmObservations.cd_ref) + .join( + VmCorAreaObservation, + VmObservations.id_observation == VmCorAreaObservation.id_observation, + ) + .filter(VmCorAreaObservation.id_area == id_area) + ).all() + result = [] + for r in query: + temp = r._asdict() + temp["geometry"] = json.loads(r.geometry or "{}") + temp["dateobs"] = str(r.dateobs) + temp["group2_inpn"] = utils.deleteAccent(r.group2_inpn) + result.append(temp) + return result + + +def get_areas_observations_by_cdnom(session, id_area): + req = ( + session.query( + VmObservations.id_observation, + VmTaxref.nom_vern, + VmTaxref.lb_nom, + VmTaxref.group2_inpn, + VmObservations.dateobs, + VmObservations.observateurs, + func.st_asgeojson(VmObservations.the_geom_point).label("geometry"), + ) + .join(VmTaxref, VmTaxref.cd_nom == VmObservations.cd_ref) + .join( + VmCorAreaObservation, + VmObservations.id_observation == VmCorAreaObservation.id_observation, + ) + .filter(VmCorAreaObservation.id_area == id_area) + ).all() + result = [] + for r in req: + temp = r._asdict() + temp["geometry"] = json.loads(r.geometry or "{}") + temp["dateobs"] = str(r.dateobs) + temp["group2_inpn"] = utils.deleteAccent(r.group2_inpn) + result.append(temp) + return result + + +def get_areas_grid_observations_by_cdnom(session, id_area, cd_nom): + query = ( + session.query( + TGrid.id_maille, + func.extract("year", VmObservations.dateobs).label("annee"), + func.st_asgeojson(TGrid.the_geom, 4326).label( + "geojson_maille" + ), + ) + .join(VmAreas, VmAreas.the_geom.st_intersects(VmObservations.the_geom_point)) + .join(TGrid, TGrid.the_geom.st_intersects(VmObservations.the_geom_point)) + .filter(and_(VmObservations.cd_ref == cd_nom, VmAreas.area_code == id_area)) + .order_by(TGrid.id_maille) + ) + + current_app.logger.debug( + " QUERY: {}".format(query) + ) + tabObs = list() + for o in query.all(): + temp = { + "id_maille": o.id_maille, + "nb_observations": 1, + "annee": o.annee, + "geojson_maille": json.loads(o.geojson_maille), + } + tabObs.append(temp) + + return tabObs + + +def get_area_taxa(session, id_area): + query = ( + session.query( + VmTaxons.cd_ref, + VmTaxons.nom_vern, + VmTaxons.nom_complet_html, + VmTaxons.group2_inpn, + VmTaxons.patrimonial, + VmTaxons.protection_stricte, + VmMedias.url, + VmMedias.chemin, + func.count(VmObservations.id_observation).label("nb_obs"), + func.max(func.extract("year", VmObservations.dateobs)).label("last_obs"), + ) + .join(VmTaxons, VmTaxons.cd_ref == VmObservations.cd_ref) + .join( + VmCorAreaObservation, + VmObservations.id_observation == VmCorAreaObservation.id_observation, + ) + .outerjoin( + VmMedias, + and_( + VmMedias.cd_ref == VmObservations.cd_ref, + VmMedias.id_type == current_app.config["ATTR_MAIN_PHOTO"], + ), + ) + .filter(VmCorAreaObservation.id_area == id_area) + .group_by( + VmTaxons.cd_ref, + VmTaxons.nom_vern, + VmTaxons.nom_complet_html, + VmTaxons.group2_inpn, + VmTaxons.patrimonial, + VmTaxons.protection_stricte, + VmMedias.url, + VmMedias.chemin, + ) + .order_by(-func.count(VmObservations.id_observation)) + ) + current_app.logger.debug(" QUERY: {}".format(query)) + current_app.logger.debug(" start loop: {}".format(datetime.now())) + result = [] + nbObsTotal = 0 + for r in query.all(): + temp = r._asdict() + temp["group2_inpn"] = utils.deleteAccent(r.group2_inpn) + temp["path"] = utils.findPath(r) + nbObsTotal = nbObsTotal + r.nb_obs + result.append(temp) + current_app.logger.debug(" end loop: {}".format(datetime.now())) + return {"taxons": result, "nbObsTotal": nbObsTotal} + + +def get_surrounding_areas(session, id_area): + subquery = ( + session.query(VmAreas.the_geom).filter(VmAreas.id_area == id_area).subquery() + ) + + query = ( + session.query( + VmAreas.id_area, + VmAreas.area_name, + VmAreas.area_code, + VmBibAreasTypes.type_code, + VmBibAreasTypes.type_name, + ) + .join(VmBibAreasTypes, VmAreas.id_type == VmBibAreasTypes.id_type) + .filter(and_(VmAreas.the_geom.st_intersects(subquery.c.the_geom))) + ) + + return query.all() diff --git a/atlas/modeles/repositories/vmCommunesRepository.py b/atlas/modeles/repositories/vmCommunesRepository.py index 79292d01..cbb27457 100644 --- a/atlas/modeles/repositories/vmCommunesRepository.py +++ b/atlas/modeles/repositories/vmCommunesRepository.py @@ -1,48 +1,45 @@ - # -*- coding:utf-8 -*- import ast + from flask import current_app from sqlalchemy import distinct from sqlalchemy.sql import text from sqlalchemy.sql.expression import func -from ..entities.vmCommunes import VmCommunes +from atlas.modeles.entities.vmCommunes import VmCommunes def getAllCommunes(session): - req = session.query( - distinct(VmCommunes.commune_maj), VmCommunes.insee - ).all() + req = session.query(distinct(VmCommunes.commune_maj), VmCommunes.insee).all() communeList = list() for r in req: - temp = {'label': r[0], 'value': r[1]} + temp = {"label": r[0], "value": r[1]} communeList.append(temp) return communeList + def getCommunesSearch(session, search, limit=50): req = session.query( distinct(VmCommunes.commune_maj), VmCommunes.insee, - func.length(VmCommunes.commune_maj) - ).filter(VmCommunes.commune_maj.ilike('%' + search + '%')) + func.length(VmCommunes.commune_maj), + ).filter(VmCommunes.commune_maj.ilike("%" + search + "%")) - if (current_app.config['ORDER_COMMUNES_BYLENGTH']): - req = req.order_by(func.length(VmCommunes.commune_maj)) - else: - req = req.order_by(VmCommunes.commune_maj) + + req = req.order_by(VmCommunes.commune_maj) req = req.limit(limit).all() - + communeList = list() for r in req: - temp = {'label': r[0], 'value': r[1]} + temp = {"label": r[0], "value": r[1]} communeList.append(temp) return communeList def getCommuneFromInsee(connection, insee): - sql = """ + sql = """ SELECT c.commune_maj, c.insee, c.commune_geojson @@ -53,21 +50,21 @@ def getCommuneFromInsee(connection, insee): communeObj = dict() for r in req: communeObj = { - 'communeName': r.commune_maj, - 'insee': str(r.insee), - 'communeGeoJson': ast.literal_eval(r.commune_geojson) + "areaName": r.commune_maj, + "areaCode": str(r.insee), + "areaGeoJson": ast.literal_eval(r.commune_geojson), } return communeObj def getCommunesObservationsChilds(connection, cd_ref): sql = """ - SELECT DISTINCT (com.insee) as insee, com.commune_maj + SELECT DISTINCT (com.insee) AS insee, com.commune_maj FROM atlas.vm_communes com JOIN atlas.vm_observations obs ON obs.insee = com.insee - WHERE obs.cd_ref in ( - SELECT * from atlas.find_all_taxons_childs(:thiscdref) + WHERE obs.cd_ref IN ( + SELECT * FROM atlas.find_all_taxons_childs(:thiscdref) ) OR obs.cd_ref = :thiscdref ORDER BY com.commune_maj ASC @@ -75,6 +72,6 @@ def getCommunesObservationsChilds(connection, cd_ref): req = connection.execute(text(sql), thiscdref=cd_ref) listCommunes = list() for r in req: - temp = {'insee': r.insee, 'commune_maj': r.commune_maj} + temp = {"insee": r.insee, "commune_maj": r.commune_maj} listCommunes.append(temp) return listCommunes diff --git a/atlas/modeles/repositories/vmCorTaxonAttribut.py b/atlas/modeles/repositories/vmCorTaxonAttribut.py index 79123f2a..b737b389 100644 --- a/atlas/modeles/repositories/vmCorTaxonAttribut.py +++ b/atlas/modeles/repositories/vmCorTaxonAttribut.py @@ -1,11 +1,10 @@ - # -*- coding:utf-8 -*- from sqlalchemy.sql import text def getAttributesTaxon( - connection, cd_ref, attrDesc, attrComment, attrMilieu, attrChoro + connection, cd_ref, attrDesc, attrComment, attrMilieu, attrChoro ): sql = """ SELECT * @@ -34,7 +33,7 @@ def getAttributesTaxon( elif r.id_attribut == attrComment: descTaxon['commentaire'] = r.valeur_attribut elif r.id_attribut == attrMilieu: - descTaxon['milieu'] = r.valeur_attribut.replace("&" , " | ") + descTaxon['milieu'] = r.valeur_attribut.replace("&", " | ") elif r.id_attribut == attrChoro: descTaxon['chorologie'] = r.valeur_attribut return descTaxon diff --git a/atlas/modeles/repositories/vmMedias.py b/atlas/modeles/repositories/vmMedias.py index 78cdcc80..467210d2 100644 --- a/atlas/modeles/repositories/vmMedias.py +++ b/atlas/modeles/repositories/vmMedias.py @@ -2,11 +2,10 @@ from flask import current_app -from .. import utils - - from sqlalchemy.sql import text +from atlas.modeles import utils + def _format_media(r): """ @@ -69,44 +68,55 @@ def getPhotoCarousel(connection, cd_ref, id): def switchMedia(row): + media_template = { # noqa + current_app.config["ATTR_AUDIO"]: "{path}", + current_app.config["ATTR_VIDEO_HEBERGEE"]: "{path}", + current_app.config["ATTR_YOUTUBE"]: """ + """, + current_app.config["ATTR_DAILYMOTION"]: """ + """, + current_app.config["ATTR_VIMEO"]: """ + """ + } + goodPath = str() - if row.chemin is None and row.url is None: + if not row.chemin and not row.url: return None - elif row.chemin is not None and row.chemin != "": + elif row.chemin: goodPath = row.chemin else: goodPath = row.url - if goodPath == "" or goodPath is None: + if not goodPath: return None - - return { - current_app.config["ATTR_AUDIO"]: goodPath, - current_app.config["ATTR_VIDEO_HEBERGEE"]: goodPath, - current_app.config[ - "ATTR_YOUTUBE" - ]: "", - current_app.config[ - "ATTR_DAILYMOTION" - ]: "", - current_app.config[ - "ATTR_VIMEO" - ]: "", # noqa - } + return media_template[row.id_type].format(path=goodPath) def getVideo_and_audio(connection, cd_ref, id5, id6, id7, id8, id9): sql = """ SELECT * FROM atlas.vm_medias - WHERE id_type in (:id5, :id6, :id7, :id8, :id9) AND cd_ref = :thiscdref + WHERE id_type IN (:id5, :id6, :id7, :id8, :id9) AND cd_ref = :thiscdref ORDER BY date_media DESC """ req = connection.execute( @@ -114,11 +124,11 @@ def getVideo_and_audio(connection, cd_ref, id5, id6, id7, id8, id9): ) tabMedias = {"audio": list(), "video": list()} for r in req: - if switchMedia(r) is not None: - path = switchMedia(r) + path = switchMedia(r) + if path is not None: temp = { "id_type": r.id_type, - "path": path[r.id_type], + "path": path, "title": r.titre, "author": deleteNone(r.auteur), "description": deleteNone(r.desc_media), @@ -137,7 +147,7 @@ def getLinks_and_articles(connection, cd_ref, id3, id4): sql = """ SELECT * FROM atlas.vm_medias - WHERE id_type in (:id3, :id4) AND cd_ref = :thiscdref + WHERE id_type IN (:id3, :id4) AND cd_ref = :thiscdref ORDER BY date_media DESC """ req = connection.execute(text(sql), thiscdref=cd_ref, id3=id3, id4=id4) @@ -188,4 +198,3 @@ def getPhotosGalleryByGroup(connection, id1, id2, INPNgroup): photo["nb_obs"] = r.nb_obs tab_photos.append(photo) return tab_photos - diff --git a/atlas/modeles/repositories/vmMoisRepository.py b/atlas/modeles/repositories/vmMoisRepository.py index f3591955..b19fa88f 100644 --- a/atlas/modeles/repositories/vmMoisRepository.py +++ b/atlas/modeles/repositories/vmMoisRepository.py @@ -1,4 +1,3 @@ - # -*- coding:utf-8 -*- from sqlalchemy.sql import text @@ -7,13 +6,13 @@ def getMonthlyObservationsChilds(connection, cd_ref): sql = """ SELECT - SUM(_01) as _01, SUM(_02) as _02, SUM(_03) as _03, - SUM(_04) as _04, SUM(_05) as _05, SUM(_06) as _06, - SUM(_07) as _07, SUM(_08) as _08, SUM(_09) as _09, - SUM(_10) as _10, SUM(_11) as _11, SUM (_12) as _12 + SUM(_01) AS _01, SUM(_02) AS _02, SUM(_03) AS _03, + SUM(_04) AS _04, SUM(_05) AS _05, SUM(_06) AS _06, + SUM(_07) AS _07, SUM(_08) AS _08, SUM(_09) AS _09, + SUM(_10) AS _10, SUM(_11) AS _11, SUM (_12) AS _12 FROM atlas.vm_mois mois - WHERE mois.cd_ref in ( - select * from atlas.find_all_taxons_childs(:thiscdref) + WHERE mois.cd_ref IN ( + SELECT * FROM atlas.find_all_taxons_childs(:thiscdref) ) OR mois.cd_ref = :thiscdref """ @@ -33,4 +32,4 @@ def getMonthlyObservationsChilds(connection, cd_ref): {'mois': "Octobre", 'value': inter._10}, {'mois': "Novembre", 'value': inter._11}, {'mois': "Decembre", 'value': inter._12} - ] \ No newline at end of file + ] diff --git a/atlas/modeles/repositories/vmObservationsMaillesRepository.py b/atlas/modeles/repositories/vmObservationsMaillesRepository.py index 801aec73..a2ed2ab6 100644 --- a/atlas/modeles/repositories/vmObservationsMaillesRepository.py +++ b/atlas/modeles/repositories/vmObservationsMaillesRepository.py @@ -1,7 +1,8 @@ -from geojson import Feature, FeatureCollection import json +from geojson import Feature, FeatureCollection from sqlalchemy.sql import text, func, or_ + from atlas.modeles.entities.vmObservations import VmObservationsMailles from atlas.modeles.utils import deleteAccent, findPath @@ -19,8 +20,8 @@ def getObservationsMaillesChilds(session, cd_ref, year_min=None, year_max=None): VmObservationsMailles.id_maille, VmObservationsMailles.geojson_maille, ) - .group_by(VmObservationsMailles.id_maille, VmObservationsMailles.geojson_maille) - .filter( + .group_by(VmObservationsMailles.id_maille, VmObservationsMailles.geojson_maille) + .filter( or_( VmObservationsMailles.cd_ref.in_(subquery), VmObservationsMailles.cd_ref == cd_ref, @@ -91,7 +92,7 @@ def lastObservationsCommuneMaille(connection, mylimit, insee): WITH last_obs AS ( SELECT obs.cd_ref, obs.dateobs, t.lb_nom, - t.nom_vern, obs.the_geom_point as l_geom + t.nom_vern, obs.the_geom_point AS l_geom FROM atlas.vm_observations obs JOIN atlas.vm_communes c ON ST_Intersects(obs.the_geom_point, c.the_geom) @@ -104,7 +105,7 @@ def lastObservationsCommuneMaille(connection, mylimit, insee): SELECT l.lb_nom, l.nom_vern, l.cd_ref, m.id_maille, m.geojson_maille FROM atlas.t_mailles_territoire m JOIN last_obs l - ON st_intersects(l.l_geom, m.the_geom) + ON st_intersects(m.the_geom, l.l_geom) GROUP BY l.lb_nom, l.cd_ref, m.id_maille, l.nom_vern, m.geojson_maille """ observations = connection.execute(text(sql), thisInsee=insee, thislimit=mylimit) @@ -129,7 +130,7 @@ def getObservationsTaxonCommuneMaille(connection, insee, cd_ref): sql = """ SELECT o.cd_ref, t.id_maille, t.geojson_maille, - extract(YEAR FROM o.dateobs) as annee + extract(YEAR FROM o.dateobs) AS annee FROM atlas.vm_observations o JOIN atlas.vm_communes c ON ST_INTERSECTS(o.the_geom_point, c.the_geom) diff --git a/atlas/modeles/repositories/vmObservationsRepository.py b/atlas/modeles/repositories/vmObservationsRepository.py index 3c7d1461..1a3c41bb 100644 --- a/atlas/modeles/repositories/vmObservationsRepository.py +++ b/atlas/modeles/repositories/vmObservationsRepository.py @@ -1,15 +1,13 @@ import json - from datetime import datetime -from geojson import Feature, FeatureCollection + from flask import current_app -from sqlalchemy import MetaData +from geojson import Feature, FeatureCollection from sqlalchemy.sql import text, func, or_ -from atlas.modeles.entities.vmObservations import VmObservations from atlas.modeles import utils from atlas.utils import engine, GenericTable - +from atlas.modeles.repositories import vmMedias currentYear = datetime.now().year cached_vm_observation = None @@ -59,10 +57,10 @@ def searchObservationsChilds(session, cd_ref): def firstObservationChild(connection, cd_ref): - sql = """SELECT min(taxons.yearmin) as yearmin + sql = """SELECT min(taxons.yearmin) AS yearmin FROM atlas.vm_taxons taxons JOIN atlas.vm_taxref taxref ON taxref.cd_ref=taxons.cd_ref - WHERE taxons.cd_ref in ( + WHERE taxons.cd_ref IN ( SELECT * FROM atlas.find_all_taxons_childs(:thiscdref) )OR taxons.cd_ref = :thiscdref""" req = connection.execute(text(sql), thiscdref=cd_ref) @@ -74,7 +72,7 @@ def lastObservations(connection, mylimit, idPhoto): sql = """ SELECT obs.*, COALESCE(split_part(tax.nom_vern, ',', 1) || ' | ', '') - || tax.lb_nom as taxon, + || tax.lb_nom AS taxon, tax.group2_inpn, medias.url, medias.chemin, medias.id_media FROM atlas.vm_observations obs @@ -102,7 +100,7 @@ def lastObservations(connection, mylimit, idPhoto): def lastObservationsCommune(connection, mylimit, insee): sql = """SELECT o.*, COALESCE(split_part(tax.nom_vern, ',', 1) || ' | ', '') - || tax.lb_nom as taxon + || tax.lb_nom AS taxon FROM atlas.vm_observations o JOIN atlas.vm_communes c ON ST_Intersects(o.the_geom_point, c.the_geom) JOIN atlas.vm_taxons tax ON o.cd_ref = tax.cd_ref @@ -124,7 +122,7 @@ def getObservationTaxonCommune(connection, insee, cd_ref): sql = """ SELECT o.*, COALESCE(split_part(tax.nom_vern, ',', 1) || ' | ', '') - || tax.lb_nom as taxon, + || tax.lb_nom AS taxon, o.observateurs FROM ( SELECT * FROM atlas.vm_observations o @@ -174,9 +172,9 @@ def observersParser(req): def getObservers(connection, cd_ref): sql = """ - SELECT distinct observateurs + SELECT DISTINCT observateurs FROM atlas.vm_observations - WHERE cd_ref in ( + WHERE cd_ref IN ( SELECT * FROM atlas.find_all_taxons_childs(:thiscdref) ) OR cd_ref = :thiscdref @@ -187,10 +185,10 @@ def getObservers(connection, cd_ref): def getGroupeObservers(connection, groupe): sql = """ - SELECT distinct observateurs + SELECT DISTINCT observateurs FROM atlas.vm_observations - WHERE cd_ref in ( - SELECT cd_ref from atlas.vm_taxons WHERE group2_inpn = :thisgroupe + WHERE cd_ref IN ( + SELECT cd_ref FROM atlas.vm_taxons WHERE group2_inpn = :thisgroupe ) """ req = connection.execute(text(sql), thisgroupe=groupe) @@ -199,7 +197,7 @@ def getGroupeObservers(connection, groupe): def getObserversCommunes(connection, insee): sql = """ - SELECT distinct observateurs + SELECT DISTINCT observateurs FROM atlas.vm_observations WHERE insee = :thisInsee """ @@ -209,7 +207,6 @@ def getObserversCommunes(connection, insee): def statIndex(connection): result = {"nbTotalObs": None, "nbTotalTaxons": None, "town": None, "photo": None} - sql = "SELECT COUNT(*) AS count \ FROM atlas.vm_observations " req = connection.execute(text(sql)) @@ -300,3 +297,29 @@ def genericStatMedias(connection, tab): return None else: return tabStat + +def getLastDiscoveries(connection): + sql=""" + SELECT date(min(dateobs)), vo.cd_ref, vt.lb_nom, vt.nom_vern, m.id_media, m.chemin, m.url, vt.group2_inpn + FROM atlas.vm_observations vo + JOIN atlas.vm_taxref vt ON vo.cd_ref = vt.cd_nom + LEFT JOIN atlas.vm_medias m ON m.cd_ref=vo.cd_ref and m.id_type = :thisidtype + WHERE id_rang='ES' + GROUP BY vo.cd_ref, vt.lb_nom, vt.nom_vern, m.id_media, m.chemin, m.url, vt.group2_inpn + ORDER BY min(dateobs) DESC + LIMIT 6 + """ + req = connection.execute(text(sql), thisidtype=current_app.config["ATTR_MAIN_PHOTO"]) + lastDiscoveriesList= list() + for r in req : + temp = { + 'date':r.date, + 'cd_ref':r.cd_ref, + 'nom_vern':r.nom_vern, + 'lb_nom':r.lb_nom, + 'id_media':r.id_media, + 'group2_inpn': r.group2_inpn, + 'media_path': r.chemin if r.chemin is not None else r.url + } + lastDiscoveriesList.append(temp) + return lastDiscoveriesList \ No newline at end of file diff --git a/atlas/modeles/repositories/vmOrganismsRepository.py b/atlas/modeles/repositories/vmOrganismsRepository.py new file mode 100644 index 00000000..ded72e5e --- /dev/null +++ b/atlas/modeles/repositories/vmOrganismsRepository.py @@ -0,0 +1,91 @@ +import json + +from geojson import Feature, FeatureCollection +from sqlalchemy.sql import text, func, or_ + +from atlas.modeles.entities import vmOrganisms + +def statOrganism (connection,id_organism): + # Fiche organism + sql = """SELECT count(DISTINCT cd_ref) AS nb_taxons, SUM(nb_observations) AS nb_obs, + nom_organism, url_organism, url_logo, adresse_organism, cp_organism, ville_organism, + tel_organism, email_organism + FROM atlas.vm_cor_taxon_organism o + WHERE o.id_organism = :thisidorganism + GROUP BY nom_organism, url_organism, url_logo, adresse_organism, cp_organism, ville_organism, + tel_organism, email_organism""" + req = connection.execute(text(sql), thisidorganism=id_organism) + StatsOrga = dict() + for r in req: + StatsOrga={ + 'nb_taxons':r.nb_taxons, + 'nb_obs':r.nb_obs, + 'nom_organism':r.nom_organism, + 'url_organism':r.url_organism, + 'url_logo':r.url_logo, + 'adresse_organism':r.adresse_organism, + 'cp_organism':r.cp_organism, + 'ville_organism':r.ville_organism, + 'tel_organism':r.tel_organism, + 'email_organism':r.email_organism + } + + return StatsOrga + + +def topObsOrganism(connection, id_organism): + #Stats avancées organism + sql = """SELECT cd_ref, nb_observations as nb_obs + FROM atlas.vm_cor_taxon_organism o + WHERE o.id_organism = :thisidorganism + ORDER BY nb_observations DESC + LIMIT 3 + """ + req = connection.execute(text(sql), thisidorganism=id_organism) + topSpecies = list() + for r in req: + temp={ + 'cd_ref':r.cd_ref, + 'nb_obs':r.nb_obs, + } + topSpecies.append(temp) + return topSpecies + + + +def getListOrganism(connection,cd_ref): + # Fiche espèce : Liste des organisms pour un taxon + sql = """SELECT nb_observations, id_organism, nom_organism, url_organism, url_logo + FROM atlas.vm_cor_taxon_organism o + WHERE cd_ref = :thiscdref + ORDER BY nb_observations DESC""" + req = connection.execute(text(sql), thiscdref=cd_ref) + ListOrganism=list() + for r in req: + temp={ + 'nb_observation':r.nb_observations, + 'id_organism':r.id_organism, + 'nom_organism':r.nom_organism, + 'url_organism':r.url_organism, + 'url_logo':r.url_logo + } + ListOrganism.append(temp) + return ListOrganism + +def getTaxonRepartitionOrganism(connection, id_organism): + #Fiche organism : réparition du type d'observations + sql="""SELECT SUM(o.nb_observations) as nb_obs_group, g.group2_inpn + FROM atlas.vm_cor_taxon_organism o + JOIN atlas.vm_taxref g on g.cd_nom=o.cd_ref + WHERE o.id_organism = :thisidorganism + GROUP BY g.group2_inpn, o.id_organism + """; + req = connection.execute(text(sql), thisidorganism=id_organism) + ListGroup=list() + for r in req: + temp={ + 'group2_inpn': r.group2_inpn, + 'nb_obs_group': int(r.nb_obs_group) + } + ListGroup.append(temp) + return ListGroup \ No newline at end of file diff --git a/atlas/modeles/repositories/vmSearchTaxonRepository.py b/atlas/modeles/repositories/vmSearchTaxonRepository.py index dd747b40..9a2fbebf 100644 --- a/atlas/modeles/repositories/vmSearchTaxonRepository.py +++ b/atlas/modeles/repositories/vmSearchTaxonRepository.py @@ -1,7 +1,7 @@ # -*- coding:utf-8 -*- from sqlalchemy import desc, func -from ..entities.vmSearchTaxon import VmSearchTaxon +from atlas.modeles.entities.vmSearchTaxon import VmSearchTaxon def listeTaxons(session): @@ -44,9 +44,9 @@ def listeTaxonsSearch(session, search, limit=50): search = search.replace(" ", "%") req = ( req.filter(VmSearchTaxon.search_name.ilike("%" + search + "%")) - .order_by(desc("idx_trgm")) - .order_by(VmSearchTaxon.cd_ref == VmSearchTaxon.cd_nom) - .limit(limit) + .order_by(desc("idx_trgm")) + .order_by(VmSearchTaxon.cd_ref == VmSearchTaxon.cd_nom) + .limit(limit) ) data = req.all() diff --git a/atlas/modeles/repositories/vmTaxonsMostView.py b/atlas/modeles/repositories/vmTaxonsMostView.py index 342e0d15..414e01c6 100644 --- a/atlas/modeles/repositories/vmTaxonsMostView.py +++ b/atlas/modeles/repositories/vmTaxonsMostView.py @@ -1,7 +1,7 @@ # -*- coding:utf-8 -*- -from .. import utils +from atlas.modeles import utils from sqlalchemy.sql import text diff --git a/atlas/modeles/repositories/vmTaxonsRepository.py b/atlas/modeles/repositories/vmTaxonsRepository.py index ac32e16e..a173521a 100644 --- a/atlas/modeles/repositories/vmTaxonsRepository.py +++ b/atlas/modeles/repositories/vmTaxonsRepository.py @@ -1,13 +1,9 @@ - # -*- coding:utf-8 -*- from flask import current_app - -import unicodedata - from sqlalchemy.sql import text -from .. import utils +from atlas.modeles import utils # With distinct the result in a array not an object, 0: lb_nom, 1: nom_vern @@ -89,7 +85,7 @@ def getINPNgroupPhotos(connection): sql = """ SELECT DISTINCT count(*) AS nb_photos, group2_inpn FROM atlas.vm_taxons T - JOIN atlas.vm_medias M on M.cd_ref = T.cd_ref + JOIN atlas.vm_medias M ON M.cd_ref = T.cd_ref GROUP BY group2_inpn ORDER BY nb_photos DESC """ @@ -122,7 +118,7 @@ def getTaxonsGroup(connection, groupe): tabTaxons = list() nbObsTotal = 0 for r in req: - nbObsTotal = nbObsTotal+r.nb_obs + nbObsTotal = nbObsTotal + r.nb_obs temp = { 'nom_complet_html': r.nom_complet_html, 'nb_obs': r.nb_obs, @@ -145,7 +141,7 @@ def getAllINPNgroup(connection): SELECT SUM(nb_obs) AS som_obs, group2_inpn FROM atlas.vm_taxons GROUP BY group2_inpn - ORDER by som_obs DESC + ORDER BY som_obs DESC """ req = connection.execute(text(sql)) groupList = list() diff --git a/atlas/modeles/repositories/vmTaxrefRepository.py b/atlas/modeles/repositories/vmTaxrefRepository.py index be2982c7..59a9472f 100644 --- a/atlas/modeles/repositories/vmTaxrefRepository.py +++ b/atlas/modeles/repositories/vmTaxrefRepository.py @@ -1,9 +1,10 @@ # -*- coding:utf-8 -*- from flask import current_app from sqlalchemy.sql import text -from .. import utils -from ..entities.vmTaxref import VmTaxref -from ..entities.tBibTaxrefRang import TBibTaxrefRang + +from atlas.modeles import utils +from atlas.modeles.entities.tBibTaxrefRang import TBibTaxrefRang +from atlas.modeles.entities.vmTaxref import VmTaxref def searchEspece(connection, cd_ref): @@ -12,16 +13,16 @@ def searchEspece(connection, cd_ref): """ sql = """ WITH limit_obs AS ( - select - :thiscdref as cd_ref, min(yearmin) AS yearmin, + SELECT + :thiscdref AS cd_ref, min(yearmin) AS yearmin, max(yearmax) AS yearmax, SUM(nb_obs) AS nb_obs FROM atlas.vm_taxons WHERE - cd_ref in (SELECT * FROM atlas.find_all_taxons_childs(:thiscdref)) + cd_ref IN (SELECT * FROM atlas.find_all_taxons_childs(:thiscdref)) OR cd_ref = :thiscdref ) SELECT taxref.*, - l.cd_ref, l.yearmin, l.yearmax, COALESCE(l.nb_obs, 0) as nb_obs, + l.cd_ref, l.yearmin, l.yearmax, COALESCE(l.nb_obs, 0) AS nb_obs, t2.patrimonial, t2.protection_stricte FROM atlas.vm_taxref taxref JOIN limit_obs l @@ -115,9 +116,9 @@ def getTaxon(session, cd_nom): TBibTaxrefRang.nom_rang, TBibTaxrefRang.tri_rang, ) - .join(TBibTaxrefRang, TBibTaxrefRang.id_rang == VmTaxref.id_rang) - .filter(VmTaxref.cd_nom == cd_nom) - .one_or_none() + .join(TBibTaxrefRang, TBibTaxrefRang.id_rang == VmTaxref.id_rang) + .filter(VmTaxref.cd_nom == cd_nom) + .one_or_none() ) @@ -129,8 +130,8 @@ def getCd_sup(session, cd_ref): def getInfoFromCd_ref(session, cd_ref): req = ( session.query(VmTaxref.lb_nom, TBibTaxrefRang.nom_rang) - .join(TBibTaxrefRang, TBibTaxrefRang.id_rang == VmTaxref.id_rang) - .filter(VmTaxref.cd_ref == cd_ref) + .join(TBibTaxrefRang, TBibTaxrefRang.id_rang == VmTaxref.id_rang) + .filter(VmTaxref.cd_ref == cd_ref) ) return {"lb_nom": req[0].lb_nom, "nom_rang": req[0].nom_rang} @@ -141,8 +142,8 @@ def getAllTaxonomy(session, cd_ref): taxon = getTaxon(session, taxonSup) tabTaxon = list() while ( - taxon - and taxon.tri_rang >= current_app.config["LIMIT_RANG_TAXONOMIQUE_HIERARCHIE"] + taxon + and taxon.tri_rang >= current_app.config["LIMIT_RANG_TAXONOMIQUE_HIERARCHIE"] ): temp = { "rang": taxon.id_rang, diff --git a/atlas/modeles/utils.py b/atlas/modeles/utils.py index 19938765..b095cef1 100644 --- a/atlas/modeles/utils.py +++ b/atlas/modeles/utils.py @@ -1,9 +1,6 @@ # -*- coding:utf-8 -*- -from ..utils import engine -from sqlalchemy import MetaData, Table import unicodedata -from ..configuration import config def deleteAccent(string): diff --git a/atlas/static/.nvmrc b/atlas/static/.nvmrc new file mode 100644 index 00000000..7b768e0b --- /dev/null +++ b/atlas/static/.nvmrc @@ -0,0 +1 @@ +14.17.6 \ No newline at end of file diff --git a/atlas/static/chart.js b/atlas/static/chart.js new file mode 100644 index 00000000..57b54678 --- /dev/null +++ b/atlas/static/chart.js @@ -0,0 +1,55 @@ +// ChartJS Graphs +const chartMainColor = getComputedStyle(document.documentElement).getPropertyValue('--main-color'); +const chartHoverMainColor = getComputedStyle(document.documentElement).getPropertyValue('--second-color'); + +const getChartDatas = function (data, key) { + let values = []; + for (var i = 0; i < data.length; i++) { + values.push(data[i][key]) + } + return values +}; + +//Generic vertical bar graph +genericChart = function (element, labels, values) { + return new Chart(element, { + type: 'bar', + data: { + labels: labels, + datasets: [{ + label: 'observations', + data: values, + backgroundColor: chartMainColor, + hoverBackgroundColor: chartHoverMainColor, + borderWidth: 0 + }] + }, + options: { + scales: { + yAxes: [{ + ticks: { + beginAtZero: true + } + }], + xAxes: [{ + gridLines: { + display: false + } + }] + }, + maintainAspectRatio: false, + plugins: { + legend: { + position: 'top', + display: false + }, + } + } + }); +}; + +var monthChartElement = document.getElementById('monthChart'); +const monthChart = genericChart(monthChartElement, months_name, getChartDatas(months_value, 'value')); + +var altiChartElement = document.getElementById('altiChart'); +const altiChart = genericChart(altiChartElement, getChartDatas(dataset, 'altitude'), getChartDatas(dataset, 'value')); diff --git a/atlas/static/chart_organism.js b/atlas/static/chart_organism.js new file mode 100644 index 00000000..35ae01e1 --- /dev/null +++ b/atlas/static/chart_organism.js @@ -0,0 +1,62 @@ +// ChartJS Graphs +const chartMainColor = getComputedStyle(document.documentElement).getPropertyValue('--main-color'); +const chartHoverMainColor = getComputedStyle(document.documentElement).getPropertyValue('--second-color'); + +const getChartDatas = function (data, key) { + let values = []; + for (var i = 0; i < data.length; i++) { + values.push(data[i][key]) + } + return values +}; + +//Circle graph for parts graph +circleChart = function (element, labels, values, colors) { + return new Chart(element, { + type: 'pie', + data: { + labels: labels, + datasets: [{ + label: 'observations', + data: values, + backgroundColor: colors + }] + }, + options: { + responsive: true, + plugins: { + legend: { + position: 'left', + }, + } + }, + }) +}; + +var color_tab = [ + '#E1CE7A', + '#FBFFB9', + '#FDD692', + '#EC7357', + '#754F44', + '#FB6376', + '#B7ADCF', + '#DEE7E7', + '#F4FAFF', + '#383D3B', + '#7C7C7C', + '#B5F44A', + '#D6FF79', + '#507255', + '#381D2A', + '#BA5624', + '#FFA552', + '#F7FFE0', + '#49C6E5', + '#54DEFD', + '#0B5563', + '#54DEFD' + ]; + +var groupChartElement = document.getElementById('groupChart'); +const groupChart = circleChart(groupChartElement, getChartDatas(dataset, 'group2_inpn'), getChartDatas(dataset, 'nb_obs_group'), color_tab); diff --git a/static/css/atlas.css b/atlas/static/css/atlas.css similarity index 71% rename from static/css/atlas.css rename to atlas/static/css/atlas.css index eb3656de..03ea8e5a 100644 --- a/static/css/atlas.css +++ b/atlas/static/css/atlas.css @@ -1,11 +1,34 @@ :root { - --main-color: #82c91e; - --second-color: #649b18; + --main-color: #c3b528; + --second-color: #5a7526; + --map-maille-border-color: #ddd; + --map-maille-lastobs-border-color: #c218d0; + --map-territory-border-color: #333; + --map-area-border-width: 3px; + --map-area-border-color: var(--second-color); + --scrollbarBG: #cfd8dc; + --thumbBG: var(--main-color); } body { + display: flex; + flex-direction: column; + min-height: 100vh; background-color: #e3e7e8; - padding-top: 50px; +} + +main { + margin-top: 60px; + margin-left: 60px; + flex: 1; +} + +#dropdown09 { + cursor: pointer; +} + +.small-placeholder::placeholder { + font-size: 13px; } .icon-color-title { @@ -32,7 +55,7 @@ body { display: inline-block; content: ""; border-top: 1px solid rgba(2, 2, 2, 0.158); - width: 5rem; + width: 3rem; margin: 0 1rem; -webkit-transform: translateY(-8px); transform: translateY(-8px); @@ -42,7 +65,7 @@ body { display: inline-block; content: ""; border-top: 1px solid rgba(2, 2, 2, 0.158); - width: 5rem; + width: 3rem; margin: 0 1rem; -webkit-transform: translateY(-8px); transform: translateY(-8px); @@ -61,8 +84,11 @@ body { } #page { - padding-left: 75px; - margin-top: 25px; + padding-left: 10px; + padding-right: 10px; + flex: 1; + /*padding-top: 60px;*/ + /*margin-top: 25px;*/ } .form-control:focus { @@ -71,6 +97,10 @@ body { 0 0 5px var(--main-color); } +.form-inline .form-control { + width: 150 px; +} + /* carto */ .leaflet-touch .leaflet-bar a:last-child { @@ -121,13 +151,14 @@ a { background-color: white !important; margin-bottom: 0px; border-radius: 0px; - border-bottom-color: var(--main-color); + border-bottom: 1px solid var(--main-color); z-index: 1999; height: 60px; } .logoStructure { height: 60px; + max-height: 60px; margin: -15px; padding-right: 15px; } @@ -138,10 +169,38 @@ a { padding-right: 20px; } -@media (max-width: 767px) { +@media (max-width: 760px) { .navbar-collapse { background-color: #333; } + + main h1 { + font-size: 1.8rem; + } + + main h2 { + font-size: 1.6rem; + } + + main h3 { + font-size: 1.4rem; + } + + main h4 { + font-size: 1.2rem; + } + + main h5 { + font-size: 1rem; + } + + main { + font-size: 0.8rem; + } + + footer { + font-size: 0.8rem; + } } .ui-autocomplete { @@ -150,13 +209,15 @@ a { /* Sidebar */ -#sideBar { +sidebar { position: fixed; + padding-top: 60px; width: 60px; background-color: #333333; - height: 100%; + height: calc(100vh); z-index: 1998; - margin-top: 10px; + flex: 1; + /*margin-top: 10px;!**!*/ } #sidebar_menu { @@ -167,8 +228,9 @@ a { } #sidebar_menu li { - padding-top: 15px; - padding-bottom: 15px; + height: 60px !important; + min-height: 60px; + line-height: 60px; color: white; cursor: pointer; text-align: center; @@ -198,10 +260,6 @@ li.sidebar-brand { color: black; } -.sidebar-brand .glyphicon { - font-size: 20px; -} - /* END sidebar */ .slider-size { @@ -255,6 +313,10 @@ input.ajax-search { background-position-x: calc(100% - 25px); } +input { + text-align: center; +} + /* LightBox */ .lb-nav { @@ -376,9 +438,13 @@ input.ajax-search { /* Footer */ -.footer { +footer { text-align: center; margin-left: 60px; + padding-top: 10px; + margin-bottom: 0px; + background-color: var(--light); + margin-top: 10px; } .credits { @@ -424,21 +490,22 @@ input.ajax-search { left: 0%; } -.overlay-obs { - color: #fff; - text-align: center; - position: relative; - top: 100px; - font-size: 13px; - background: rgba(0, 0, 0, 0.6); - -webkit-transform: translatey(-100px); - -ms-transform: translatey(-100px); - transform: translatey(-100px); - -webkit-transition: all 0.2s ease-in-out; - transition: all 0.2s ease-in-out; - padding: 10px; - text-decoration: none; -} +/*.overlay-obs {*/ +/* color: #fff;*/ +/* text-align: center;*/ +/* position: relative;*/ +/* top: 120px;*/ +/* font-size: 13px;*/ +/* background: rgba(0, 0, 0, 0.6);*/ +/* -webkit-transform: translatey(-100px);*/ +/* -ms-transform: translatey(-100px);*/ +/* transform: translatey(-100px);*/ +/* -webkit-transition: all 0.2s ease-in-out;*/ +/* transition: all 0.2s ease-in-out;*/ +/* padding: 10px;*/ +/* text-decoration: none;*/ +/* margin-top: 10px;*/ +/*}*/ .img-custom-medias { height: 250px; @@ -449,8 +516,24 @@ input.ajax-search { transition: 0.3s ease-in-out; -ms-transition: 0.3s ease-in-out; } + +.italic { + font-style: italic; +} + +.clickable { + cursor: pointer; +} + .cover { background-size: cover; + background-position: center; +} +.no-repeat { + background-repeat: no-repeat; +} +.background-center { + background-position: center; } .zoom-wrapper:hover .img-custom-medias { @@ -460,7 +543,7 @@ input.ajax-search { } #allGroups { - margin: 0 10px; + /*margin: 0 10px;*/ } #sort, @@ -470,7 +553,7 @@ input.ajax-search { } #insertPhotos { - margin-bottom: 20px; + /*margin-bottom: 20px;*/ padding: 0px; } @@ -525,3 +608,81 @@ input.ajax-search { display: inline-block; text-decoration: none !important; } + +.btn-success { + color: #fff; + background-color: var(--main-color); + border-color: var(--main-color); +} + +.btn-success:hover { + background-color: var(--second-color); + border-color: var(--second-color); +} + +#areaPage { + display: flex; +} + +/* Loader spinner */ + +#loaderSpinner { + position: absolute !important; + left: 50%; + top: 50%; + z-index: 999; +} + +.overlay-obs { + color: #fff; + text-align: center; + position: relative; + top: 100px; + font-size: 13px; + background: rgba(0, 0, 0, 0.6); + -webkit-transform: translatey(-100px); + -ms-transform: translatey(-100px); + transform: translatey(-100px); + -webkit-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; + padding: 10px; + text-decoration: none; + margin-top: 10px; +} + +.overlay-intro-image { + color: #fff; + text-align: center; + position: relative; + top: 100%; + float: left; + font-size: 13px; + background: rgba(0, 0, 0, 0.6); + padding: 10px; + text-decoration: none; +} + +.modal-header { + background-color: var(--main-color); + color: white; + padding: 0.5rem 0.5rem; +} + +#surroundingAreas .modal-body { + padding: 0; + max-height: 80vh; + overflow-y: auto; +} + +#surroundingAreasList li:hover { + background-color: var(--light); +} + +.leaflet-popup-content-wrapper, +.leaflet-popup-tip { + background: white; + color: #333; + box-shadow: 0 3px 14px rgba(0, 0, 0, 0.4); + border-radius: 2px; + border-left: 5px solid var(--main-color); +} diff --git a/static/css/ficheEspece.css b/atlas/static/css/ficheEspece.css similarity index 96% rename from static/css/ficheEspece.css rename to atlas/static/css/ficheEspece.css index 2fd01fbd..92843b2c 100644 --- a/static/css/ficheEspece.css +++ b/atlas/static/css/ficheEspece.css @@ -1,8 +1,8 @@ #page li a { - color: var(--main-color) !important; + color: var(--main-color); } -#identityPanel { +#identityCard { } #taxonIdentity { @@ -123,8 +123,8 @@ p.imgDescription.main { } #mapStat li { - margin-top: 15px; - margin-bottom: 15px; + margin-top: 12px; + margin-bottom: 12px; display: inline-block; width: 100px; text-align: center; @@ -195,7 +195,7 @@ tr.accordion-toggle { padding-right: 10px; } -#mapPanel { +#mapCard { margin-bottom: 2px; } diff --git a/static/css/fonts/et-line.eot b/atlas/static/css/fonts/et-line.eot similarity index 100% rename from static/css/fonts/et-line.eot rename to atlas/static/css/fonts/et-line.eot diff --git a/static/css/fonts/et-line.svg b/atlas/static/css/fonts/et-line.svg similarity index 100% rename from static/css/fonts/et-line.svg rename to atlas/static/css/fonts/et-line.svg diff --git a/static/css/fonts/et-line.ttf b/atlas/static/css/fonts/et-line.ttf similarity index 100% rename from static/css/fonts/et-line.ttf rename to atlas/static/css/fonts/et-line.ttf diff --git a/static/css/fonts/et-line.woff b/atlas/static/css/fonts/et-line.woff similarity index 100% rename from static/css/fonts/et-line.woff rename to atlas/static/css/fonts/et-line.woff diff --git a/static/css/icones.css b/atlas/static/css/icones.css similarity index 100% rename from static/css/icones.css rename to atlas/static/css/icones.css diff --git a/static/css/index.css b/atlas/static/css/index.css similarity index 73% rename from static/css/index.css rename to atlas/static/css/index.css index 30ef6122..ca0b9e22 100644 --- a/static/css/index.css +++ b/atlas/static/css/index.css @@ -2,14 +2,17 @@ border-color: transparent !important; } -.font-icon { - font-size: 40px; +.my-shadow { + box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14), + 0 1px 5px 0 rgba(0, 0, 0, 0.12); } h4.title-spaced { margin-top: 0px; } - +.center { + text-align: center; +} #overlay { /* position: absolute; */ padding: 10px; @@ -60,18 +63,18 @@ h4 { } .large { - font-size: 5rem; + font-size: 3rem; } .muted { color: grey; } -.text-muted { - text-transform: uppercase; - font-weight: 700; - font-size: 1.5rem; -} +/*.text-muted {*/ +/* text-transform: uppercase;*/ +/* font-weight: 700;*/ +/* font-size: 1.5rem;*/ +/*}*/ .title-spaced { letter-spacing: 0.025em; @@ -98,14 +101,27 @@ h3.title-spaced { margin-top: 0px !important; } -/*Stat block*/ +/* Bandeau de logos (slider slick) en page accueil */ + +.slidepartenaireindex { + width: 280px; +} -.stat-panel { - padding-bottom: 0px; +.slidepartenaireindex img { + max-height: 80px; + margin: auto; } +.slick-prev::before, +.slick-next::before { + color: #1e1b0c; +} + +/*Stat block*/ + .stat-object { min-height: 200px; + padding: 0px; } .stat-object .form-control { @@ -117,6 +133,7 @@ h3.title-spaced { background-color: rgb(255, 255, 255); margin-bottom: 0px; border-radius: 0px; + padding: 10px; } .stat-thumbnail span { @@ -127,25 +144,45 @@ h3.title-spaced { margin: 0px; } -#searchTaxonsStat, #searchCommunesStat { +#searchTaxonsStat, +#searchCommunesStat { background-position: right center; background-repeat: no-repeat; background-size: 25px 25px; background-position-x: calc(100% - 25px); + outline: none; } -/*Custom Stat Block*/ - -.row-medias { - margin-right: -5px; - margin-left: -5px; +.addon { + position: absolute; + margin-left: 5px; + display: flex; + align-items: center; + z-index: 100; + font-size: 20px !important; + color: grey; + padding-top: px; + margin-top: 9px; } -.stat-medias-wrapper { - padding-left: 5px; - padding-right: 5px; +.addon-navbar { + position: absolute; + margin-left: 5px; + display: flex; + align-items: center; + z-index: 100; + font-size: 20px !important; + color: grey; + padding-top: px; + margin-top: 9px; } +/*Custom Stat Block*/ + +.center-input { + width: 80%; + margin: 0 auto; +} .stat-custom-panel { padding: 10px; } @@ -226,6 +263,7 @@ h3.title-spaced { transition: all 0.2s ease-in-out; padding: 10px; text-decoration: none; + margin-top: 10px; } .zoom-wrapper:hover .img-custom-medias { @@ -247,10 +285,6 @@ h3.title-spaced { clear: both; } -#mapRow { - max-height: 600px; -} - #map { width: 100%; height: 600px; @@ -262,6 +296,13 @@ h3.title-spaced { } } +.list-group { + max-height: fit-content; + height: 100%; + overflow: scroll; + -webkit-overflow-scrolling: touch; +} + @media (min-width: 992px) { #listMap { padding-left: 0px; @@ -271,11 +312,14 @@ h3.title-spaced { .pictoImg { width: 100%; background-position: center center; - /* background-size: cover; */ height: 60px; min-width: 60px; } +.picto-img-no-resize { + background-size: cover; +} + .pictoImgSmall { height: 60px; } @@ -283,24 +327,51 @@ h3.title-spaced { .pictoImgMedium { height: 250px; } -table#tableEspece { + +#lastObsList { display: block; max-height: 600px; overflow-y: scroll; background: white; } -.tabEspece:hover { - background-color: #cccccc; +.lastObslistItem:hover { + background-color: var(--light); + cursor: pointer; } -.tabEspece.current { +.lastObslistItem .lastObslistItemIcon { + width: 80px; + height: 40px; + background-position: center; + align: center; + object-fit: contain; +} + +.lastObslistItem .lastObslistItemImage { + width: 80px; + height: 80px; + background-position: center; + object-fit: cover; + background-color: var(--light); +} + +.lastObslistItem.current { background-color: #e6e6e6; font-weight: bold; } -.singleTaxon { +/*.singleTaxon { cursor: pointer; +}*/ + +.tabEspece:hover { + background-color: #cccccc; +} + +.tabEspece.current { + background-color: #e6e6e6; + font-weight: bold; } td.singleTaxon.name { diff --git a/atlas/static/css/listEspeces.css b/atlas/static/css/listEspeces.css new file mode 100644 index 00000000..291d527f --- /dev/null +++ b/atlas/static/css/listEspeces.css @@ -0,0 +1,206 @@ +.panel { + margin-top: 10px; + padding: 5px; +} + +#page { + padding-left: 0; + padding-right: 0; +} + +footer { + margin-top: 0; +} + +#taxonList { + flex: 1 1 0; + overflow-y: auto; +} + + +/*#mapWrapper {*/ +/* position: relative !important;*/ +/* !*left: 58% !important;*!*/ +/* top: 0;*/ +/* bottom: 0;*/ +/* width: 100%;*/ +/*}*/ + +#mapContainer { + height: calc(100vh - 60px); +} + +#map { + height: 600px; +} + +#clear { + clear: both; +} + +#parent { + text-align: center; + margin-top: 10px; +} + +table.dataTable { + line-height: 1; + font-size: 1rem; +} + +table.dataTable thead .sorting, +table.dataTable thead .sorting_asc, +table.dataTable thead .sorting_desc { + background: none; +} + +.dataTables_length { + margin: 10px; +} + +.dataTables_filter { + margin: 10px; +} + +.dataTables_paginate { + margin: 10px; +} + +.dataTables_wrapper .dataTables_paginate .paginate_button { + padding: 0px; +} + +.dataTables_wrapper .dataTables_paginate .paginate_button:hover { + padding: 0px; + border: none; +} + +.pagination > .disabled > a, +.pagination > .disabled > a:focus, +.pagination > .disabled > a:hover, +.pagination > .disabled > span, +.pagination > .disabled > span:focus, +.pagination > .disabled > span:hover { + cursor: default; +} + +#stat li { + float: left; + width: 100px; + text-align: center; + border-right: 1px solid #e8e8e8; + list-style-type: none; +} + +ul#stat { + float: left; + padding: 5px; + margin-left: 32%; +} + +#statHierarchy li { + display: inline-block; + width: 100px; +} + +ul#statHierarchy { + float: left; + padding: 5px; + margin: auto; + width: 100%; + text-align: center; + margin-top: 10px; +} + +.leaflet-bar.leaflet-control.leaflet-control-custom img { + display: block; + margin-left: auto; + margin-right: auto; + margin-top: 3px; +} + +#myTable .glyphicon { + color: #333333; + font-size: 2em; +} + +/* +.eye { + padding-left: 20% +} + +.displayObs { + cursor: pointer; +} +*/ + +#loadingGif { + z-index: 1000000; + position: absolute; + left: 40%; + top: 40%; +} + +.hiddenSpan { + visibility: hidden; +} + +tbody tr:hover { + /*background-color: #cccccc !important;*/ + cursor: pointer; +} + +tbody tr.current { + background-color: #e6e6e6 !important; + font-weight: bold; +} + +.pictoImgListIcon { + width: 60px; +} + +.pictoImgList { + width: 80px; + background-position: center center; + background-size: cover; + height: 80px; + border-radius: 6px; +} + + +#taxonList .current { + background-color: var(--light); +} + + + +@media (max-width: 1200px) { + #statHierarchy i { + font-size: 2rem; + color: red; + } +} + + + @media (min-width: 992px and max-width: 1200px) { + #statHierarchy i { + font-size: 1.5rem; + color: green; + } +} + + + @media screen and (max-width: 768px) { + #statHierarchy i { + font-size: 1rem; + color: blue; + } +} + + + @media screen and (max-width: 576px) { + #statHierarchy i { + font-size: 0.8rem; + color: deeppink; + } +} \ No newline at end of file diff --git a/static/css/static_pages.css b/atlas/static/css/staticPages.css similarity index 80% rename from static/css/static_pages.css rename to atlas/static/css/staticPages.css index 444d8e4d..c383db2c 100644 --- a/static/css/static_pages.css +++ b/atlas/static/css/staticPages.css @@ -9,58 +9,65 @@ /* CUSTOMIZE THE CAROUSEL -------------------------------------------------- */ - /* Carousel base class */ .carousel { - height: 500px; - margin-bottom: 60px; + margin-top: 60px; } /* Since positioning the image, we need to help out the caption */ .carousel-caption { - z-index: 10; + z-index: 10; +} + +.carousel-inner { + height: 500px; } /* Declare heights because of positioning of img element */ -.carousel .item { - height: 500px; - background-color: #777; +.carousel-item { + height: 500px; + background-color: #777; } -.carousel-inner > .item > img { - position: absolute; - top: 0; - left: 0; - min-width: 100%; - height: 500px; +.carousel-inner > .carousel-item > img { + position: absolute; + top: 0; + bottom: 0; + margin: auto; } /* Center align the text within the three columns below the carousel */ + +.presentation { + position: relative; +} + .presentation .col-lg-4 { - margin-bottom: 20px; - text-align: center; + margin-bottom: 20px; + text-align: center; } .presentation h2 { - font-weight: normal; + font-weight: normal; + position: relative; } .presentation .col-lg-4 p { - margin-right: 10px; - margin-left: 10px; + margin-right: 10px; + margin-left: 10px; } /* Featurettes ------------------------- */ .featurette-divider { - margin: 80px 0; /* Space out the Bootstrap
more */ + margin: 80px 0; /* Space out the Bootstrap
more */ } /* RESPONSIVE CSS -------------------------------------------------- */ - /* Bump up size of carousel content */ +/* Bump up size of carousel content */ .carousel-caption p { margin-bottom: 20px; font-size: 21px; @@ -92,13 +99,13 @@ .headline h1 { font-size: 130px; background: #fff; - background: rgba(255,255,255,0.9); + background: rgba(255, 255, 255, 0.9); } .headline h2 { font-size: 77px; background: #fff; - background: rgba(255,255,255,0.9); + background: rgba(255, 255, 255, 0.9); } .featurette-divider { @@ -125,11 +132,8 @@ font-size: 50px; } -footer { - margin: 50px 0; -} -@media(max-width:1200px) { +@media (max-width: 1200px) { .headline h1 { font-size: 140px; } @@ -155,7 +159,7 @@ footer { } } -@media(max-width:991px) { +@media (max-width: 991px) { .headline h1 { font-size: 105px; } @@ -185,7 +189,7 @@ footer { } } -@media(max-width:768px) { +@media (max-width: 768px) { .container { margin: 0 15px; } @@ -199,7 +203,7 @@ footer { } } -@media(max-width:668px) { +@media (max-width: 668px) { .headline h1 { font-size: 70px; } @@ -213,7 +217,7 @@ footer { } } -@media(max-width:640px) { +@media (max-width: 640px) { .headline { padding: 75px 0 25px 0; } @@ -227,7 +231,7 @@ footer { } } -@media(max-width:375px) { +@media (max-width: 375px) { .featurette-divider { margin: 10px 0; } diff --git a/atlas/static/css/style.css b/atlas/static/css/style.css new file mode 100644 index 00000000..bf9cbd22 --- /dev/null +++ b/atlas/static/css/style.css @@ -0,0 +1,447 @@ +@font-face { + font-family: "et-line"; + src: url("fonts/et-line.eot"); + src: url("fonts/et-line.eot?#iefix") format("embedded-opentype"), + url("fonts/et-line.woff") format("woff"), + url("fonts/et-line.ttf") format("truetype"), + url("fonts/et-line.svg#et-line") format("svg"); + font-weight: normal; + font-style: normal; +} + +/* Use the following CSS code if you want to use data attributes for inserting your icons */ +[data-icon]:before { + font-family: "et-line"; + content: attr(data-icon); + speak: none; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + display: inline-block; +} + +/* Use the following CSS code if you want to have a class per icon */ +/* +Instead of a list of all class selectors, +you can use the generic selector below, but it's slower: +[class*="icon-"] { +*/ + +.badge-primary { + color: #000; +} + +.icon-mobile, +.icon-laptop, +.icon-desktop, +.icon-tablet, +.icon-phone, +.icon-document, +.icon-documents, +.icon-search, +.icon-clipboard, +.icon-newspaper, +.icon-notebook, +.icon-book-open, +.icon-browser, +.icon-calendar, +.icon-presentation, +.icon-picture, +.icon-pictures, +.icon-video, +.icon-camera, +.icon-printer, +.icon-toolbox, +.icon-briefcase, +.icon-wallet, +.icon-gift, +.icon-bargraph, +.icon-grid, +.icon-expand, +.icon-focus, +.icon-edit, +.icon-adjustments, +.icon-ribbon, +.icon-hourglass, +.icon-lock, +.icon-megaphone, +.icon-shield, +.icon-trophy, +.icon-flag, +.icon-map, +.icon-puzzle, +.icon-basket, +.icon-envelope, +.icon-streetsign, +.icon-telescope, +.icon-gears, +.icon-key, +.icon-paperclip, +.icon-attachment, +.icon-pricetags, +.icon-lightbulb, +.icon-layers, +.icon-pencil, +.icon-tools, +.icon-tools-2, +.icon-scissors, +.icon-paintbrush, +.icon-magnifying-glass, +.icon-circle-compass, +.icon-linegraph, +.icon-mic, +.icon-strategy, +.icon-beaker, +.icon-caution, +.icon-recycle, +.icon-anchor, +.icon-profile-male, +.icon-profile-female, +.icon-bike, +.icon-wine, +.icon-hotairballoon, +.icon-globe, +.icon-genius, +.icon-map-pin, +.icon-dial, +.icon-chat, +.icon-heart, +.icon-cloud, +.icon-upload, +.icon-download, +.icon-target, +.icon-hazardous, +.icon-piechart, +.icon-speedometer, +.icon-global, +.icon-compass, +.icon-lifesaver, +.icon-clock, +.icon-aperture, +.icon-quote, +.icon-scope, +.icon-alarmclock, +.icon-refresh, +.icon-happy, +.icon-sad, +.icon-facebook, +.icon-twitter, +.icon-googleplus, +.icon-rss, +.icon-tumblr, +.icon-linkedin, +.icon-dribbble { + font-family: "et-line"; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + display: inline-block; +} +.icon-mobile:before { + content: "\e000"; +} +.icon-laptop:before { + content: "\e001"; +} +.icon-desktop:before { + content: "\e002"; +} +.icon-tablet:before { + content: "\e003"; +} +.icon-phone:before { + content: "\e004"; +} +.icon-document:before { + content: "\e005"; +} +.icon-documents:before { + content: "\e006"; +} +.icon-search:before { + content: "\e007"; +} +.icon-clipboard:before { + content: "\e008"; +} +.icon-newspaper:before { + content: "\e009"; +} +.icon-notebook:before { + content: "\e00a"; +} +.icon-book-open:before { + content: "\e00b"; +} +.icon-browser:before { + content: "\e00c"; +} +.icon-calendar:before { + content: "\e00d"; +} +.icon-presentation:before { + content: "\e00e"; +} +.icon-picture:before { + content: "\e00f"; +} +.icon-pictures:before { + content: "\e010"; +} +.icon-video:before { + content: "\e011"; +} +.icon-camera:before { + content: "\e012"; +} +.icon-printer:before { + content: "\e013"; +} +.icon-toolbox:before { + content: "\e014"; +} +.icon-briefcase:before { + content: "\e015"; +} +.icon-wallet:before { + content: "\e016"; +} +.icon-gift:before { + content: "\e017"; +} +.icon-bargraph:before { + content: "\e018"; +} +.icon-grid:before { + content: "\e019"; +} +.icon-expand:before { + content: "\e01a"; +} +.icon-focus:before { + content: "\e01b"; +} +.icon-edit:before { + content: "\e01c"; +} +.icon-adjustments:before { + content: "\e01d"; +} +.icon-ribbon:before { + content: "\e01e"; +} +.icon-hourglass:before { + content: "\e01f"; +} +.icon-lock:before { + content: "\e020"; +} +.icon-megaphone:before { + content: "\e021"; +} +.icon-shield:before { + content: "\e022"; +} +.icon-trophy:before { + content: "\e023"; +} +.icon-flag:before { + content: "\e024"; +} +.icon-map:before { + content: "\e025"; +} +.icon-puzzle:before { + content: "\e026"; +} +.icon-basket:before { + content: "\e027"; +} +.icon-envelope:before { + content: "\e028"; +} +.icon-streetsign:before { + content: "\e029"; +} +.icon-telescope:before { + content: "\e02a"; +} +.icon-gears:before { + content: "\e02b"; +} +.icon-key:before { + content: "\e02c"; +} +.icon-paperclip:before { + content: "\e02d"; +} +.icon-attachment:before { + content: "\e02e"; +} +.icon-pricetags:before { + content: "\e02f"; +} +.icon-lightbulb:before { + content: "\e030"; +} +.icon-layers:before { + content: "\e031"; +} +.icon-pencil:before { + content: "\e032"; +} +.icon-tools:before { + content: "\e033"; +} +.icon-tools-2:before { + content: "\e034"; +} +.icon-scissors:before { + content: "\e035"; +} +.icon-paintbrush:before { + content: "\e036"; +} +.icon-magnifying-glass:before { + content: "\e037"; +} +.icon-circle-compass:before { + content: "\e038"; +} +.icon-linegraph:before { + content: "\e039"; +} +.icon-mic:before { + content: "\e03a"; +} +.icon-strategy:before { + content: "\e03b"; +} +.icon-beaker:before { + content: "\e03c"; +} +.icon-caution:before { + content: "\e03d"; +} +.icon-recycle:before { + content: "\e03e"; +} +.icon-anchor:before { + content: "\e03f"; +} +.icon-profile-male:before { + content: "\e040"; +} +.icon-profile-female:before { + content: "\e041"; +} +.icon-bike:before { + content: "\e042"; +} +.icon-wine:before { + content: "\e043"; +} +.icon-hotairballoon:before { + content: "\e044"; +} +.icon-globe:before { + content: "\e045"; +} +.icon-genius:before { + content: "\e046"; +} +.icon-map-pin:before { + content: "\e047"; +} +.icon-dial:before { + content: "\e048"; +} +.icon-chat:before { + content: "\e049"; +} +.icon-heart:before { + content: "\e04a"; +} +.icon-cloud:before { + content: "\e04b"; +} +.icon-upload:before { + content: "\e04c"; +} +.icon-download:before { + content: "\e04d"; +} +.icon-target:before { + content: "\e04e"; +} +.icon-hazardous:before { + content: "\e04f"; +} +.icon-piechart:before { + content: "\e050"; +} +.icon-speedometer:before { + content: "\e051"; +} +.icon-global:before { + content: "\e052"; +} +.icon-compass:before { + content: "\e053"; +} +.icon-lifesaver:before { + content: "\e054"; +} +.icon-clock:before { + content: "\e055"; +} +.icon-aperture:before { + content: "\e056"; +} +.icon-quote:before { + content: "\e057"; +} +.icon-scope:before { + content: "\e058"; +} +.icon-alarmclock:before { + content: "\e059"; +} +.icon-refresh:before { + content: "\e05a"; +} +.icon-happy:before { + content: "\e05b"; +} +.icon-sad:before { + content: "\e05c"; +} +.icon-facebook:before { + content: "\e05d"; +} +.icon-twitter:before { + content: "\e05e"; +} +.icon-googleplus:before { + content: "\e05f"; +} +.icon-rss:before { + content: "\e060"; +} +.icon-tumblr:before { + content: "\e061"; +} +.icon-linkedin:before { + content: "\e062"; +} +.icon-dribbble:before { + content: "\e063"; +} diff --git a/atlas/static/custom/custom.css.sample b/atlas/static/custom/custom.css.sample new file mode 100644 index 00000000..07486362 --- /dev/null +++ b/atlas/static/custom/custom.css.sample @@ -0,0 +1,7 @@ +/* Insert your custom override CSS in this file */ + +:root { + --main-color: #82c91e; + --second-color: #649b18; + --map-maille-border-color: "black"; +} \ No newline at end of file diff --git a/static/custom/glossaire.json.sample b/atlas/static/custom/glossaire.json.sample similarity index 100% rename from static/custom/glossaire.json.sample rename to atlas/static/custom/glossaire.json.sample diff --git a/static/images/sample.favicon.ico b/atlas/static/custom/images/favicon.ico similarity index 100% rename from static/images/sample.favicon.ico rename to atlas/static/custom/images/favicon.ico diff --git a/static/custom/images/sample.accueil-intro.jpg b/atlas/static/custom/images/sample.accueil-intro.jpg similarity index 100% rename from static/custom/images/sample.accueil-intro.jpg rename to atlas/static/custom/images/sample.accueil-intro.jpg diff --git a/static/custom/images/sample.logo-structure.png b/atlas/static/custom/images/sample.logo-structure.png similarity index 100% rename from static/custom/images/sample.logo-structure.png rename to atlas/static/custom/images/sample.logo-structure.png diff --git a/static/custom/images/sample.logo_patrimonial.png b/atlas/static/custom/images/sample.logo_patrimonial.png similarity index 100% rename from static/custom/images/sample.logo_patrimonial.png rename to atlas/static/custom/images/sample.logo_patrimonial.png diff --git a/static/custom/maps-custom.js.sample b/atlas/static/custom/maps-custom.js.sample similarity index 83% rename from static/custom/maps-custom.js.sample rename to atlas/static/custom/maps-custom.js.sample index 3b340279..64e89d5e 100644 --- a/static/custom/maps-custom.js.sample +++ b/atlas/static/custom/maps-custom.js.sample @@ -4,8 +4,7 @@ var pointDisplayOptionsFicheEspece = (pointDisplayOptionsFicheCommuneHome = func feature ) { return { - fillColor: feature.properties.diffusion_level < 5 ? "#3A9D23" : "#3388ff", - color: feature.properties.diffusion_level < 5 ? "#3A9D23" : "#3388ff" + color: feature.properties.diffusion_level < 5 || feature.properties.diffusion_level != null ? "#3388ff": "#3A9D23" }; }); diff --git a/atlas/static/custom/templates/bandeaulogoshome.html.sample b/atlas/static/custom/templates/bandeaulogoshome.html.sample new file mode 100644 index 00000000..173e19a3 --- /dev/null +++ b/atlas/static/custom/templates/bandeaulogoshome.html.sample @@ -0,0 +1,63 @@ + + +
+
+

{{ _('home.partners') }}

+
+
+
+ +
+
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+
+
+
+ + + diff --git a/static/custom/templates/credits.html.sample b/atlas/static/custom/templates/credits.html.sample similarity index 53% rename from static/custom/templates/credits.html.sample rename to atlas/static/custom/templates/credits.html.sample index 2710f34b..4d63c164 100644 --- a/static/custom/templates/credits.html.sample +++ b/atlas/static/custom/templates/credits.html.sample @@ -1,16 +1,13 @@ - - \ No newline at end of file + diff --git a/atlas/static/custom/templates/footer.html.sample b/atlas/static/custom/templates/footer.html.sample new file mode 100644 index 00000000..fa2be43c --- /dev/null +++ b/atlas/static/custom/templates/footer.html.sample @@ -0,0 +1,84 @@ + + {{ _('home') }} | + {{ configuration.STRUCTURE }} | + {{ _('credits') }} | + {{ _('legal') }} + + +
+ + {{ configuration.NOM_APPLICATION }} - {{ _('atlas.fauna.flora') }} {{ _('from1') }} {{ configuration.STRUCTURE }}, 2021 +
+ {{ _('powered.by') }} GeoNature-atlas, {{ _('developed.by') }} + {{ _('ecrins.national.park') }} +
+
+ + + + + +{% if configuration.ID_GOOGLE_ANALYTICS != "UA-xxxxxxx-xx" %} + + +{% endif %} + + diff --git a/atlas/static/custom/templates/introduction.html.sample b/atlas/static/custom/templates/introduction.html.sample new file mode 100644 index 00000000..8c5d9da1 --- /dev/null +++ b/atlas/static/custom/templates/introduction.html.sample @@ -0,0 +1,25 @@ +
+
+
+
+

+ {{ _('welcome.message') }} + {{ _('from1') }} {{ _('from2') }} {{ _('from3') }} {{ _('from4') }} {{ _('from5') }} + {{configuration.STRUCTURE}} +

+

+ {{ _('home.introduction.message') }} +

+

+ En + savoir plus +

+
+
+ {{configuration.NOM_APPLICATION}} +
+
+
+ +
diff --git a/static/custom/templates/mentions-legales.html.sample b/atlas/static/custom/templates/mentions-legales.html.sample similarity index 98% rename from static/custom/templates/mentions-legales.html.sample rename to atlas/static/custom/templates/mentions-legales.html.sample index 78d75b52..dae15e37 100644 --- a/static/custom/templates/mentions-legales.html.sample +++ b/atlas/static/custom/templates/mentions-legales.html.sample @@ -1,8 +1,3 @@ - -