PnX-SI / GeoNature-citizen

Portail web d'inventaire citoyen de la biodiversité à destination du grand public
https://pnx-si.github.io/GeoNature-citizen/
GNU Affero General Public License v3.0
20 stars 29 forks source link

[Installation] - Retour d'experience et problème validation observation #273

Closed lepontois closed 8 months ago

lepontois commented 3 years ago

Bonjour,

Il y a quelque temps j'avais réalisé une installation en locale de GN-Citizen pour évaluer son adéquation avec nos besoins.

Je passe à présent à une "vraie" installation et je tenais à vous partager ce retour d'expérience.

L'installation est réalisée sur un ubuntu server 18.04 à partir de la pre-release 0.99.3

J'ai suivi la doc d'installation manuelle (car l'automatique m'avait posé problème en locale) sans faire d'installation de taxhub vu qu'il est déjà en place sur un serveur GeoNature indépendant. J'ai tout de même intégré en base le schema taxonomie car même si GN-Citizen peut interoger un taxhub distant, j'ai cru comprendre qu'il avait tout de même besoin de ce schéma.

J'ai donc déroulé la précédure d'installation mais je rencontre un bug en fin de course lorsque j'exécute : sudo supervisorctl reload : cannot import name 'get_jwt' Pour résoudre ça, j'ai dû mettre à jour flask_jwt_extended : pip install flask_jwt_extended --upgrade

J'ai également mis à jour flask_admin car j'ai eu une erreur similaire pour l'import de secure_filename : pip install flask_admin --upgrade

A l'étape de création de la structure de la base de données

export FLASK_ENV=development; export FLASK_DEBUG=1; export FLASK_RUN_PORT=5002; export FLASK_APP=wsgi;
python -m flask run --host=0.0.0.0)

seules quelques tables ont été créés :

Le schéma gnc_core n'est donc pas complet et aucune table dans les schémas gnc_obstax et gnc_sites.

CRITICAL in routes: [get_observations] Error: (psycopg2.errors.UndefinedTable) relation "gnc_obstax.t_obstax" does not exist
LINE 3: FROM gnc_obstax.t_obstax) AS anon_1

Grâce à ma précédente installation locale, j'ai pu reconstruire la base. (voir script sql à la fin de ce message)

A partir de ce point l'interface web est accessible (quelque souci avec iptables qui doit autoriser l'intégralité des OUTPUT : iptables -A OUTPUT -j ACCEPT)

Sauf que ! Et oui, ce n'est pas fini, et pour le coup, je suis à sec... Lorsque je suis sur le formulaire de saisie d'une observation, impossible de valider l'observation. Le bouton reste toujours "disable" malgré que les champs soient complétés. (si je retire disable via la console, le formulaire s'enregistre bien mais pas très commode :) ). Il semble donc qu'il y ait quelque chose dans le contrôle du formulaire qui bloque. C'était déjà le cas sur mon instance locale mais j'ai pas trop insisté.

Pour ceux qui souhaitent tester, le serveur n'étant pas encore associé à un nom de domaine, il vous faut ajouter dans votre fichier hosts l'entrée suivante : 188.165.58.13 obs-citoyenne.pyrenees-parcnational.fr et du coup, vous aurez accès à cette instance de citizen par http://obs-citoyenne.pyrenees-parcnational.fr

En espérant que vous aurez des éléments à m'apporter et que ce retour d'expérience pourra être utile à d'autres. Merci !

Annexe : Script sql permettant de reconstruire la base (ce script ajoute les tables manquantes uniquement)

CREATE SEQUENCE gnc_core.bib_groups_id_group_seq
    INCREMENT 1
    START 1
    MINVALUE 1
    MAXVALUE 2147483647
    CACHE 1;

CREATE SEQUENCE gnc_core.cor_users_groups_id_user_right_seq
    INCREMENT 1
    START 1
    MINVALUE 1
    MAXVALUE 2147483647
    CACHE 1;

CREATE SEQUENCE gnc_core.t_revoked_tokens_id_seq
    INCREMENT 1
    START 1
    MINVALUE 1
    MAXVALUE 2147483647
    CACHE 1;

CREATE SEQUENCE gnc_core.t_users_id_user_seq
    INCREMENT 1
    START 1
    MINVALUE 1
    MAXVALUE 2147483647
    CACHE 1;

CREATE SEQUENCE gnc_core.t_users_rights_id_user_right_seq
    INCREMENT 1
    START 1
    MINVALUE 1
    MAXVALUE 2147483647
    CACHE 1;

CREATE TABLE gnc_core.bib_groups
(
    id_group integer NOT NULL DEFAULT nextval('gnc_core.bib_groups_id_group_seq'::regclass),
    category character varying(150) COLLATE pg_catalog."default",
    "group" character varying(150) COLLATE pg_catalog."default" NOT NULL,
    CONSTRAINT bib_groups_pkey PRIMARY KEY (id_group)
)
;

CREATE TABLE gnc_core.t_users
(
    id_user integer NOT NULL DEFAULT nextval('gnc_core.t_users_id_user_seq'::regclass),
    name character varying(100) COLLATE pg_catalog."default" NOT NULL,
    surname character varying(100) COLLATE pg_catalog."default" NOT NULL,
    username character varying(120) COLLATE pg_catalog."default" NOT NULL,
    password character varying(120) COLLATE pg_catalog."default" NOT NULL,
    email character varying(150) COLLATE pg_catalog."default" NOT NULL,
    phone character varying(15) COLLATE pg_catalog."default",
    organism character varying(100) COLLATE pg_catalog."default",
    avatar character varying COLLATE pg_catalog."default",
    active boolean,
    admin boolean,
    timestamp_create timestamp without time zone NOT NULL,
    timestamp_update timestamp without time zone,
    CONSTRAINT t_users_pkey PRIMARY KEY (id_user),
    CONSTRAINT t_users_email_key UNIQUE (email),
    CONSTRAINT t_users_username_key UNIQUE (username)
)
;

CREATE TABLE gnc_core.t_users_rights
(
    id_user_right integer NOT NULL DEFAULT nextval('gnc_core.t_users_rights_id_user_right_seq'::regclass),
    id_user integer NOT NULL,
    id_module integer,
    id_program integer,
    "right" character varying(150) COLLATE pg_catalog."default" NOT NULL,
    "create" boolean,
    read boolean,
    update boolean,
    delete boolean,
    timestamp_create timestamp without time zone NOT NULL,
    timestamp_update timestamp without time zone,
    CONSTRAINT t_users_rights_pkey PRIMARY KEY (id_user_right),
    CONSTRAINT t_users_rights_id_module_fkey FOREIGN KEY (id_module)
        REFERENCES gnc_core.t_modules (id_module) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE NO ACTION,
    CONSTRAINT t_users_rights_id_program_fkey FOREIGN KEY (id_program)
        REFERENCES gnc_core.t_programs (id_program) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE CASCADE,
    CONSTRAINT t_users_rights_id_user_fkey FOREIGN KEY (id_user)
        REFERENCES gnc_core.t_users (id_user) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE NO ACTION
)
;

CREATE TABLE gnc_core.cor_users_groups
(
    id_user_right integer NOT NULL DEFAULT nextval('gnc_core.cor_users_groups_id_user_right_seq'::regclass),
    id_user integer NOT NULL,
    id_group integer NOT NULL,
    timestamp_create timestamp without time zone NOT NULL,
    timestamp_update timestamp without time zone,
    CONSTRAINT cor_users_groups_pkey PRIMARY KEY (id_user_right),
    CONSTRAINT cor_users_groups_id_group_fkey FOREIGN KEY (id_group)
        REFERENCES gnc_core.bib_groups (id_group) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE CASCADE,
    CONSTRAINT cor_users_groups_id_user_fkey FOREIGN KEY (id_user)
        REFERENCES gnc_core.t_users (id_user) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE NO ACTION
)
;

CREATE TABLE gnc_core.t_revoked_tokens
(
    id integer NOT NULL DEFAULT nextval('gnc_core.t_revoked_tokens_id_seq'::regclass),
    jti character varying(120) COLLATE pg_catalog."default",
    CONSTRAINT t_revoked_tokens_pkey PRIMARY KEY (id)
)
;

CREATE SEQUENCE gnc_obstax.cor_obstax_media_id_match_seq
    INCREMENT 1
    START 1
    MINVALUE 1
    MAXVALUE 2147483647
    CACHE 1;

CREATE SEQUENCE gnc_obstax.t_obstax_id_observation_seq
    INCREMENT 1
    START 1
    MINVALUE 1
    MAXVALUE 2147483647
    CACHE 1;

    CREATE TABLE gnc_obstax.t_obstax
