diff --git a/backend/.env b/backend/.env index def8a16..81da84d 100644 --- a/backend/.env +++ b/backend/.env @@ -1,7 +1,7 @@ DB_NAME=immonator_test -DB_PORT=5433 -DB_HOST=34.135.132.141 -DB_USERNAME=django -DB_PASSWORD=T17HE59a7Xlu2lBgPUQ9rdCPTe4159UNedGhcOvrTu8= +DB_PORT=5432 +DB_HOST=34.155.247.19 +DB_USERNAME=postgres +DB_PASSWORD=3cd70e73f0b73a2411c595f3a2f8cf125ee3937498f82628906ed946e8499a00f7733c6ec588cdff4aec386de3c3cc51d0a166369c6a99e73b9c95d2a1bd115a API_TOKEN=B0uKZQN+qIsLc0yNR/t9xCOkgP6Keg0oarLUiZkO2Mo= - +FLUXIMMO_API_KEY=a diff --git a/backend/app.py b/backend/app.py index 136d3aa..73f4071 100644 --- a/backend/app.py +++ b/backend/app.py @@ -228,6 +228,26 @@ def _load_scraper_params(value: Any) -> Dict[str, Any]: abort(400, description="Field 'params' must be a JSON object or string") +def _validate_property_types(value: str | None) -> str | None: + """Valide que les types de propriétés sont dans la liste autorisée.""" + if value is None or value.strip() == "": + return None + + valid_types = {"immeuble", "appartement", "maison"} + types = [t.strip().lower() for t in value.split(",") if t.strip()] + + invalid_types = [t for t in types if t not in valid_types] + + if invalid_types: + abort( + 400, + description=f"Invalid property types: {', '.join(invalid_types)}. " + f"Allowed values: {', '.join(sorted(valid_types))}" + ) + + return value.strip() + + def build_scraper_params( params: Dict[str, Any], first_seen_days: int | None, @@ -441,6 +461,7 @@ SCRAPER_RESPONSE_FIELDS = ( "max_pages", "enrich_llm", "only_match", + "once", ) SCRAPER_INT_FIELDS = ( @@ -451,6 +472,7 @@ SCRAPER_INT_FIELDS = ( "enabled", "enrich_llm", "only_match", + "once", ) @@ -743,13 +765,19 @@ def create_scraper(): data: Dict[str, Any] = {"id": scraper_id} - for field in ("params", "frequency", "task_name", "property_types"): + for field in ("params", "frequency", "task_name"): if field in payload: value = payload[field] data[field] = ( None if value is None else _parse_string(value, field, allow_empty=True) ) + # Validation spéciale pour property_types + if "property_types" in payload: + value = payload["property_types"] + parsed_value = None if value is None else _parse_string(value, "property_types", allow_empty=True) + data["property_types"] = _validate_property_types(parsed_value) + for field in SCRAPER_INT_FIELDS: if field in payload: value = payload[field] @@ -768,13 +796,19 @@ def update_scraper(scraper_id: str): payload = _get_json_body() updates: Dict[str, Any] = {} - for field in ("params", "frequency", "task_name", "property_types"): + for field in ("params", "frequency", "task_name"): if field in payload: value = payload[field] updates[field] = ( None if value is None else _parse_string(value, field, allow_empty=True) ) + # Validation spéciale pour property_types + if "property_types" in payload: + value = payload["property_types"] + parsed_value = None if value is None else _parse_string(value, "property_types", allow_empty=True) + updates["property_types"] = _validate_property_types(parsed_value) + for field in SCRAPER_INT_FIELDS: if field in payload: value = payload[field] @@ -860,4 +894,4 @@ def count_scraper_properties(): if __name__ == "__main__": - app.run(host="0.0.0.0", port=int(os.getenv("PORT", "8000")), debug=False) + app.run(host="0.0.0.0", port=int(os.getenv("PORT", "3000")), debug=False) diff --git a/frontend/.env b/frontend/.env new file mode 100644 index 0000000..a07e427 --- /dev/null +++ b/frontend/.env @@ -0,0 +1,2 @@ +VITE_API_BASE_URL=http://localhost:3000 +VITE_API_TOKEN=B0uKZQN+qIsLc0yNR/t9xCOkgP6Keg0oarLUiZkO2Mo= diff --git a/frontend/src/components/schema-builder/SchemaFieldRenderer.tsx b/frontend/src/components/schema-builder/SchemaFieldRenderer.tsx index b41c60c..008481d 100644 --- a/frontend/src/components/schema-builder/SchemaFieldRenderer.tsx +++ b/frontend/src/components/schema-builder/SchemaFieldRenderer.tsx @@ -112,6 +112,15 @@ function renderEnum( ) { const error = getFirstError(errorMap, path); + // Helper function to get value and label from enum option + const getOptionValue = (option: string | { value: string; label: string }) => { + return typeof option === "string" ? option : option.value; + }; + + const getOptionLabel = (option: string | { value: string; label: string }) => { + return typeof option === "string" ? option : option.label; + }; + if (schema.multiple) { const current = Array.isArray(value) ? (value as string[]) : []; @@ -120,20 +129,22 @@ function renderEnum( {schema.label ?? getLabelFromPath(path)}
{schema.options.map((option) => { - const checked = current.includes(option); + const optionValue = getOptionValue(option); + const optionLabel = getOptionLabel(option); + const checked = current.includes(optionValue); return ( -