From d051153e8ee985c7c4fd73dc864a9d18f7139fd6 Mon Sep 17 00:00:00 2001 From: Arthur Araujo Date: Tue, 28 Oct 2025 18:11:06 -0300 Subject: [PATCH 1/5] Add visualized field and add an endpoint to get form by id --- .idea/compiler.xml | 3 ++- .../api/controller/FormController.java | 16 ++++++++++++++++ .../com/arnar/openforms/api/database/Form.java | 5 +++++ .../openforms/api/response/SimplifiedForm.java | 4 +++- src/main/resources/data.sql | 5 ++++- src/main/resources/schema.sql | 1 + .../api/test/controller/FormControllerTest.java | 17 +++++++++++++++++ 7 files changed, 48 insertions(+), 3 deletions(-) diff --git a/.idea/compiler.xml b/.idea/compiler.xml index 63a7679..0018852 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -8,12 +8,13 @@ - + + diff --git a/src/main/java/br/com/arnar/openforms/api/controller/FormController.java b/src/main/java/br/com/arnar/openforms/api/controller/FormController.java index c626305..0a01f20 100644 --- a/src/main/java/br/com/arnar/openforms/api/controller/FormController.java +++ b/src/main/java/br/com/arnar/openforms/api/controller/FormController.java @@ -20,8 +20,10 @@ import br.com.arnar.openforms.api.OpenFormsApplication; import br.com.arnar.openforms.api.database.Form; import br.com.arnar.openforms.api.database.User; +import br.com.arnar.openforms.api.exception.NoSuchEntryException; import br.com.arnar.openforms.api.request.form.FormSendRequest; import br.com.arnar.openforms.api.response.SimpleFormsResponse; +import br.com.arnar.openforms.api.response.SimplifiedForm; import br.com.arnar.openforms.api.service.FormServiceInterface; import br.com.arnar.openforms.api.service.UserServiceInterface; import jakarta.servlet.http.HttpServletRequest; @@ -60,4 +62,18 @@ public ResponseEntity listAllForMe(HttpServletRequest request) { return ok(new SimpleFormsResponse(forms)); } + + @Transactional + @GetMapping(path = "/me/{id}", produces = "application/json") + public ResponseEntity getByIdForMe(@PathVariable Long id, HttpServletRequest request) { + User me = userService.getMe(request); + + Form forms = service.getById(id); + + if (!forms.getOwner().getId().equals(me.getId())) { + throw new NoSuchEntryException("Unable to find a form with this id"); + } + + return ok(new SimplifiedForm(forms)); + } } diff --git a/src/main/java/br/com/arnar/openforms/api/database/Form.java b/src/main/java/br/com/arnar/openforms/api/database/Form.java index 7711836..13f07af 100644 --- a/src/main/java/br/com/arnar/openforms/api/database/Form.java +++ b/src/main/java/br/com/arnar/openforms/api/database/Form.java @@ -19,6 +19,7 @@ import jakarta.persistence.*; import lombok.Data; +import org.hibernate.annotations.ColumnDefault; import org.hibernate.annotations.OnDelete; import org.hibernate.annotations.OnDeleteAction; @@ -47,4 +48,8 @@ public class Form { @Column(name = "message") private String message; + + @ColumnDefault("false") + @Column(name = "visualized") + private Boolean visualized; } diff --git a/src/main/java/br/com/arnar/openforms/api/response/SimplifiedForm.java b/src/main/java/br/com/arnar/openforms/api/response/SimplifiedForm.java index f071ba2..f49e048 100644 --- a/src/main/java/br/com/arnar/openforms/api/response/SimplifiedForm.java +++ b/src/main/java/br/com/arnar/openforms/api/response/SimplifiedForm.java @@ -23,12 +23,13 @@ @Getter @Setter -class SimplifiedForm { +public class SimplifiedForm { public Long id; public String name; public String phoneNumber; public String email; public String message; + public Boolean visualized; public SimplifiedForm(Form form) { setId(form.getId()); @@ -36,5 +37,6 @@ public SimplifiedForm(Form form) { setPhoneNumber(form.getPhoneNumber()); setEmail(form.getEmail()); setMessage(form.getMessage()); + setVisualized(form.getVisualized()); } } \ No newline at end of file diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql index a1038cc..f8fb80c 100644 --- a/src/main/resources/data.sql +++ b/src/main/resources/data.sql @@ -17,4 +17,7 @@ INSERT INTO member (username, email, password) VALUES ('mock.admin', 'mock.admin@gmail.com', '061cf224cffe1951e32ffaa1c414544a9dae01c216e0cd89aa5d496cb45a968202d755be85db9c1f8a565a7b4846c2cba027b81cdfb159b023b2ee3a94da7de9'); INSERT INTO form (owner_id, name, phone_number, email, message) VALUES - (3, 'Mock User Client', '5521921232132', 'mock.disposable@gmail.com', 'hello there'); \ No newline at end of file + (3, 'Mock User Client', '5521921232132', 'mock.disposable@gmail.com', 'hello there'); + +INSERT INTO form (owner_id, name, phone_number, email, message) VALUES + (2, 'Conta 2 Client', '5521921232132', 'mock.disposable@gmail.com', 'hello there'); \ No newline at end of file diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index a897a38..71fb2f0 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -15,6 +15,7 @@ CREATE TABLE form ( phone_number varchar(128), email varchar(128), message varchar(1280), + visualized boolean DEFAULT false, PRIMARY KEY (id), CONSTRAINT fk_owner_id FOREIGN KEY(owner_id) REFERENCES member(id) ); \ No newline at end of file diff --git a/src/test/java/br/com/arnar/openforms/api/test/controller/FormControllerTest.java b/src/test/java/br/com/arnar/openforms/api/test/controller/FormControllerTest.java index b081ae2..a5e7fa3 100644 --- a/src/test/java/br/com/arnar/openforms/api/test/controller/FormControllerTest.java +++ b/src/test/java/br/com/arnar/openforms/api/test/controller/FormControllerTest.java @@ -68,4 +68,21 @@ void getAllForMeNotAuthenticated() throws Exception { req.get("/form/me/listAll").andExpect(status().isForbidden()); } + @Test + void getByIdForMe() throws Exception { + String jwt = MockValues.getUserJwt(mockMvc); + req.get("/form/me/1", jwt).andExpect(status().isOk()); + } + + @Test + void getByIdExistentButNotMine() throws Exception { + String jwt = MockValues.getUserJwt(mockMvc); + req.get("/form/me/2", jwt).andExpect(status().isNotFound()); + } + + @Test + void getByIdInexistent() throws Exception { + String jwt = MockValues.getUserJwt(mockMvc); + req.get("/form/me/23", jwt).andExpect(status().isNotFound()); + } } From 35aa8cc09f96150ead2466438def2f9100279b45 Mon Sep 17 00:00:00 2001 From: Arthur Araujo Date: Tue, 28 Oct 2025 18:30:12 -0300 Subject: [PATCH 2/5] Implement visualization of forms --- .../api/controller/FormController.java | 17 +++++++++++++++++ .../api/service/FormServiceInterface.java | 1 + .../service/implementation/FormService.java | 5 +++++ .../controller/ControllerTestRequester.java | 11 +++++++++++ .../test/controller/FormControllerTest.java | 18 ++++++++++++++++++ 5 files changed, 52 insertions(+) diff --git a/src/main/java/br/com/arnar/openforms/api/controller/FormController.java b/src/main/java/br/com/arnar/openforms/api/controller/FormController.java index 0a01f20..71fb439 100644 --- a/src/main/java/br/com/arnar/openforms/api/controller/FormController.java +++ b/src/main/java/br/com/arnar/openforms/api/controller/FormController.java @@ -76,4 +76,21 @@ public ResponseEntity getByIdForMe(@PathVariable Long id, HttpServletRequest return ok(new SimplifiedForm(forms)); } + + @Transactional + @PatchMapping(path = "/me/{id}/view") + public ResponseEntity setFormVisualized(@PathVariable Long id, HttpServletRequest request) { + User me = userService.getMe(request); + + Form form = service.getById(id); + + if (!form.getOwner().getId().equals(me.getId())) { + throw new NoSuchEntryException("Unable to find a form with this id"); + } + + form.setVisualized(true); + service.insert(form); + + return ok(new SimplifiedForm(form)); + } } diff --git a/src/main/java/br/com/arnar/openforms/api/service/FormServiceInterface.java b/src/main/java/br/com/arnar/openforms/api/service/FormServiceInterface.java index 619faa8..1ff92e8 100644 --- a/src/main/java/br/com/arnar/openforms/api/service/FormServiceInterface.java +++ b/src/main/java/br/com/arnar/openforms/api/service/FormServiceInterface.java @@ -26,4 +26,5 @@ public interface FormServiceInterface { List
getByOwner(User owner); Form getById(Long id); Form insert(Form entity, Long ownerId); + Form insert(Form entity); } diff --git a/src/main/java/br/com/arnar/openforms/api/service/implementation/FormService.java b/src/main/java/br/com/arnar/openforms/api/service/implementation/FormService.java index 7e02910..d542a6b 100644 --- a/src/main/java/br/com/arnar/openforms/api/service/implementation/FormService.java +++ b/src/main/java/br/com/arnar/openforms/api/service/implementation/FormService.java @@ -74,4 +74,9 @@ public Form insert(Form entity, Long ownerId) { return repository.save(entity); } + + @Override + public Form insert(Form entity) { + return repository.save(entity); + } } diff --git a/src/test/java/br/com/arnar/openforms/api/test/controller/ControllerTestRequester.java b/src/test/java/br/com/arnar/openforms/api/test/controller/ControllerTestRequester.java index 38de1aa..7fcfd58 100644 --- a/src/test/java/br/com/arnar/openforms/api/test/controller/ControllerTestRequester.java +++ b/src/test/java/br/com/arnar/openforms/api/test/controller/ControllerTestRequester.java @@ -117,4 +117,15 @@ public ResultActions post(String url, String content) throws Exception { public ResultActions post(String url, String content, String jwt) throws Exception { return mockMvc.perform(MockMvcRequestBuilders.post(API_PATH + url).header("Authorization", "Bearer " + jwt).contentType("application/json").content(content)); } + + /** + * Performs a PATCH request in an API endpoint that uses JWT authentication. + * @param url The endpoint + * @param jwt The authentication token + * @return The result of the request + * @throws Exception If the request fails + */ + public ResultActions patch(String url, String jwt) throws Exception { + return mockMvc.perform(MockMvcRequestBuilders.patch(API_PATH + url).header("Authorization", "Bearer " + jwt)); + } } diff --git a/src/test/java/br/com/arnar/openforms/api/test/controller/FormControllerTest.java b/src/test/java/br/com/arnar/openforms/api/test/controller/FormControllerTest.java index a5e7fa3..025ec49 100644 --- a/src/test/java/br/com/arnar/openforms/api/test/controller/FormControllerTest.java +++ b/src/test/java/br/com/arnar/openforms/api/test/controller/FormControllerTest.java @@ -85,4 +85,22 @@ void getByIdInexistent() throws Exception { String jwt = MockValues.getUserJwt(mockMvc); req.get("/form/me/23", jwt).andExpect(status().isNotFound()); } + + @Test + void visualize() throws Exception { + String jwt = MockValues.getUserJwt(mockMvc); + req.patch("/form/me/1/view", jwt).andExpect(status().isOk()); + } + + @Test + void visualizeExistentBotNotMine() throws Exception { + String jwt = MockValues.getUserJwt(mockMvc); + req.patch("/form/me/2/view", jwt).andExpect(status().isNotFound()); + } + + @Test + void visualizeInexistent() throws Exception { + String jwt = MockValues.getUserJwt(mockMvc); + req.patch("/form/me/2231/view", jwt).andExpect(status().isNotFound()); + } } From ec57cb5c39f8351aa803b00b49316e8fa7b1e964 Mon Sep 17 00:00:00 2001 From: Arthur Araujo Date: Wed, 29 Oct 2025 04:41:26 -0300 Subject: [PATCH 3/5] Add leading slash to requestMatcher --- .../openforms/api/authentication/SecurityConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/br/com/arnar/openforms/api/authentication/SecurityConfiguration.java b/src/main/java/br/com/arnar/openforms/api/authentication/SecurityConfiguration.java index 35be07e..af8e573 100644 --- a/src/main/java/br/com/arnar/openforms/api/authentication/SecurityConfiguration.java +++ b/src/main/java/br/com/arnar/openforms/api/authentication/SecurityConfiguration.java @@ -48,7 +48,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .requestMatchers("/api/v1/form/me/**").authenticated() .requestMatchers("/api/v1/user/me").authenticated() .requestMatchers("/api/v1/user/me/**").authenticated() - .requestMatchers("**").permitAll()); + .requestMatchers("/**").permitAll()); http.exceptionHandling(handling -> handling.accessDeniedPage("/access-denied")); From 7438704ead6ba31d41fef1ee3e57fa0bd9014e8f Mon Sep 17 00:00:00 2001 From: Arthur Araujo Date: Wed, 29 Oct 2025 07:35:04 -0300 Subject: [PATCH 4/5] Use get instead of patch for visualizing --- .../openforms/api/controller/FormController.java | 2 +- .../api/test/controller/ControllerTestRequester.java | 11 ----------- .../api/test/controller/FormControllerTest.java | 6 +++--- 3 files changed, 4 insertions(+), 15 deletions(-) diff --git a/src/main/java/br/com/arnar/openforms/api/controller/FormController.java b/src/main/java/br/com/arnar/openforms/api/controller/FormController.java index 71fb439..a9272cf 100644 --- a/src/main/java/br/com/arnar/openforms/api/controller/FormController.java +++ b/src/main/java/br/com/arnar/openforms/api/controller/FormController.java @@ -78,7 +78,7 @@ public ResponseEntity getByIdForMe(@PathVariable Long id, HttpServletRequest } @Transactional - @PatchMapping(path = "/me/{id}/view") + @GetMapping(path = "/me/{id}/view") public ResponseEntity setFormVisualized(@PathVariable Long id, HttpServletRequest request) { User me = userService.getMe(request); diff --git a/src/test/java/br/com/arnar/openforms/api/test/controller/ControllerTestRequester.java b/src/test/java/br/com/arnar/openforms/api/test/controller/ControllerTestRequester.java index 7fcfd58..38de1aa 100644 --- a/src/test/java/br/com/arnar/openforms/api/test/controller/ControllerTestRequester.java +++ b/src/test/java/br/com/arnar/openforms/api/test/controller/ControllerTestRequester.java @@ -117,15 +117,4 @@ public ResultActions post(String url, String content) throws Exception { public ResultActions post(String url, String content, String jwt) throws Exception { return mockMvc.perform(MockMvcRequestBuilders.post(API_PATH + url).header("Authorization", "Bearer " + jwt).contentType("application/json").content(content)); } - - /** - * Performs a PATCH request in an API endpoint that uses JWT authentication. - * @param url The endpoint - * @param jwt The authentication token - * @return The result of the request - * @throws Exception If the request fails - */ - public ResultActions patch(String url, String jwt) throws Exception { - return mockMvc.perform(MockMvcRequestBuilders.patch(API_PATH + url).header("Authorization", "Bearer " + jwt)); - } } diff --git a/src/test/java/br/com/arnar/openforms/api/test/controller/FormControllerTest.java b/src/test/java/br/com/arnar/openforms/api/test/controller/FormControllerTest.java index 025ec49..b99f7e6 100644 --- a/src/test/java/br/com/arnar/openforms/api/test/controller/FormControllerTest.java +++ b/src/test/java/br/com/arnar/openforms/api/test/controller/FormControllerTest.java @@ -89,18 +89,18 @@ void getByIdInexistent() throws Exception { @Test void visualize() throws Exception { String jwt = MockValues.getUserJwt(mockMvc); - req.patch("/form/me/1/view", jwt).andExpect(status().isOk()); + req.get("/form/me/1/view", jwt).andExpect(status().isOk()); } @Test void visualizeExistentBotNotMine() throws Exception { String jwt = MockValues.getUserJwt(mockMvc); - req.patch("/form/me/2/view", jwt).andExpect(status().isNotFound()); + req.get("/form/me/2/view", jwt).andExpect(status().isNotFound()); } @Test void visualizeInexistent() throws Exception { String jwt = MockValues.getUserJwt(mockMvc); - req.patch("/form/me/2231/view", jwt).andExpect(status().isNotFound()); + req.get("/form/me/2231/view", jwt).andExpect(status().isNotFound()); } } From dbb34ca67c0143887cdcc8a06c4d3899f83c5805 Mon Sep 17 00:00:00 2001 From: Arthur Araujo Date: Wed, 29 Oct 2025 07:41:50 -0300 Subject: [PATCH 5/5] Skip database update if the form has been already visualized --- .../br/com/arnar/openforms/api/controller/FormController.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/br/com/arnar/openforms/api/controller/FormController.java b/src/main/java/br/com/arnar/openforms/api/controller/FormController.java index a9272cf..3b279f8 100644 --- a/src/main/java/br/com/arnar/openforms/api/controller/FormController.java +++ b/src/main/java/br/com/arnar/openforms/api/controller/FormController.java @@ -88,6 +88,10 @@ public ResponseEntity setFormVisualized(@PathVariable Long id, HttpServletReq throw new NoSuchEntryException("Unable to find a form with this id"); } + if (form.getVisualized()) { + return ok(new SimplifiedForm(form)); + } + form.setVisualized(true); service.insert(form);