Skip to content

feat(DataElement): Allow updating filename property#958

Open
henningjensen wants to merge 1 commit into
Altinn:mainfrom
henningjensen:feature/dataelement-update-filename
Open

feat(DataElement): Allow updating filename property#958
henningjensen wants to merge 1 commit into
Altinn:mainfrom
henningjensen:feature/dataelement-update-filename

Conversation

@henningjensen

@henningjensen henningjensen commented Apr 14, 2026

Copy link
Copy Markdown

Description

Include filename in the list of properties that are allowed to be updated on a DataElement. This property is already included in the OverwriteData-method in the DataController, but is missing from the more general Update-method. This allows updating of filenames after initial upload.

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)

Summary by CodeRabbit

  • New Features

    • Data element filenames can now be updated through the metadata update endpoint.
  • Tests

    • Added test case to verify filename updates are properly handled alongside other updatable metadata properties.

@coderabbitai

coderabbitai Bot commented Apr 14, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

The changes add support for updating the /filename property in the DataController's Update endpoint with URL decoding applied. A new test verifies that the filename field is included in the list of updateable properties.

Changes

Cohort / File(s) Summary
Filename Update Support
src/Storage/Controllers/DataController.cs, test/UnitTest/TestingControllers/DataControllerTests.cs
Added /filename property mapping to the DataController Update method, applying URL decoding via HttpUtility.UrlDecode(). New test Update_VerifyListOfAllowedPropertiesToUpdate verifies that filename is included in the allowed properties dictionary passed to the repository update, alongside other metadata properties like /locked, /refs, /tags, and /metadata.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(DataElement): Allow updating filename property' directly summarizes the main change: enabling filename updates via the Update method in DataController.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
test/UnitTest/TestingControllers/DataControllerTests.cs (1)

1168-1179: Strengthen Update test to assert exact property set and filename value

This currently verifies only key presence. To protect the contract better, assert the exact key set and validate the /filename value passed to repository.

Suggested test tightening
+        const string expectedFilename = "name+v1.txt";
         dataRepositoryMock
             .Setup(dr =>
                 dr.Update(
                     It.IsAny<Guid>(),
                     It.IsAny<Guid>(),
                     It.Is<Dictionary<string, object>>(propertyList =>
-                        propertyList.ContainsKey("/locked")
-                        && propertyList.ContainsKey("/refs")
-                        && propertyList.ContainsKey("/references")
-                        && propertyList.ContainsKey("/tags")
-                        && propertyList.ContainsKey("/userDefinedMetadata")
-                        && propertyList.ContainsKey("/metadata")
-                        && propertyList.ContainsKey("/deleteStatus")
-                        && propertyList.ContainsKey("/lastChanged")
-                        && propertyList.ContainsKey("/lastChangedBy")
-                        && propertyList.ContainsKey("/filename")
+                        new HashSet<string>
+                        {
+                            "/locked",
+                            "/refs",
+                            "/references",
+                            "/tags",
+                            "/userDefinedMetadata",
+                            "/metadata",
+                            "/deleteStatus",
+                            "/lastChanged",
+                            "/lastChangedBy",
+                            "/filename",
+                        }.SetEquals(propertyList.Keys)
+                        && Equals(propertyList["/filename"], expectedFilename)
                     ),
                     It.IsAny<CancellationToken>()
                 )
             )
             .ReturnsAsync(new DataElement());
@@
         DataElement dataElementBody = new()
         {
             Id = dataGuid,
             InstanceGuid = instanceGuid,
             DataType = "default",
-            Filename = "filename.txt",
+            Filename = expectedFilename,
         };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/UnitTest/TestingControllers/DataControllerTests.cs` around lines 1168 -
1179, The test's predicate using It.Is<Dictionary<string, object>>(propertyList
=> ...) only checks for presence of keys; update that predicate to assert the
exact key set and the filename value: build the expected key set (the nine keys
shown) and compare propertyList.Keys to that expected set (ensure counts match
and all expected keys are present), and additionally assert
propertyList["/filename"] (or propertyList.GetValueOrDefault("/filename"))
equals the expected filename passed into the controller; modify the
It.Is<Dictionary<string, object>> predicate in DataControllerTests.cs so the
mock verification enforces both exact keys and the exact "/filename" value.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/Storage/Controllers/DataController.cs`:
- Line 777: In the Update handler in DataController, remove the URL-decoding
call around dataElement.Filename (the { "/filename",
HttpUtility.UrlDecode(dataElement.Filename) } entry) so the controller persists
the raw deserialized filename from the JSON body; simply use
dataElement.Filename directly (no HttpUtility.UrlDecode) because ASP.NET already
binds the JSON string and decoding corrupts names with '+' characters.

