Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/main/java/org/tdl/vireo/model/CustomActionDefinition.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,15 @@ public CustomActionDefinition(String label, Boolean isStudentVisible) {
isStudentVisible(isStudentVisible);
}

/**
* @return the position
*/
@Override
@JsonView(Views.SubmissionList.class)
public Long getPosition() {
return super.getPosition();
}
Comment thread
cstarcher marked this conversation as resolved.
Comment thread
cstarcher marked this conversation as resolved.

/**
* @return the label
*/
Expand Down
2 changes: 1 addition & 1 deletion src/main/webapp/app/views/admin/list.html
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ <h1>List ETDs</h1>
<span ng-class="{'glyphicon glyphicon-remove-circle' : $first}" ng-click="addRowFilter($parent.$index, row)"></span>
<span ng-if="col.title() !== 'Custom Actions'">{{displaySubmissionProperty(row, col)}}</span>
<span ng-if="col.title() === 'Custom Actions'">
<span ng-repeat="ca in row.customActionValues">
<span ng-repeat="ca in row.customActionValues | orderBy:'definition.position'">
<input ng-checked="{{ca.value}}" type="checkbox" disabled> {{getCustomActionLabelById(ca.definition.id)}}</input>
<br/>
</span>
Expand Down
69 changes: 69 additions & 0 deletions src/test/java/org/tdl/vireo/model/CustomActionDefinitionTest.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
package org.tdl.vireo.model;

import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.util.stream.Stream;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.provider.Arguments;
import org.mockito.InjectMocks;
import org.tdl.vireo.model.response.Views;

import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;

public class CustomActionDefinitionTest extends AbstractModelCustomMethodTest<CustomActionDefinition> {

Expand Down Expand Up @@ -43,4 +54,62 @@ private static Stream<Arguments> getParameterMethodStream() {
);
}

/**
* Regression test for GitHub issue #2104.
*
* Verifies that {@code CustomActionDefinition.position} is included in the
* JSON output when serialized under {@link Views.SubmissionList} (and its
* sub-views such as {@link Views.SubmissionIndividualActionLogs}).
*
* The application sets {@code jackson.mapper.default-view-inclusion: false},
* so any field without a matching {@code @JsonView} annotation is silently
* excluded when a view is active. The fix overrides {@code getPosition()} in
* {@code CustomActionDefinition} with {@code @JsonView(Views.SubmissionList.class)}.
* Removing that annotation will cause this test to fail.
*/
@Test
public void testPositionSerializedInSubmissionListView() throws Exception {
// Configure ObjectMapper to match application.yml: default-view-inclusion: false
ObjectMapper mapper = JsonMapper.builder()
.disable(MapperFeature.DEFAULT_VIEW_INCLUSION)
.build();

CustomActionDefinition definition = new CustomActionDefinition("Test action", true);
definition.setPosition(3L);

// Serialize under Views.SubmissionList — the view used by /submission/query
String json = mapper.writerWithView(Views.SubmissionList.class).writeValueAsString(definition);
ObjectNode node = (ObjectNode) mapper.readTree(json);

assertNotNull(node.get("position"),
"position must be present in SubmissionList view JSON; " +
"ensure getPosition() in CustomActionDefinition is annotated with @JsonView(Views.SubmissionList.class)");
assertTrue(node.get("position").isNumber(),
"position must be a numeric value in SubmissionList view JSON");
}

/**
* Verifies that {@code position} is also included when serialized under the
* {@link Views.SubmissionIndividualActionLogs} view used by the admin
* {@code GET /submission/get-one/{id}} endpoint, since that view extends
* {@link Views.SubmissionList}.
*/
@Test
public void testPositionSerializedInSubmissionIndividualActionLogsView() throws Exception {
ObjectMapper mapper = JsonMapper.builder()
.disable(MapperFeature.DEFAULT_VIEW_INCLUSION)
.build();

CustomActionDefinition definition = new CustomActionDefinition("Test action", true);
definition.setPosition(5L);

String json = mapper.writerWithView(Views.SubmissionIndividualActionLogs.class).writeValueAsString(definition);
ObjectNode node = (ObjectNode) mapper.readTree(json);

assertNotNull(node.get("position"),
"position must be present in SubmissionIndividualActionLogs view JSON");
assertTrue(node.get("position").isNumber(),
"position must be a numeric value in SubmissionIndividualActionLogs view JSON");
}

}
Loading