Skip to content

Commit

Permalink
Merge pull request #152 from bounswe/issue#150-create-post
Browse files Browse the repository at this point in the history
Implement Post CRUD Operations and Tag-based Filtering
  • Loading branch information
sametaln authored Oct 21, 2024
2 parents f0156ed + 103b4dd commit 794369e
Show file tree
Hide file tree
Showing 13 changed files with 392 additions and 9 deletions.
6 changes: 6 additions & 0 deletions backend/demo-group7/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@
<version>1.18.34</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>

</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,10 @@ public class AuthenticationController {
private final AuthenticationService authenticationService;

@PostMapping("/register")
public ResponseEntity<String> register(@RequestBody RegisterRequest request) {
try {
User registeredUser = authenticationService.register(request);
// TODO: can create and return session token on signing up.
return ResponseEntity.status(HttpStatus.CREATED).body(null);
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage());
}
public ResponseEntity<String> register(@RequestBody RegisterRequest request) throws Exception {
User registeredUser = authenticationService.register(request);
// TODO: can create and return session token on signing up.
return ResponseEntity.status(HttpStatus.CREATED).body(null);
}

@PostMapping("/login")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.group7.demo.controllers;

import com.group7.demo.dtos.PostRequest;
import com.group7.demo.dtos.PostResponse;
import com.group7.demo.models.Post;
import com.group7.demo.services.PostService;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Set;

@RestController
@RequestMapping("/api/posts")
@AllArgsConstructor
public class PostController {
private PostService postService;

@PostMapping
public ResponseEntity<PostResponse> createPost(@RequestBody PostRequest postRequest) {
PostResponse createdPost = postService.createPost(postRequest);
return ResponseEntity.ok(createdPost);
}

@GetMapping
public ResponseEntity<List<PostResponse>> fetchPosts(
@RequestParam(required = false) Set<String> tags) {

List<PostResponse> posts;

if (tags != null) {
posts = postService.getPostsByTags(tags);
return ResponseEntity.ok(posts);
} else {
posts = postService.getAllPosts();
}

return ResponseEntity.ok(posts);
}

@DeleteMapping("/{postId}")
public ResponseEntity<String> deletePost(@PathVariable Long postId) {
postService.deletePost(postId);
return ResponseEntity.ok("Post deleted successfully.");
}

// @GetMapping("/by-tags")
// public ResponseEntity<List<PostResponse>> getPostsByTags(@RequestParam ) {
//
// }
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.group7.demo.dtos;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Set;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class PostRequest {

private String content;
private Set<String> tags;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.group7.demo.dtos;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;
import java.util.Set;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class PostResponse {

private Long id;
private String content;
private Set<String> tags;
private LocalDateTime createdAt;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.group7.demo.exceptions;

import java.time.LocalDateTime;

public class ErrorResponse {

private LocalDateTime timestamp;
private String message;
private String details;

public ErrorResponse(LocalDateTime timestamp, String message, String details) {
this.timestamp = timestamp;
this.message = message;
this.details = details;
}

// Getters and Setters
public LocalDateTime getTimestamp() {
return timestamp;
}

public void setTimestamp(LocalDateTime timestamp) {
this.timestamp = timestamp;
}

public String getMessage() {
return message;
}

public void setMessage(String message) {
this.message = message;
}

public String getDetails() {
return details;
}

public void setDetails(String details) {
this.details = details;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.group7.demo.exceptions.handler;

import com.group7.demo.exceptions.ErrorResponse;
import jakarta.persistence.EntityNotFoundException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

@ControllerAdvice
public class GlobalExceptionHandler {

// Handle generic exceptions
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleGlobalException(Exception ex, WebRequest request) {
ErrorResponse errorResponse = new ErrorResponse(
LocalDateTime.now(),
"An unexpected error occurred",
ex.getMessage()
);
return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR);
}


@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<Object> handleIllegalArgumentException(IllegalArgumentException ex, WebRequest request) {
Map<String, Object> body = new HashMap<>();
body.put("timestamp", LocalDateTime.now());
body.put("message", ex.getMessage());

return new ResponseEntity<>(body, HttpStatus.BAD_REQUEST);
}

@ExceptionHandler(EntityNotFoundException.class)
public ResponseEntity<Object> handleEntityNotFoundException(EntityNotFoundException ex, WebRequest request) {
Map<String, Object> body = new HashMap<>();
body.put("timestamp", LocalDateTime.now());
body.put("message", ex.getMessage());

return new ResponseEntity<>(body, HttpStatus.NOT_FOUND);
}



}
34 changes: 34 additions & 0 deletions backend/demo-group7/src/main/java/com/group7/demo/models/Post.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.group7.demo.models;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import jakarta.persistence.*;
import lombok.*;

import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.Set;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Entity
@EqualsAndHashCode(exclude = "tags") // Avoid using tags in equals and hashCode to prevent recursion
public class Post {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String content;

private LocalDateTime createdAt;

@ManyToMany
@JoinTable(
name = "post_tags",
joinColumns = @JoinColumn(name = "post_id"),
inverseJoinColumns = @JoinColumn(name = "tag_name"))
// @JsonIgnoreProperties("posts") // Prevents infinite recursion with Tag entity
private Set<Tag> tags = new HashSet<>();
}
27 changes: 27 additions & 0 deletions backend/demo-group7/src/main/java/com/group7/demo/models/Tag.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.group7.demo.models;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToMany;
import lombok.*;

import java.util.HashSet;
import java.util.Set;


@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Entity
@EqualsAndHashCode(exclude = "posts") // Avoid using posts in equals and hashCode to prevent recursion
public class Tag {

@Id
private String name;

@ManyToMany(mappedBy = "tags")
// @JsonIgnoreProperties("tags") // Prevents infinite recursion with Post entity
private Set<Post> posts = new HashSet<>();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.group7.demo.repository;

import com.group7.demo.dtos.PostResponse;
import com.group7.demo.models.Post;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.List;
import java.util.Set;

public interface PostRepository extends JpaRepository<Post, Long> {
List<Post> findByTags_Name(String tagName);

@Query("SELECT p.id, p.content, p.createdAt, t.name FROM Post p LEFT JOIN p.tags t")
List<Object[]> findAllPostDataWithTags();

@Query("SELECT DISTINCT p FROM Post p LEFT JOIN FETCH p.tags")
List<Post> findAllPostsWithTags();


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.group7.demo.repository;

import com.group7.demo.models.Tag;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.Optional;

public interface TagRepository extends JpaRepository<Tag, Long> {
Optional<Tag> findByName(String name);
}
Loading

0 comments on commit 794369e

Please sign in to comment.