post functionality - #60
Conversation
WalkthroughThe changes update the post creation flow in the application. The Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant ProfileView (HTML)
participant ProfilePostController
participant PostService
User->>ProfileView (HTML): Fill and submit post form (content + optional image)
ProfileView (HTML)->>ProfilePostController: HTTP POST /profile/{username}/post (form data)
ProfilePostController->>ProfilePostController: Verify user matches username
alt User mismatch
ProfilePostController-->>ProfileView (HTML): Redirect with error flash message
else User match
ProfilePostController->>PostService: createPost(dto, file, username)
alt Exception thrown
ProfilePostController-->>ProfileView (HTML): Redirect with error flash message
else Success
ProfilePostController-->>ProfileView (HTML): Redirect with success flash message
end
end
Possibly related PRs
Suggested reviewers
Poem
✨ Finishing Touches
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
src/main/java/se/storkforge/petconnect/controller/PostController.java (1)
55-60: Update Javadoc to reflect removed image upload functionalityThe Javadoc still mentions "optional image" but the method implementation no longer accepts image uploads.
- /** - * Creates a new post with optional image. - * - * @param dto The post content data - * @param principal The currently authenticated user - * @return The created post DTO - */ + /** + * Creates a new post. + * + * @param dto The post content data + * @param principal The currently authenticated user + * @return The created post DTO + */
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
src/main/java/se/storkforge/petconnect/controller/PostController.java(1 hunks)src/main/java/se/storkforge/petconnect/service/UserService.java(1 hunks)src/main/resources/application.properties(1 hunks)src/main/resources/templates/profileView.html(5 hunks)
🔇 Additional comments (5)
src/main/java/se/storkforge/petconnect/service/UserService.java (1)
219-222: Good utility method addition!The new
getUserByUsernameOrThrowmethod provides a convenient way to retrieve a user with built-in exception handling, following the same pattern as the existinggetOrElseThrowmethod for ID-based retrieval.src/main/resources/templates/profileView.html (4)
2-2: LGTM - Cleaner HTML declarationThe removal of the unused
secnamespace simplifies the HTML declaration.
14-38: UI improvements look goodThe profile section has been cleaned up with better organization and centering. The positioning of the premium badge and edit profile button provides a more consistent visual hierarchy.
46-46: Good security and permission improvements
- The visibility condition for pet controls has been simplified to only require
isOwner- Added CSRF token to the pet deletion form for better security
Also applies to: 69-73
83-123: Great UI addition for posts functionalityThe post display section is well-implemented with proper handling of:
- Conditional display based on user permissions
- Image display when available
- Formatted timestamps
- Empty state message
| spring.servlet.multipart.max-file-size=5MB | ||
| spring.servlet.multipart.max-request-size=5MB |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
Verify file upload configuration consistency
You've configured multipart upload limits, but the POST controller in PostController.java no longer accepts multipart file uploads (changed from @RequestPart to @RequestBody). This seems inconsistent with the form in profileView.html which still uses enctype="multipart/form-data".
🏁 Script executed:
#!/bin/bash
# Check which controllers are using multipart file uploads
echo "Searching for controllers that use MultipartFile..."
rg -A 3 "MultipartFile" --type java src/main/java/se/storkforge/petconnect/controller
echo "Checking for endpoints that handle the form post action..."
rg -A 5 "/profile/.+/post" --type javaLength of output: 4941
🏁 Script executed:
#!/bin/bash
set -e
echo "=== PostController.java: @PostMapping methods ==="
rg -n -C3 "@PostMapping" --type java src/main/java/se/storkforge/petconnect/controller/PostController.java || true
echo
echo "=== PostController.java: MultipartFile usage ==="
rg -n "MultipartFile" --type java src/main/java/se/storkforge/petconnect/controller/PostController.java || true
echo
echo "=== PostController.java: @RequestPart or consumes attribute ==="
rg -n "@RequestPart\|consumes" -C2 --type java src/main/java/se/storkforge/petconnect/controller/PostController.java || true
echo
echo "=== HTML templates: forms and enctype ==="
rg -n "profileView" -A2 --type html src/main/resources || true
rg -n "enctype" --type html src/main/resources || trueLength of output: 1734
🏁 Script executed:
#!/bin/bash
set -e
echo "=== PostController.java: Class and RequestMapping ==="
sed -n '1,50p' src/main/java/se/storkforge/petconnect/controller/PostController.java
echo
echo "=== profileView.html: Form details around enctype ==="
sed -n '80,120p' src/main/resources/templates/profileView.htmlLength of output: 3777
🏁 Script executed:
#!/bin/bash
set -e
echo "=== Searching for @GetMapping or @PostMapping on '/profile' endpoints ==="
rg -n '@GetMapping.*"/profile' -C2 --type java src/main/java/se/storkforge/petconnect/controller || true
rg -n '@PostMapping.*"/profile' -C2 --type java src/main/java/se/storkforge/petconnect/controller || true
echo
echo "=== Searching all Java sources for '/profile/' usages ==="
rg -n "/profile/" -C3 --type java src/main/java/se/storkforge/petconnect || trueLength of output: 5539
Align multipart form and controller handling for profile posts
The form in src/main/resources/templates/profileView.html still uses enctype="multipart/form-data" with a <input type="file" name="file"> and posts to /profile/{username}/post, but there’s no matching controller method to consume that file (and PostController under /api/posts now only accepts JSON via @RequestBody). Please address this mismatch by choosing one of the following:
- Remove the file input and
enctype="multipart/form-data"from the profile post form if file attachments are no longer supported. - Or implement a web‐controller endpoint for
/profile/{username}/postthat accepts aMultipartFile(e.g. via@RequestParam("file") MultipartFile fileor@RequestPart) and delegates to your service. - Alternatively, point the form at your JSON API (
/api/posts) and submit via AJAX if you intend to keep file uploads in the REST layer.
Additionally, clean up the unused MultipartFile import in src/main/java/se/storkforge/petconnect/controller/PostController.java.
• src/main/resources/templates/profileView.html – update/remove file input and enctype or add corresponding handler
• src/main/java/se/storkforge/petconnect/controller/PostController.java – remove unused import org.springframework.web.multipart.MultipartFile;
| <form th:action="@{/profile/{username}/post(username=${user.username})}" | ||
| method="post" | ||
| enctype="multipart/form-data" | ||
| class="mb-4"> | ||
| <input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" /> | ||
| <textarea name="content" rows="3" class="w-full p-2 border rounded mb-2" | ||
| placeholder="Write something..."></textarea> | ||
| <input type="file" name="file" accept="image/*" class="mb-2 block"> | ||
| <button type="submit" | ||
| class="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 transition"> | ||
| Post | ||
| </button> | ||
| </form> |
There was a problem hiding this comment.
Form submission is incompatible with the updated PostController
The form is configured to submit multipart form data with a file upload, but the PostController.java endpoint has been modified to only accept JSON data (@RequestBody) and not multipart files.
You have two options to resolve this:
- Revert the PostController changes to support multipart upload
- Create a separate controller method to handle this form submission with the correct URL pattern:
@Controller
@RequestMapping("/profile")
public class ProfileController {
private final PostService postService;
@PostMapping("/{username}/post")
public String createPost(@PathVariable String username,
@RequestParam("content") String content,
@RequestParam(value = "file", required = false) MultipartFile file,
Principal principal,
RedirectAttributes redirectAttributes) {
// Create post with file
// ...
return "redirect:/profile/" + username;
}
}There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (3)
src/main/java/se/storkforge/petconnect/controller/ProfilePostController.java (3)
24-31: Consider adding file validation at the controller level.While you may have validation in the service layer, adding some preliminary checks in the controller would provide faster feedback to users.
@PostMapping("/profile/{username}/post") @PreAuthorize("hasAnyRole('ROLE_USER', 'ROLE_PREMIUM')") public String handleProfilePost(@PathVariable String username, @RequestParam("content") String content, @RequestParam(value = "file", required = false) MultipartFile file, Principal principal, RedirectAttributes redirectAttributes, HttpServletRequest request) { + // Validate file if present + if (file != null && !file.isEmpty()) { + if (file.getSize() > 5 * 1024 * 1024) { // 5MB limit + redirectAttributes.addFlashAttribute("error", "File size should not exceed 5MB."); + return "redirect:/profile/" + username; + } + + String contentType = file.getContentType(); + if (contentType == null || !contentType.startsWith("image/")) { + redirectAttributes.addFlashAttribute("error", "Only image files are allowed."); + return "redirect:/profile/" + username; + } + }
1-14: Consider adding missing imports for enhanced validation.If you implement the suggested validation improvements, don't forget to add the required imports.
import org.springframework.validation.BindingResult; import jakarta.validation.Valid; import org.springframework.web.bind.annotation.ModelAttribute; import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory;
15-22: Consider adding logging.Adding logging would help with debugging and tracking application behavior.
@Controller public class ProfilePostController { + private static final Logger logger = LoggerFactory.getLogger(ProfilePostController.class); + private final PostService postService; public ProfilePostController(PostService postService) { + logger.debug("Initializing ProfilePostController"); this.postService = postService; }Don't forget to add:
import org.slf4j.Logger; import org.slf4j.LoggerFactory;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/main/java/se/storkforge/petconnect/controller/PostController.java(1 hunks)src/main/java/se/storkforge/petconnect/controller/ProfilePostController.java(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- src/main/java/se/storkforge/petconnect/controller/PostController.java
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/main/java/se/storkforge/petconnect/controller/ProfilePostController.java (1)
src/main/java/se/storkforge/petconnect/dto/PostInputDTO.java (1)
PostInputDTO(6-19)
🔇 Additional comments (2)
src/main/java/se/storkforge/petconnect/controller/ProfilePostController.java (2)
32-35: Good authorization check.The authorization check to prevent users from posting as someone else is well-implemented.
24-25: Appropriate role-based access control.Good use of
@PreAuthorizeto restrict access to authenticated users with specific roles.
| try { | ||
| postService.createPost(dto, file, username); | ||
| redirectAttributes.addFlashAttribute("success", "Post created successfully!"); | ||
| } catch (IllegalArgumentException e) { | ||
| redirectAttributes.addFlashAttribute("error", e.getMessage()); | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Improve exception handling to catch more specific exceptions.
Currently, only IllegalArgumentException is caught, which might not cover all potential errors.
try {
postService.createPost(dto, file, username);
redirectAttributes.addFlashAttribute("success", "Post created successfully!");
-} catch (IllegalArgumentException e) {
+} catch (IllegalArgumentException e) {
+ redirectAttributes.addFlashAttribute("error", e.getMessage());
+} catch (IOException e) {
+ redirectAttributes.addFlashAttribute("error", "Error processing file upload: " + e.getMessage());
+ // Consider logging the exception here
+} catch (Exception e) {
+ // Log the unexpected exception
+ redirectAttributes.addFlashAttribute("error", "An unexpected error occurred. Please try again later.");
}Make sure to add:
import java.io.IOException;| @Controller | ||
| public class ProfilePostController { | ||
|
|
||
| private final PostService postService; | ||
|
|
||
| public ProfilePostController(PostService postService) { | ||
| this.postService = postService; | ||
| } | ||
|
|
||
| @PostMapping("/profile/{username}/post") | ||
| @PreAuthorize("hasAnyRole('ROLE_USER', 'ROLE_PREMIUM')") | ||
| public String handleProfilePost(@PathVariable String username, | ||
| @RequestParam("content") String content, | ||
| @RequestParam(value = "file", required = false) MultipartFile file, | ||
| Principal principal, | ||
| RedirectAttributes redirectAttributes, | ||
| HttpServletRequest request) { | ||
| if (!principal.getName().equals(username)) { | ||
| redirectAttributes.addFlashAttribute("error", "You are not allowed to post as another user."); | ||
| return "redirect:/profile/" + username; | ||
| } | ||
|
|
||
| PostInputDTO dto = new PostInputDTO(); | ||
| dto.setContent(content); | ||
|
|
||
| try { | ||
| postService.createPost(dto, file, username); | ||
| redirectAttributes.addFlashAttribute("success", "Post created successfully!"); | ||
| } catch (IllegalArgumentException e) { | ||
| redirectAttributes.addFlashAttribute("error", e.getMessage()); | ||
| } | ||
|
|
||
| return "redirect:/profile/" + username; | ||
| } | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Overall structure looks good, but input validation could be improved.
The controller effectively handles post submissions for user profiles with proper authorization checks. However, there's an opportunity to improve input validation.
Consider adding @Valid annotation to validate the PostInputDTO and handle validation errors:
@PostMapping("/profile/{username}/post")
@PreAuthorize("hasAnyRole('ROLE_USER', 'ROLE_PREMIUM')")
public String handleProfilePost(@PathVariable String username,
- @RequestParam("content") String content,
+ @Valid @ModelAttribute PostInputDTO dto,
+ BindingResult bindingResult,
@RequestParam(value = "file", required = false) MultipartFile file,
Principal principal,
RedirectAttributes redirectAttributes,
HttpServletRequest request) {
if (!principal.getName().equals(username)) {
redirectAttributes.addFlashAttribute("error", "You are not allowed to post as another user.");
return "redirect:/profile/" + username;
}
+ if (bindingResult.hasErrors()) {
+ redirectAttributes.addFlashAttribute("error",
+ bindingResult.getFieldError().getDefaultMessage());
+ return "redirect:/profile/" + username;
+ }
- PostInputDTO dto = new PostInputDTO();
- dto.setContent(content);
try {
postService.createPost(dto, file, username);
redirectAttributes.addFlashAttribute("success", "Post created successfully!");
} catch (IllegalArgumentException e) {
redirectAttributes.addFlashAttribute("error", e.getMessage());
}
return "redirect:/profile/" + username;
}Don't forget to add these imports:
import org.springframework.validation.BindingResult;
import jakarta.validation.Valid;
import org.springframework.web.bind.annotation.ModelAttribute;
connects shared story backend to frontend
Summary by CodeRabbit