(
    id_observation integer NOT NULL DEFAULT nextval('gnc_obstax.t_obstax_id_observation_seq'::regclass),
    uuid_sinp uuid NOT NULL,
    id_program integer NOT NULL,
    cd_nom integer NOT NULL,
    date date NOT NULL,
    count integer,
    comment character varying(300) COLLATE pg_catalog."default",
    municipality integer,
    geom geometry(Point,4326),
    json_data jsonb,
    id_role integer,
    obs_txt character varying(150) COLLATE pg_catalog."default",
    email character varying(150) COLLATE pg_catalog."default",
    timestamp_create timestamp without time zone NOT NULL,
    timestamp_update timestamp without time zone,
    CONSTRAINT t_obstax_pkey PRIMARY KEY (id_observation),
    CONSTRAINT t_obstax_uuid_sinp_key UNIQUE (uuid_sinp),
    CONSTRAINT t_obstax_cd_nom_fkey FOREIGN KEY (cd_nom)
        REFERENCES taxonomie.taxref (cd_nom) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE NO ACTION,
    CONSTRAINT t_obstax_id_program_fkey FOREIGN KEY (id_program)
        REFERENCES gnc_core.t_programs (id_program) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE SET NULL,
    CONSTRAINT t_obstax_id_role_fkey FOREIGN KEY (id_role)
        REFERENCES gnc_core.t_users (id_user) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE CASCADE,
    CONSTRAINT t_obstax_municipality_fkey FOREIGN KEY (municipality)
        REFERENCES ref_geo.l_areas (id_area) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE NO ACTION
);

CREATE TABLE gnc_obstax.cor_obstax_media
(
    id_match integer NOT NULL DEFAULT nextval('gnc_obstax.cor_obstax_media_id_match_seq'::regclass),
    id_data_source integer NOT NULL,
    id_media integer NOT NULL,
    timestamp_create timestamp without time zone NOT NULL,
    timestamp_update timestamp without time zone,
    CONSTRAINT cor_obstax_media_pkey PRIMARY KEY (id_match),
    CONSTRAINT cor_obstax_media_id_data_source_fkey FOREIGN KEY (id_data_source)
        REFERENCES gnc_obstax.t_obstax (id_observation) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE CASCADE,
    CONSTRAINT cor_obstax_media_id_media_fkey FOREIGN KEY (id_media)
        REFERENCES gnc_core.t_medias (id_media) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE CASCADE
)
;

CREATE SEQUENCE gnc_sites.cor_program_typesites_id_cor_program_typesite_seq
    INCREMENT 1
    START 1
    MINVALUE 1
    MAXVALUE 2147483647
    CACHE 1;

CREATE SEQUENCE gnc_sites.cor_sites_obstax_id_cor_site_obstax_seq
    INCREMENT 1
    START 1
    MINVALUE 1
    MAXVALUE 2147483647
    CACHE 1;

CREATE SEQUENCE gnc_sites.cor_visites_media_id_match_seq
    INCREMENT 1
    START 1
    MINVALUE 1
    MAXVALUE 2147483647
    CACHE 1;

CREATE SEQUENCE gnc_sites.t_sites_id_site_seq
    INCREMENT 1
    START 1
    MINVALUE 1
    MAXVALUE 2147483647
    CACHE 1;

CREATE SEQUENCE gnc_sites.t_typesite_id_typesite_seq
    INCREMENT 1
    START 1
    MINVALUE 1
    MAXVALUE 2147483647
    CACHE 1;

CREATE SEQUENCE gnc_sites.t_visit_id_visit_seq
    INCREMENT 1
    START 1
    MINVALUE 1
    MAXVALUE 2147483647
    CACHE 1;

CREATE TABLE gnc_sites.t_typesite
(
    id_typesite integer NOT NULL DEFAULT nextval('gnc_sites.t_typesite_id_typesite_seq'::regclass),
    category character varying(200) COLLATE pg_catalog."default",
    type character varying(200) COLLATE pg_catalog."default",
    id_form integer,
    pictogram text COLLATE pg_catalog."default",
    timestamp_create timestamp without time zone NOT NULL,
    timestamp_update timestamp without time zone,
    CONSTRAINT t_typesite_pkey PRIMARY KEY (id_typesite),
    CONSTRAINT t_typesite_id_form_fkey FOREIGN KEY (id_form)
        REFERENCES gnc_core.t_custom_form (id_form) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE NO ACTION
)
;