---

Nitpick comments:
In `@test/UnitTest/TestingControllers/DataControllerTests.cs`:
- Around line 1168-1179: The test's predicate using It.Is<Dictionary<string,
object>>(propertyList => ...) only checks for presence of keys; update that
predicate to assert the exact key set and the filename value: build the expected
key set (the nine keys shown) and compare propertyList.Keys to that expected set
(ensure counts match and all expected keys are present), and additionally assert
propertyList["/filename"] (or propertyList.GetValueOrDefault("/filename"))
equals the expected filename passed into the controller; modify the
It.Is<Dictionary<string, object>> predicate in DataControllerTests.cs so the
mock verification enforces both exact keys and the exact "/filename" value.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8424e11e-2ad7-4ba8-8c7a-cbefc7103353

📥 Commits

Reviewing files that changed from the base of the PR and between a39a501 and 6e56999.

📒 Files selected for processing (2)
  • src/Storage/Controllers/DataController.cs
  • test/UnitTest/TestingControllers/DataControllerTests.cs

{ "/deleteStatus", dataElement.DeleteStatus },
{ "/lastChanged", dataElement.LastChanged },
{ "/lastChangedBy", dataElement.LastChangedBy },
{ "/filename", HttpUtility.UrlDecode(dataElement.Filename) },

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

In .NET, does System.Web.HttpUtility.UrlDecode convert '+' to a space character, and is UrlDecode recommended for values already parsed from JSON request bodies?

💡 Result:

Yes, System.Web.HttpUtility.UrlDecode converts '+' to a space character. No, it is not recommended for values already parsed from JSON request bodies.

Citations:


🏁 Script executed:

# Locate and examine DataController.cs
find . -type f -name "DataController.cs" | head -20

Repository: Altinn/altinn-storage

Length of output: 108


🏁 Script executed:

# Get context around line 777 in DataController.cs
if [ -f "src/Storage/Controllers/DataController.cs" ]; then
  sed -n '765,790p' "src/Storage/Controllers/DataController.cs" | cat -n
fi

Repository: Altinn/altinn-storage

Length of output: 1139


🏁 Script executed:

# Find the Update method signature with context
if [ -f "src/Storage/Controllers/DataController.cs" ]; then
  rg -n "public.*Update" "src/Storage/Controllers/DataController.cs" -A 5
fi

Repository: Altinn/altinn-storage

Length of output: 317


🏁 Script executed:

# Check for [Consumes] attribute on Update method
if [ -f "src/Storage/Controllers/DataController.cs" ]; then
  rg -n "\[Consumes" "src/Storage/Controllers/DataController.cs" -B 5 -A 10
fi

Repository: Altinn/altinn-storage

Length of output: 1621


🏁 Script executed:

# Examine PgDataRepository.cs around line 203-204 to see filename usage
if [ -f "src/Storage/Repository/PgDataRepository.cs" ]; then
  sed -n '195,215p' "src/Storage/Repository/PgDataRepository.cs" | cat -n
fi

Repository: Altinn/altinn-storage

Length of output: 1229


Remove URL-decoding of filename from JSON body in Update

Line 777 applies HttpUtility.UrlDecode to dataElement.Filename, which corrupts filenames containing + characters (e.g., a+b.txt becomes a b.txt). This endpoint declares [Consumes("application/json")] and binds from the request body—the filename is already deserialized as a plain string by ASP.NET model binding and should be persisted as-is.

Proposed fix
-            { "/filename", HttpUtility.UrlDecode(dataElement.Filename) },
+            { "/filename", dataElement.Filename },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{ "/filename", HttpUtility.UrlDecode(dataElement.Filename) },
{ "/filename", dataElement.Filename },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/Storage/Controllers/DataController.cs` at line 777, In the Update handler
in DataController, remove the URL-decoding call around dataElement.Filename (the
{ "/filename", HttpUtility.UrlDecode(dataElement.Filename) } entry) so the
controller persists the raw deserialized filename from the JSON body; simply use
dataElement.Filename directly (no HttpUtility.UrlDecode) because ASP.NET already
binds the JSON string and decoding corrupts names with '+' characters.

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.

1 participant