Skip to content

post functionality - #60

Open
MarcGust wants to merge 2 commits into
mainfrom
post_functionality
Open

post functionality#60
MarcGust wants to merge 2 commits into
mainfrom
post_functionality

Conversation

@MarcGust

@MarcGust MarcGust commented Apr 22, 2025

Copy link
Copy Markdown
Contributor

connects shared story backend to frontend

Summary by CodeRabbit

  • New Features
    • Added the ability for profile owners to create and display posts, including support for text and image uploads, directly from the profile page.
    • Introduced a new endpoint for handling profile post submissions with role-based access control.
  • Improvements
    • Enhanced the profile view layout for better clarity and consistency.
    • Simplified UI logic for displaying pet and post management options.
  • Security
    • Added CSRF protection to pet deletion and post submission forms.
  • Configuration
    • Set a 5MB file size limit for uploads.
  • Bug Fixes
    • Removed unused XML namespace from the profile view template.

@coderabbitai

coderabbitai Bot commented Apr 22, 2025

Copy link
Copy Markdown

Walkthrough

The changes update the post creation flow in the application. The PostController#createPost method was refactored to accept only a JSON request body, removing the previous support for multipart file uploads. A new utility method was added to UserService for retrieving users by username with exception handling. The application.properties file now sets a 5MB limit on multipart file uploads, though the controller no longer accepts file uploads. The profile view template was enhanced to include post creation and listing, CSRF protection, and improved UI logic. Additionally, a new ProfilePostController was introduced to handle profile-specific post submissions with authorization and error handling.

Changes

File(s) Change Summary
src/main/java/se/storkforge/petconnect/controller/PostController.java Refactored createPost method to accept only JSON (@RequestBody), removed multipart file support, updated method signature/docs.
src/main/java/se/storkforge/petconnect/service/UserService.java Added getUserByUsernameOrThrow method for user retrieval with exception handling.
src/main/resources/application.properties Added properties to limit multipart file and request size to 5MB each.
src/main/resources/templates/profileView.html Enhanced profile page: added post creation/display, CSRF protection, simplified UI logic, and reordered buttons.
src/main/java/se/storkforge/petconnect/controller/ProfilePostController.java Added new controller to handle profile post submissions with authorization, validation, and redirect with flash messages.

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
Loading

Possibly related PRs

  • 47 story sharing functionality #58: This PR originally introduced the multipart file upload support in PostController#createPost, which is now being refactored in the current PR.

Suggested reviewers

  • Lhlmlund

Poem

A post without a picture, oh what a sight,
Now JSON alone takes flight!
Profile pages bloom with posts anew,
CSRF tokens guard what users do.
Five megabytes set the gate,
For future files, they'll have to wait.
🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

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)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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 functionality

The 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

📥 Commits

Reviewing files that changed from the base of the PR and between f80300c and 1753906.

📒 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 getUserByUsernameOrThrow method provides a convenient way to retrieve a user with built-in exception handling, following the same pattern as the existing getOrElseThrow method for ID-based retrieval.

src/main/resources/templates/profileView.html (4)

2-2: LGTM - Cleaner HTML declaration

The removal of the unused sec namespace simplifies the HTML declaration.


14-38: UI improvements look good

The 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

  1. The visibility condition for pet controls has been simplified to only require isOwner
  2. Added CSRF token to the pet deletion form for better security

Also applies to: 69-73


83-123: Great UI addition for posts functionality

The 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

Comment on lines +56 to +57
spring.servlet.multipart.max-file-size=5MB
spring.servlet.multipart.max-request-size=5MB

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 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 java

Length 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 || true

Length 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.html

Length 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 || true

Length 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}/post that accepts a MultipartFile (e.g. via @RequestParam("file") MultipartFile file or @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;

Comment on lines +89 to +101
<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>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

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:

  1. Revert the PostController changes to support multipart upload
  2. 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;
    }
}

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

📥 Commits

Reviewing files that changed from the base of the PR and between 1753906 and 7c64715.

📒 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 @PreAuthorize to restrict access to authenticated users with specific roles.

Comment on lines +40 to +45
try {
postService.createPost(dto, file, username);
redirectAttributes.addFlashAttribute("success", "Post created successfully!");
} catch (IllegalArgumentException e) {
redirectAttributes.addFlashAttribute("error", e.getMessage());
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ 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;

Comment on lines +15 to +49
@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;
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ 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;

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