CREATE TABLE gnc_sites.t_sites
(
    id_site integer NOT NULL DEFAULT nextval('gnc_sites.t_sites_id_site_seq'::regclass),
    uuid_sinp uuid NOT NULL,
    id_program integer NOT NULL,
    name character varying(250) COLLATE pg_catalog."default",
    id_type integer NOT NULL,
    geom geometry(Point,4326),
    timestamp_create timestamp without time zone NOT NULL,
    timestamp_update timestamp without time zone,
    id_role integer,
    obs_txt character varying(150) COLLATE pg_catalog."default",
    email character varying(150) COLLATE pg_catalog."default",
    CONSTRAINT t_sites_pkey PRIMARY KEY (id_site),
    CONSTRAINT t_sites_uuid_sinp_key UNIQUE (uuid_sinp),
    CONSTRAINT t_sites_id_program_fkey FOREIGN KEY (id_program)
        REFERENCES gnc_core.t_programs (id_program) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE NO ACTION,
    CONSTRAINT t_sites_id_role_fkey FOREIGN KEY (id_role)
        REFERENCES gnc_core.t_users (id_user) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE CASCADE,
    CONSTRAINT t_sites_id_type_fkey FOREIGN KEY (id_type)
        REFERENCES gnc_sites.t_typesite (id_typesite) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE NO ACTION
)
;

CREATE TABLE gnc_sites.t_visit
(
    id_visit integer NOT NULL DEFAULT nextval('gnc_sites.t_visit_id_visit_seq'::regclass),
    id_site integer,
    date date,
    json_data jsonb,
    timestamp_create timestamp without time zone NOT NULL,
    timestamp_update timestamp without time zone,
    id_role integer,
    obs_txt character varying(150) COLLATE pg_catalog."default",
    email character varying(150) COLLATE pg_catalog."default",
    CONSTRAINT t_visit_pkey PRIMARY KEY (id_visit),
    CONSTRAINT t_visit_id_role_fkey FOREIGN KEY (id_role)
        REFERENCES gnc_core.t_users (id_user) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE CASCADE,
    CONSTRAINT t_visit_id_site_fkey FOREIGN KEY (id_site)
        REFERENCES gnc_sites.t_sites (id_site) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE CASCADE
)
;

CREATE TABLE gnc_sites.cor_program_typesites
(
    id_cor_program_typesite integer NOT NULL DEFAULT nextval('gnc_sites.cor_program_typesites_id_cor_program_typesite_seq'::regclass),
    id_program integer,
    id_typesite integer,
    timestamp_create timestamp without time zone NOT NULL,
    timestamp_update timestamp without time zone,
    CONSTRAINT cor_program_typesites_pkey PRIMARY KEY (id_cor_program_typesite),
    CONSTRAINT cor_program_typesites_id_program_fkey FOREIGN KEY (id_program)
        REFERENCES gnc_core.t_programs (id_program) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE CASCADE,
    CONSTRAINT cor_program_typesites_id_typesite_fkey FOREIGN KEY (id_typesite)
        REFERENCES gnc_sites.t_typesite (id_typesite) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE CASCADE
)
;

CREATE TABLE gnc_sites.cor_sites_obstax
(
    id_cor_site_obstax integer NOT NULL DEFAULT nextval('gnc_sites.cor_sites_obstax_id_cor_site_obstax_seq'::regclass),
    id_site integer NOT NULL,
    id_obstax integer NOT NULL,
    timestamp_create timestamp without time zone NOT NULL,
    timestamp_update timestamp without time zone,
    CONSTRAINT cor_sites_obstax_pkey PRIMARY KEY (id_cor_site_obstax),
    CONSTRAINT cor_sites_obstax_id_obstax_fkey FOREIGN KEY (id_obstax)
        REFERENCES gnc_obstax.t_obstax (id_observation) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE SET NULL,
    CONSTRAINT cor_sites_obstax_id_site_fkey FOREIGN KEY (id_site)
        REFERENCES gnc_sites.t_sites (id_site) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE SET NULL
)
;

CREATE TABLE gnc_sites.cor_visites_media
(
    id_match integer NOT NULL DEFAULT nextval('gnc_sites.cor_visites_media_id_match_seq'::regclass),
    id_data_source integer NOT NULL,
    id_media integer NOT NULL,
    timestamp_create timestamp without time zone NOT NULL,
    timestamp_update timestamp without time zone,
    CONSTRAINT cor_visites_media_pkey PRIMARY KEY (id_match),
    CONSTRAINT cor_visites_media_id_data_source_fkey FOREIGN KEY (id_data_source)
        REFERENCES gnc_sites.t_visit (id_visit) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE CASCADE,
    CONSTRAINT cor_visites_media_id_media_fkey FOREIGN KEY (id_media)
        REFERENCES gnc_core.t_medias (id_media) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE CASCADE
)
;

