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

fix multipart requests on entities with a non-default initialized @Version property #2045

Merged
merged 2 commits into from
Jul 20, 2024
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ public ResponseEntity<RepresentationModel<?>> createEntityAndContent(RootResourc

String store = pathSegments[1];

boolean entitySaved = false;
// Save the entity and re-assign the result to savedEntity, so that it exists in the repository before content is added to it.
savedEntity = repoInvokerFactory.getInvokerFor(domainType).invokeSave(savedEntity);

StoreInfo info = this.stores.getStore(Store.class, StoreUtils.withStorePath(store));
if (info != null) {
Expand All @@ -114,15 +115,9 @@ public ResponseEntity<RepresentationModel<?>> createEntityAndContent(RootResourc

headers.setContentLength(file.getSize());
service.setContent(req, resp, headers, new InputStreamResourceWithFilename(file.getInputStream(), file.getOriginalFilename()), MediaType.parseMediaType(file.getContentType()), storeResource);
entitySaved = true;
}
}

// if we didn't find store info, or there weren't any files in the request, the entity has not been saved yet
if (!entitySaved) {
repoInvokerFactory.getInvokerFor(domainType).invokeSave(savedEntity);
}

Optional<PersistentEntityResource> resource = Optional.ofNullable(assembler.toFullResource(savedEntity));
headers.setContentType(new MediaType("application", "hal+json"));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public class TestEntity4 implements ContentEntity {
public @ContentId UUID contentId;
public @ContentLength Long len;
public @MimeType String mimeType;
private @Version Long version;
private @Version Long version = 0L;
private @CreatedDate Date createdDate;
private @LastModifiedDate Date modifiedDate;
private @OriginalFileName String originalFileName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,70 @@ public class ContentEntityRestEndpointsIT {
});
});

Context("given a multipart/form POST to an entity with a non-default initialized @Version property (#Issue 2044)", () -> {
Context("with content", () -> {
It("should create a new entity and its content and respond with a 201 Created", () -> {

String newContent = "This is some new content";

MockMultipartFile file = new MockMultipartFile("content", "filename.txt", "text/plain",
newContent.getBytes());

// POST the entity
MockHttpServletResponse response = mvc.perform(multipart("/testEntity4s")
.file(file)
.param("name", "foo")
.param("title", "bar"))

.andExpect(status().isCreated())
.andReturn().getResponse();

String location = response.getHeader("Location");

// assert that the entity exists
Optional<TestEntity4> fetchedEntity = repo4.findById(
Long.valueOf(StringUtils.substringAfterLast(location, "/")));
assertThat(fetchedEntity.get().getName(), is("foo"));
assertThat(fetchedEntity.get().getTitle(), is("bar"));
assertThat(fetchedEntity.get().getContentId(), is(not(nullValue())));
assertThat(fetchedEntity.get().getLen(), is(file.getSize()));
assertThat(fetchedEntity.get().getOriginalFileName(), is(file.getOriginalFilename()));

// assert that the content now exists
response = mvc.perform(get(location)
.accept("text/plain"))
.andExpect(status().isOk())
.andReturn().getResponse();

assertThat(response.getContentAsString(), is(newContent));
});
});

Context("without content", () -> {
It("should create a new entity and respond with a 201 Created", () -> {

// POST the entity
MockHttpServletResponse response = mvc.perform(multipart("/testEntity4s")
.param("name", "foo")
.param("title", "bar"))

.andExpect(status().isCreated())
.andReturn().getResponse();

String location = response.getHeader("Location");

// assert that the entity exists
Optional<TestEntity4> fetchedEntity = repo4.findById(
Long.valueOf(StringUtils.substringAfterLast(location, "/")));
assertThat(fetchedEntity.get().getName(), is("foo"));
assertThat(fetchedEntity.get().getTitle(), is("bar"));
assertThat(fetchedEntity.get().getContentId(), is(nullValue()));
assertThat(fetchedEntity.get().getLen(), is(nullValue()));
assertThat(fetchedEntity.get().getOriginalFileName(), is(nullValue()));
});
});
});

Context("given an entity with a single correlated content property", () -> {
BeforeEach(() -> {
testEntity9 = repo9.save(new TestEntity9());
Expand Down Expand Up @@ -303,7 +367,7 @@ public class ContentEntityRestEndpointsIT {
});
});

Context("given a a multipart/form POST to an entity with a single correlated content property", () -> {
Context("given a multipart/form POST to an entity with a single correlated content property", () -> {
It("should create a new entity and its content and respond with a 201 Created", () -> {
// assert content does not exist
String newContent = "This is some new content";
Expand Down Expand Up @@ -336,7 +400,7 @@ public class ContentEntityRestEndpointsIT {
});
});

Context("given a a multipart/form POST that doesn't include the content property", () -> {
Context("given a multipart/form POST that doesn't include the content property", () -> {
It("should create a new entity with no content and respond with a 201 Created", () -> {

var testEntity4Id = repo4.save(new TestEntity4()).getId();
Expand Down Expand Up @@ -366,7 +430,7 @@ public class ContentEntityRestEndpointsIT {
});
});

Context("given a a multipart/form POST to an entity with a mapped content property", () -> {
Context("given a multipart/form POST to an entity with a mapped content property", () -> {
It("should create a new entity and its content and respond with a 201 Created", () -> {
// assert content does not exist
String newContent = "This is some new content";
Expand Down
Loading