Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support backend validation for multiple data models #619

Closed
wants to merge 25 commits into from

Conversation

ivarne
Copy link
Member

@ivarne ivarne commented Apr 27, 2024

New type record struct ModelBinding to replace the current use of string in a way that ensures a structured way of storing the optional reference to an extra data model.

public readonly record struct ModelBinding
{
    public ModelBinding()
    {
        DataType = "default";
    }

    public required string Field { get; init; }
    public string DataType { get; init; }

    // Consider removing the implicit operator. It makes the existing tests work with much less changes.
    public static implicit operator ModelBinding(string field)
    {
        return new ModelBinding { Field = field };
    }
}

I'm pretty happy about the minimal changes required for everything but the actual lookup of data to work.

Remaining work

  • Make the IDataModel implementations aware of multiple data models so that lookups don't just ignore them.
    • Decide on a caching approach. Should we use a caching version IDataClient registered as scoped in DI? Or do we have other options?

Related Issue(s)

Verification

  • Your code builds clean without any errors or warnings
  • Manual testing done (required)
  • Relevant automated test added (if you find this hard, leave it and we'll help out)
  • All tests run green

Documentation

  • User documentation is updated with a separate linked PR in altinn-studio-docs. (if applicable)

@ivarne ivarne requested a review from martinothamar April 27, 2024 19:47
@martinothamar
Copy link
Contributor

Do you want me to review the whole thing or just the ModelBinding struct for now?

Would ModelBindingSelector be a better name? To me that sounds more specific and clear about what it does/is used for, in that it represents the selection/query into the datamodel. I think the structure is good. It doesn't really validate the inputs, so in terms of correctness I don't think it improves the "primitive obsession" situation that we have (I don't think there are any good ways to actually do that well atm anyway)

I think we have to have the implicit operator since we're doing string -> ModelBinding change on IDataModelAccessor? Re not having breaking changes

@ivarne
Copy link
Member Author

ivarne commented Apr 29, 2024

Do you want me to review the whole thing or just the ModelBinding struct for now?

I want any feedback I can get, apart from "Hi! I made a test app, how do I test this new behavior", because it isn't complete yet.

@ivarne ivarne force-pushed the feat/multiple-data-models branch 2 times, most recently from 9b19779 to a02524d Compare May 25, 2024 18:02
[Route("{org}/{app}/api/validationconfig/{id}")]
public ActionResult GetValidationConfiguration(string org, string app, string id)
[Route("{org}/{app}/api/validationconfig/{dataTypeId}")]
public ActionResult GetValidationConfiguration(string org, string app, string dataTypeId)

Check failure

Code scanning / SonarCloud

ModelState.IsValid should be called in controller actions

<!--SONAR_ISSUE_KEY:AY-xAXfXLsHLlXI5hr1K-->ModelState.IsValid should be checked in controller actions. <p>See more on <a href="https://sonarcloud.io/project/issues?id=Altinn_app-lib-dotnet&issues=AY-xAXfXLsHLlXI5hr1K&open=AY-xAXfXLsHLlXI5hr1K&pullRequest=619">SonarCloud</a></p>
@ivarne ivarne force-pushed the feat/multiple-data-models branch from 3c74bf2 to edb533c Compare June 1, 2024 11:51
@ivarne ivarne changed the title WIP: Add ModelBinding type to encapsulate the possibility of referring to different models Support backend validation for multiple data models Jun 2, 2024
src/Altinn.App.Core/Implementation/AppResourcesSI.cs Dismissed Show dismissed Hide dismissed
src/Altinn.App.Core/Implementation/AppResourcesSI.cs Dismissed Show dismissed Hide dismissed
@ivarne ivarne force-pushed the feat/multiple-data-models branch from 93009a5 to 34863a2 Compare June 2, 2024 13:17
@ivarne ivarne force-pushed the feat/multiple-data-models branch from 0ba8554 to 7fd0b18 Compare June 2, 2024 14:49
@ivarne
Copy link
Member Author

ivarne commented Jun 2, 2024

@martinothamar @bjosttveit

Da virker alle eksisterende tester og det er egentlig klart for review. Har ikke begynt å skrive tester for den nye funksjonaliteten ennå.

Har inkludert ["language"] expression funksjonen, fordi den krever mer context var naturlig å legge med når jeg uansett måtte endre LayoutEvaluatorStateInitializer.Init funksjonen for å støtte flere modeller.

@ivarne ivarne force-pushed the feat/multiple-data-models branch from f07f795 to 0161134 Compare June 2, 2024 15:34
Copy link
Contributor

@martinothamar martinothamar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made one pass, will make another once tests come in 😄

src/Altinn.App.Core/Models/Expressions/Expression.cs Outdated Show resolved Hide resolved
}

/// <inheritdoc />
public DataElement DefaultDataElement { get; }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the usecase for this being public?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing! (at least that I can think of)

I needed it to get the data element for ValidationIssue, but it did not solve the full issue, so I added LayoutEvaluatorState.GetDataElement(ModelBinding field) instead. I should probably just move that implementation into the data model and not rely on the _instanceContext

Also enforce that CachedFormDataAccessor verifies that it only runs in one request (to protect against any cross user leakage)
Comment on lines 128 to 137
catch (Exception e)
{
using var jsonDocument = JsonDocument.Parse(data);

testCase.Name = jsonDocument.RootElement.GetProperty("name").GetString();
testCase.ExpectsFailure = jsonDocument.RootElement.TryGetProperty("expectsFailure", out var expectsFailure)
? expectsFailure.GetString()
: null;
testCase.ParsingException = e;
}

Check notice

Code scanning / CodeQL

Generic catch clause Note test

Generic catch clause.
var deserializedObject = JsonSerializer.Deserialize(jsonString, dynamicType);
var numbersProperty = dynamicType.GetProperty("Numbers")!.GetValue(deserializedObject) as List<double?>;

numbersProperty.Should().NotBeNull();

Check warning

Code scanning / CodeQL

Dereferenced variable may be null Warning test

Variable
numbersProperty
may be null at this access because of
this
assignment.
Copy link
Contributor

@martinothamar martinothamar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally LGTM 👍

In terms of public vs internal - I don't think we should add more public members unless we have an agreed-upon use-case with consumers already. Didn't seem like that was the case, so according to previous discussions I think those should be made internal. If not, I think we should revisit the decision in the team, so we have shared understanding

Copy link

sonarcloud bot commented Jun 19, 2024

Comment on lines +117 to +126
var validationIssue = new ValidationIssue
{
Field = resolvedField.Field,
DataElementId = resolvedField.DataType,
Severity = validation.Severity ?? ValidationIssueSeverity.Error,
CustomTextKey = validation.Message,
Code = validation.Message,
Source = ValidationIssueSources.Expression,
};
validationIssues.Add(validationIssue);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The DataElementId should not be set to the data type id?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, that would not be very helpful. Good catch!

Copy link

sonarcloud bot commented Aug 15, 2024

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants