Skip to content

Commit

Permalink
Dynamic form : cast defaut value on backend side - fix #3011 #2978
Browse files Browse the repository at this point in the history
  • Loading branch information
TheoLechemia committed May 2, 2024
1 parent 12d5bf8 commit 2c4f957
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 14 deletions.
12 changes: 5 additions & 7 deletions backend/geonature/core/gn_commons/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
from geonature.core.gn_permissions import decorators as permissions
from geonature.core.gn_permissions.decorators import login_required
from geonature.core.gn_permissions.tools import get_scope
from geonature.core.gn_commons.schemas import TAdditionalFieldsSchema
import geonature.core.gn_commons.tasks # noqa: F401

from shapely.geometry import shape
Expand Down Expand Up @@ -194,14 +195,11 @@ def get_additional_fields():
else:
query = query.where(TAdditionalFields.objects.any(code_object=object_code))

return jsonify(
[
d.as_dict(
fields=["bib_nomenclature_type", "modules", "objects", "datasets", "type_widget"]
)
for d in db.session.scalars(query).all()
]
#
schema = TAdditionalFieldsSchema(
only=["bib_nomenclature_type", "modules", "objects", "datasets", "type_widget"], many=True
)
return jsonify(schema.dump(db.session.scalars(query).all()))


@routes.route("/t_mobile_apps", methods=["GET"])
Expand Down
39 changes: 37 additions & 2 deletions backend/geonature/core/gn_commons/schemas.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import logging
from marshmallow import Schema, pre_load, fields, EXCLUDE

from pypnnomenclature.schemas import NomenclatureSchema
from utils_flask_sqla.schema import SmartRelationshipsMixin

from pypnnomenclature.schemas import NomenclatureSchema, BibNomenclaturesTypesSchema

from pypnusershub.schemas import UserSchema
from geonature.utils.env import MA
from geonature.core.gn_commons.models import (
Expand All @@ -10,6 +14,10 @@
TAdditionalFields,
BibWidgets,
)
from geonature.core.gn_permissions.schemas import PermObjectSchema


log = logging.getLogger()


class ModuleSchema(MA.SQLAlchemyAutoSchema):
Expand Down Expand Up @@ -68,11 +76,38 @@ class LabelValueDict(Schema):
value = fields.Raw()


class TAdditionalFieldsSchema(MA.SQLAlchemyAutoSchema):
class CastableField(fields.Field):
"""
A field which tries to cast the value to int or float before returning it.
If the value is not castable, the default value is returned.
"""

def _serialize(self, value, attr, obj, **kwargs):
if value:
try:
value = float(value)
except ValueError:
log.warning("default value not castable to float")
try:
value = int(value)
except ValueError:
log.warning("default value not castable to int")
return value


class TAdditionalFieldsSchema(SmartRelationshipsMixin, MA.SQLAlchemyAutoSchema):
class Meta:
model = TAdditionalFields
load_instance = True

default_value = CastableField(allow_none=True)

modules = fields.Nested(ModuleSchema, many=True, dump_only=True)
objects = fields.Nested(PermObjectSchema, many=True, dump_only=True)
type_widget = fields.Nested(BibWidgetSchema, dump_only=True)
datasets = fields.Nested("DatasetSchema", many=True, dump_only=True)
bib_nomenclature_type = fields.Nested(BibNomenclaturesTypesSchema, dump_only=True)

def load(self, data, *, many=None, **kwargs):

if data["type_widget"].widget_name in (
Expand Down
10 changes: 10 additions & 0 deletions backend/geonature/core/gn_permissions/schemas.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from marshmallow import fields, validates_schema, EXCLUDE

from geonature.utils.env import db, ma
from geonature.core.gn_permissions.models import PermObject


class PermObjectSchema(ma.SQLAlchemyAutoSchema):
class Meta:
model = PermObject
include_fk = True
20 changes: 19 additions & 1 deletion backend/geonature/tests/test_gn_commons.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from flask import url_for, current_app
from geoalchemy2.elements import WKTElement
from PIL import Image
from marshmallow import Schema
from pypnnomenclature.models import BibNomenclaturesTypes, TNomenclatures
from sqlalchemy import func, select, exists
from werkzeug.exceptions import Conflict, Forbidden, NotFound, Unauthorized
Expand All @@ -19,11 +20,16 @@
from geonature.core.gn_permissions.models import PermObject
from geonature.utils.env import db
from geonature.utils.errors import GeoNatureError
from geonature.core.gn_commons.schemas import CastableField

from .fixtures import *
from .utils import set_logged_user


class DummySchema(Schema):
test = CastableField()


@pytest.fixture(scope="function")
def place(users):
place = TPlaces(place_name="test", role=users["user"])
Expand All @@ -46,7 +52,8 @@ def additional_field(app, datasets):
description="une descrption",
quantitative=False,
unity="degré C",
field_values=["la", "li"],
field_values=[100, 200, 300],
default_value="100",
id_widget=1,
modules=[module],
objects=[obj],
Expand Down Expand Up @@ -500,6 +507,9 @@ def test_get_additional_fields(self, datasets, additional_field):
assert "type_widget" in addi_one
assert "bib_nomenclature_type" in addi_one

# test default value has been casted
assert type(addi_one["default_value"]) is int

def test_get_additional_fields_multi_module(self, datasets, additional_field):
response = self.client.get(
url_for("gn_commons.get_additional_fields"),
Expand Down Expand Up @@ -561,6 +571,14 @@ def test_additional_field_admin(self, app, users, module, perm_object):
exists().where(TAdditionalFields.field_name == "pytest_invvalid").select()
)

@pytest.mark.parametrize(
"value, expected_type", [("1", int), ("1.0", float), ("1 ans", str), ("1,0", str)]
)
def test_castable_field(self, value, expected_type):
# test the serialization of a model using CastableField
result = DummySchema().dump({"test": value})
assert type(result["test"] == expected_type)

def test_get_t_mobile_apps(self, mobile_app):
import os, shutil, time
from pathlib import Path
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,7 @@ export class DynamicFormService {
createControl(formDef): AbstractControl {
const formControl = new UntypedFormControl();
const value = formDef.value == undefined ? null : formDef.value;
const defaultValue = parseFloat(value) ? parseFloat(value) : value;

this.setControl(formControl, formDef, defaultValue);
this.setControl(formControl, formDef, value);

return formControl;
}
Expand Down

0 comments on commit 2c4f957

Please sign in to comment.