INSERT INTO gnc_sites.t_typesite (category, type, id_form, pictogram, timestamp_create, timestamp_update)
VALUES ('default_site', 'NR', NULL, NULL, '2021-04-01 09:47:24.176533', '2021-04-01 09:47:24.176538');

GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA gnc_core TO obs_citoyenne_dbadmin;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA gnc_obstax TO obs_citoyenne_dbadmin;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA gnc_sites TO obs_citoyenne_dbadmin;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO obs_citoyenne_dbadmin;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA ref_geo TO obs_citoyenne_dbadmin;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA taxonomie TO obs_citoyenne_dbadmin;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA taxonomie TO obs_citoyenne_dbadmin;
lepontois commented 3 years ago

J'ai mis le doigt sur le problème et j'ai trouvé la solution adaptée.

ça se passe en ligne 22 du formValidators : https://github.com/PnX-SI/GeoNature-citizen/blob/master/frontend/src/app/programs/observations/form/formValidators.ts L'expression régulière permettant de contrôler la validité des coordonées n'accepte que des valeurs positive. Mes tests étant de l'autre côté du méridien, il me retournait toujours false.

Voici ma proposition de correction (c'est celle que j'applique sur mon instance) :

[...]
const validGeometry = /Point\([-]?\d{1,3}(|\.\d{1,7}),(|\s)[-]?\d{1,3}(|\.\d{1,7})\)$/.test(
[...]

Merci de reporter ce correctif dans les sources (je ne suis pas relié au git)

camillemonchicourt commented 3 years ago

Concernant l'installation packagée, on a identifié plusieurs soucis dans la 0.99.3, et ils ont été réglé dans la branche "develop" avec notamment de nombreuses mises à jour de dépendances. Voir le ticket sur le sujet. En attente de la release de la 0.99.4 qui inclut ces corrections.

Merci pour ton retour détaillé d'installation.

camillemonchicourt commented 3 years ago

Le ticket d'il y a quelques jours sur les problèmes de version des dépendances que tu as rencontré : https://github.com/PnX-SI/GeoNature-citizen/issues/271

Concernant les coordonnées négatives, en effet ça a été remonté dans un ticket il y a quelques semaines, avec la correction du code à appliquer (https://github.com/PnX-SI/GeoNature-citizen/issues/261).

Merci et bon weekend.

mvergez commented 3 years ago

Bonjour,

J'ai rencontré le même problème que toi @lepontois sur la route get_observations de citizen (branche 0.99.4-dev) sur debian 10. Merci pour ton script sql qui m'a bien aidé sur le moment.

Pour tenter de corriger ce bug, je viens d'essayer de déplacer le bloc suivant : https://github.com/PnX-SI/GeoNature-citizen/blob/699067934ba5e700b5d47a3f77e99bc6c0354d0e/backend/server.py#L95-L97 Juste avant la ligne https://github.com/PnX-SI/GeoNature-citizen/blob/699067934ba5e700b5d47a3f77e99bc6c0354d0e/backend/server.py#L141 Exactement comme c'était fait sur le tag 0.99.1 : https://github.com/PnX-SI/GeoNature-citizen/blob/5caf4545ca6f188396bdc6cd6db9a1cf49def386/backend/server.py#L155-L160

Et cela semble résoudre le problème chez moi. Toutes les tables sont bien créées et je n'ai pas d'erreur lorsque j'accède à l'URL de citizen.

@camillemonchicourt, as-tu rencontré le même problème lors de tes tests ?

Je vais essayer de regarder quel commit a déplacé ce bloc de code. Je vous tiens au courant.

mvergez commented 3 years ago

Cela semble être dû à ce commit : https://github.com/PnX-SI/GeoNature-citizen/commit/54a249021f293e988c3cdcf8967d8151ca969b50#diff-7aad1d8a7c12e554a56640e331270f5fc84e24f6f937b35b69eb83766b2318ed Mais il n'y a pas l'air d'y avoir plus d'explications.

camillemonchicourt commented 8 months ago

A priori corrigé dans la version 1.0.0