From 400c839fca2df773cce78fce89aad7f88e0fa1b8 Mon Sep 17 00:00:00 2001 From: shyye Date: Thu, 19 Sep 2024 10:40:50 +0200 Subject: [PATCH 01/11] Delete application.yml example --- src/main/resources/application.yml | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 src/main/resources/application.yml diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml deleted file mode 100644 index 02c2591..0000000 --- a/src/main/resources/application.yml +++ /dev/null @@ -1,7 +0,0 @@ -server: - port: 4000 - error: - include-message: always - include-binding-errors: always - include-stacktrace: never - include-exception: false From 31eeb0559a8abe67192a1023abfe6b5d1128c9fe Mon Sep 17 00:00:00 2001 From: shyye Date: Thu, 19 Sep 2024 10:41:39 +0200 Subject: [PATCH 02/11] Add application.yml to gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index c2065bc..b3db3e2 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,5 @@ out/ ### VS Code ### .vscode/ + +application.yml From 7f3def7d77a28846c9cf334b87cdd02429484ccc Mon Sep 17 00:00:00 2001 From: shyye Date: Thu, 19 Sep 2024 13:09:49 +0200 Subject: [PATCH 03/11] Add Response and ErrorResponse --- .../api/responses/ErrorResponse.java | 19 +++++++++++++++++++ .../com/booleanuk/api/responses/Response.java | 14 ++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 src/main/java/com/booleanuk/api/responses/ErrorResponse.java create mode 100644 src/main/java/com/booleanuk/api/responses/Response.java diff --git a/src/main/java/com/booleanuk/api/responses/ErrorResponse.java b/src/main/java/com/booleanuk/api/responses/ErrorResponse.java new file mode 100644 index 0000000..bda3184 --- /dev/null +++ b/src/main/java/com/booleanuk/api/responses/ErrorResponse.java @@ -0,0 +1,19 @@ +package com.booleanuk.api.responses; + +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.HashMap; +import java.util.Map; + +@Getter +@NoArgsConstructor +public class ErrorResponse extends Response> { + public void set(String message) { + this.status = "error"; + + Map reply = new HashMap<>(); + reply.put("message", message); + this.data = reply; + } +} diff --git a/src/main/java/com/booleanuk/api/responses/Response.java b/src/main/java/com/booleanuk/api/responses/Response.java new file mode 100644 index 0000000..e7fa6f3 --- /dev/null +++ b/src/main/java/com/booleanuk/api/responses/Response.java @@ -0,0 +1,14 @@ +package com.booleanuk.api.responses; + +import lombok.Getter; + +@Getter +public class Response { + protected String status; + protected T data; + + public void set(T data) { + this.status = "success"; + this.data = data; + } +} From d4a726f70641428b4e6020217b7da44b1eec9ddf Mon Sep 17 00:00:00 2001 From: shyye Date: Thu, 19 Sep 2024 13:10:44 +0200 Subject: [PATCH 04/11] Add BlogPost classes --- .../com/booleanuk/api/models/BlogPost.java | 42 +++++++++++++++++++ .../api/repositories/BlogPostRepository.java | 7 ++++ 2 files changed, 49 insertions(+) create mode 100644 src/main/java/com/booleanuk/api/models/BlogPost.java create mode 100644 src/main/java/com/booleanuk/api/repositories/BlogPostRepository.java diff --git a/src/main/java/com/booleanuk/api/models/BlogPost.java b/src/main/java/com/booleanuk/api/models/BlogPost.java new file mode 100644 index 0000000..6710ffd --- /dev/null +++ b/src/main/java/com/booleanuk/api/models/BlogPost.java @@ -0,0 +1,42 @@ +package com.booleanuk.api.models; + +import jakarta.persistence.*; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.CreationTimestamp; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +@Data +@NoArgsConstructor +@Entity +@Table +public class BlogPost { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private int id; + + @ManyToOne + @JoinColumn + private User publisher; + + @CreationTimestamp + @Column(updatable = false) + private LocalDateTime createdAt; + + // Content text of blogpost + @Column + private String text; + + @OneToMany + @JoinColumn + private List comments = new ArrayList<>(); + + public BlogPost(User publisher, String text) { + this.publisher = publisher; + this.text = text; + } +} diff --git a/src/main/java/com/booleanuk/api/repositories/BlogPostRepository.java b/src/main/java/com/booleanuk/api/repositories/BlogPostRepository.java new file mode 100644 index 0000000..7d98795 --- /dev/null +++ b/src/main/java/com/booleanuk/api/repositories/BlogPostRepository.java @@ -0,0 +1,7 @@ +package com.booleanuk.api.repositories; + +import com.booleanuk.api.models.BlogPost; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface BlogPostRepository extends JpaRepository { +} From cb36fd2c2dd47708b1302f7fcfaec03c55609dbf Mon Sep 17 00:00:00 2001 From: shyye Date: Thu, 19 Sep 2024 13:10:56 +0200 Subject: [PATCH 05/11] Add Comment classes --- .../com/booleanuk/api/models/Comment.java | 40 +++++++++++++++++++ .../api/repositories/CommentRepository.java | 7 ++++ 2 files changed, 47 insertions(+) create mode 100644 src/main/java/com/booleanuk/api/models/Comment.java create mode 100644 src/main/java/com/booleanuk/api/repositories/CommentRepository.java diff --git a/src/main/java/com/booleanuk/api/models/Comment.java b/src/main/java/com/booleanuk/api/models/Comment.java new file mode 100644 index 0000000..f11af9b --- /dev/null +++ b/src/main/java/com/booleanuk/api/models/Comment.java @@ -0,0 +1,40 @@ +package com.booleanuk.api.models; + +import jakarta.persistence.*; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.CreationTimestamp; + +import java.time.LocalDateTime; + +@Data +@NoArgsConstructor +@Entity +@Table +public class Comment { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private int id; + + @ManyToOne // Many comments can be published by one user + @JoinColumn + private User publisher; + + @ManyToOne // Many comments can belong to one blog post + @JoinColumn + private BlogPost blogPost; + + @CreationTimestamp + @Column(updatable = false) + private LocalDateTime createdAt; + + @Column + private String text; + + public Comment(User publisher, BlogPost blogPost, String text) { + this.publisher = publisher; + this.blogPost = blogPost; + this.text = text; + } +} diff --git a/src/main/java/com/booleanuk/api/repositories/CommentRepository.java b/src/main/java/com/booleanuk/api/repositories/CommentRepository.java new file mode 100644 index 0000000..356354d --- /dev/null +++ b/src/main/java/com/booleanuk/api/repositories/CommentRepository.java @@ -0,0 +1,7 @@ +package com.booleanuk.api.repositories; + +import com.booleanuk.api.models.Comment; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface CommentRepository extends JpaRepository { +} From 87845044f0bead1f6aab6d810612b3d63904aa33 Mon Sep 17 00:00:00 2001 From: shyye Date: Thu, 19 Sep 2024 13:11:09 +0200 Subject: [PATCH 06/11] Add Main --- src/main/java/com/booleanuk/api/Main.java | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 src/main/java/com/booleanuk/api/Main.java diff --git a/src/main/java/com/booleanuk/api/Main.java b/src/main/java/com/booleanuk/api/Main.java new file mode 100644 index 0000000..8e749e0 --- /dev/null +++ b/src/main/java/com/booleanuk/api/Main.java @@ -0,0 +1,11 @@ +package com.booleanuk.api; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Main { + public static void main(String[] args) { + SpringApplication.run(Main.class, args); + } +} From 1d45ae68c431f68ccbd414fcbf101f2302b86b84 Mon Sep 17 00:00:00 2001 From: shyye Date: Thu, 19 Sep 2024 13:11:26 +0200 Subject: [PATCH 07/11] Add User classes --- .../api/controllers/UserController.java | 91 +++++++++++++++++++ .../java/com/booleanuk/api/models/User.java | 47 ++++++++++ .../api/repositories/UserRepository.java | 7 ++ .../api/responses/UserListResponse.java | 8 ++ .../booleanuk/api/responses/UserResponse.java | 6 ++ 5 files changed, 159 insertions(+) create mode 100644 src/main/java/com/booleanuk/api/controllers/UserController.java create mode 100644 src/main/java/com/booleanuk/api/models/User.java create mode 100644 src/main/java/com/booleanuk/api/repositories/UserRepository.java create mode 100644 src/main/java/com/booleanuk/api/responses/UserListResponse.java create mode 100644 src/main/java/com/booleanuk/api/responses/UserResponse.java diff --git a/src/main/java/com/booleanuk/api/controllers/UserController.java b/src/main/java/com/booleanuk/api/controllers/UserController.java new file mode 100644 index 0000000..73228e0 --- /dev/null +++ b/src/main/java/com/booleanuk/api/controllers/UserController.java @@ -0,0 +1,91 @@ +package com.booleanuk.api.controllers; + +import com.booleanuk.api.models.User; +import com.booleanuk.api.repositories.BlogPostRepository; +import com.booleanuk.api.repositories.CommentRepository; +import com.booleanuk.api.repositories.UserRepository; +import com.booleanuk.api.responses.ErrorResponse; +import com.booleanuk.api.responses.Response; +import com.booleanuk.api.responses.UserListResponse; +import com.booleanuk.api.responses.UserResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("users") +public class UserController { + + @Autowired + private UserRepository userRepository; + + @Autowired + private BlogPostRepository blogPostRepository; + + @Autowired + private CommentRepository commentRepository; + + @PostMapping + public ResponseEntity create(@RequestBody User user) { + this.userRepository.save(user); + UserResponse response = new UserResponse(); + response.set(user); + return new ResponseEntity<>(response, HttpStatus.CREATED); + } + + @GetMapping + public ResponseEntity getAll() { + UserListResponse response = new UserListResponse(); + response.set(this.userRepository.findAll()); + return ResponseEntity.ok(response); + } + + @GetMapping("{id}") + public ResponseEntity> getSpecific(@PathVariable int id) { + User user = this.userRepository.findById(id).orElse(null); + if (user == null) { + ErrorResponse error = new ErrorResponse(); + error.set("A user with this id was not found."); + return new ResponseEntity<>(error, HttpStatus.NOT_FOUND); + } + UserResponse response = new UserResponse(); + response.set(user); + return ResponseEntity.ok(response); + } + + @PutMapping("{id}") + public ResponseEntity> update(@PathVariable int id, @RequestBody User user) { + User originalUser = this.userRepository.findById(id).orElse(null); + if (originalUser == null) { + ErrorResponse error = new ErrorResponse(); + error.set("Not found"); + return new ResponseEntity<>(error, HttpStatus.NOT_FOUND); + } + user.setId(id); + try { + this.userRepository.save(user); + } catch (Exception e) { + ErrorResponse error = new ErrorResponse(); + error.set("Bad request"); + return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST); + } + UserResponse response = new UserResponse(); + response.set(user); + return new ResponseEntity<>(response, HttpStatus.CREATED); + } + + @DeleteMapping("{id}") + public ResponseEntity> delete(@PathVariable int id) { + User user = this.userRepository.findById(id).orElse(null); + if (user == null) { + ErrorResponse error = new ErrorResponse(); + error.set("Not found"); + return new ResponseEntity<>(error, HttpStatus.NOT_FOUND); + } + this.userRepository.delete(user); + UserResponse response = new UserResponse(); + response.set(user); + return ResponseEntity.ok(response); + } +} diff --git a/src/main/java/com/booleanuk/api/models/User.java b/src/main/java/com/booleanuk/api/models/User.java new file mode 100644 index 0000000..75deb2f --- /dev/null +++ b/src/main/java/com/booleanuk/api/models/User.java @@ -0,0 +1,47 @@ +package com.booleanuk.api.models; + +import jakarta.persistence.*; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.List; + +@Data +@NoArgsConstructor +@Entity +@Table +public class User { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private int id; + + @Column + private String name; + + @Column + private String username; + + + @OneToMany + @JoinTable( + name = "user_blogpost", + joinColumns = @JoinColumn(name = "user_id"), + inverseJoinColumns = @JoinColumn(name = "blogpost_id") + ) + private List blogPosts = new ArrayList<>(); + + @OneToMany + @JoinTable( + name = "user_comment", + joinColumns = @JoinColumn(name = "user_id"), + inverseJoinColumns = @JoinColumn(name = "comment_id") + ) + private List comments = new ArrayList<>(); + + public User(String name, String username) { + this.name = name; + this.username = username; + } +} diff --git a/src/main/java/com/booleanuk/api/repositories/UserRepository.java b/src/main/java/com/booleanuk/api/repositories/UserRepository.java new file mode 100644 index 0000000..26097e0 --- /dev/null +++ b/src/main/java/com/booleanuk/api/repositories/UserRepository.java @@ -0,0 +1,7 @@ +package com.booleanuk.api.repositories; + +import com.booleanuk.api.models.User; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface UserRepository extends JpaRepository { +} diff --git a/src/main/java/com/booleanuk/api/responses/UserListResponse.java b/src/main/java/com/booleanuk/api/responses/UserListResponse.java new file mode 100644 index 0000000..834dac5 --- /dev/null +++ b/src/main/java/com/booleanuk/api/responses/UserListResponse.java @@ -0,0 +1,8 @@ +package com.booleanuk.api.responses; + +import com.booleanuk.api.models.User; + +import java.util.List; + +public class UserListResponse extends Response>{ +} diff --git a/src/main/java/com/booleanuk/api/responses/UserResponse.java b/src/main/java/com/booleanuk/api/responses/UserResponse.java new file mode 100644 index 0000000..4ed5485 --- /dev/null +++ b/src/main/java/com/booleanuk/api/responses/UserResponse.java @@ -0,0 +1,6 @@ +package com.booleanuk.api.responses; + +import com.booleanuk.api.models.User; + +public class UserResponse extends Response{ +} From 1a3eadd8ab5cfa613407b2a3823954fbd7c79c93 Mon Sep 17 00:00:00 2001 From: shyye Date: Thu, 19 Sep 2024 14:19:34 +0200 Subject: [PATCH 08/11] User blogpost Test --- .../api/controllers/UserController.java | 43 ++++++++++++++++++- .../com/booleanuk/api/models/BlogPost.java | 3 +- .../java/com/booleanuk/api/models/User.java | 2 +- 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/booleanuk/api/controllers/UserController.java b/src/main/java/com/booleanuk/api/controllers/UserController.java index 73228e0..d78dd1b 100644 --- a/src/main/java/com/booleanuk/api/controllers/UserController.java +++ b/src/main/java/com/booleanuk/api/controllers/UserController.java @@ -1,5 +1,6 @@ package com.booleanuk.api.controllers; +import com.booleanuk.api.models.BlogPost; import com.booleanuk.api.models.User; import com.booleanuk.api.repositories.BlogPostRepository; import com.booleanuk.api.repositories.CommentRepository; @@ -83,9 +84,49 @@ public ResponseEntity> delete(@PathVariable int id) { error.set("Not found"); return new ResponseEntity<>(error, HttpStatus.NOT_FOUND); } - this.userRepository.delete(user); + UserResponse response = new UserResponse(); response.set(user); + + try { + this.userRepository.delete(user); + } catch (Exception e) { + ErrorResponse error = new ErrorResponse(); + error.set("Bad request"); + return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST); + } return ResponseEntity.ok(response); } + + // Publish a blogpost for user with provided id + @PostMapping("{userId}/blogposts") + public ResponseEntity> publishBlogPostForUser( + @PathVariable int userId, + @RequestBody BlogPost blogpost) { + + User user = this.userRepository.findById(userId).orElse(null); + if (user == null) { + ErrorResponse error = new ErrorResponse(); + error.set("A user with this id was not found."); + return new ResponseEntity<>(error, HttpStatus.NOT_FOUND); + } + + // Populate blogpost with publisher info + blogpost.setPublisher(user); + this.blogPostRepository.save(blogpost); + + // Add blogpost to user + user.getBlogPosts().add(blogpost); + try { + this.userRepository.save(user); + } catch (Exception e) { + ErrorResponse error = new ErrorResponse(); + error.set("Bad request"); + return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST); + } + + UserResponse response = new UserResponse(); + response.set(user); + return new ResponseEntity<>(response, HttpStatus.CREATED); + } } diff --git a/src/main/java/com/booleanuk/api/models/BlogPost.java b/src/main/java/com/booleanuk/api/models/BlogPost.java index 6710ffd..4090813 100644 --- a/src/main/java/com/booleanuk/api/models/BlogPost.java +++ b/src/main/java/com/booleanuk/api/models/BlogPost.java @@ -35,8 +35,7 @@ public class BlogPost { @JoinColumn private List comments = new ArrayList<>(); - public BlogPost(User publisher, String text) { - this.publisher = publisher; + public BlogPost(String text) { this.text = text; } } diff --git a/src/main/java/com/booleanuk/api/models/User.java b/src/main/java/com/booleanuk/api/models/User.java index 75deb2f..4d294f4 100644 --- a/src/main/java/com/booleanuk/api/models/User.java +++ b/src/main/java/com/booleanuk/api/models/User.java @@ -9,7 +9,7 @@ @Data @NoArgsConstructor -@Entity +@Entity(name = "users") @Table public class User { From 3ff3f721ad097b2f44bb5c3794ff5bf94ebb1658 Mon Sep 17 00:00:00 2001 From: shyye Date: Thu, 19 Sep 2024 15:21:52 +0200 Subject: [PATCH 09/11] User blogpost Test 2 --- .../api/controllers/UserController.java | 14 +++++----- .../com/booleanuk/api/models/BlogPost.java | 5 +++- .../java/com/booleanuk/api/models/User.java | 28 +++++++++++-------- 3 files changed, 27 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/booleanuk/api/controllers/UserController.java b/src/main/java/com/booleanuk/api/controllers/UserController.java index d78dd1b..2546d36 100644 --- a/src/main/java/com/booleanuk/api/controllers/UserController.java +++ b/src/main/java/com/booleanuk/api/controllers/UserController.java @@ -117,13 +117,13 @@ public ResponseEntity> publishBlogPostForUser( // Add blogpost to user user.getBlogPosts().add(blogpost); - try { - this.userRepository.save(user); - } catch (Exception e) { - ErrorResponse error = new ErrorResponse(); - error.set("Bad request"); - return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST); - } +// try { +// this.userRepository.save(user); +// } catch (Exception e) { +// ErrorResponse error = new ErrorResponse(); +// error.set("Bad request"); +// return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST); +// } UserResponse response = new UserResponse(); response.set(user); diff --git a/src/main/java/com/booleanuk/api/models/BlogPost.java b/src/main/java/com/booleanuk/api/models/BlogPost.java index 4090813..9acf3f5 100644 --- a/src/main/java/com/booleanuk/api/models/BlogPost.java +++ b/src/main/java/com/booleanuk/api/models/BlogPost.java @@ -19,8 +19,11 @@ public class BlogPost { @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; +// @ManyToOne +// @JoinColumn +// private User publisher; @ManyToOne - @JoinColumn + @JoinColumn(name = "user_id") // This creates the foreign key in the BlogPost table private User publisher; @CreationTimestamp diff --git a/src/main/java/com/booleanuk/api/models/User.java b/src/main/java/com/booleanuk/api/models/User.java index 4d294f4..1710961 100644 --- a/src/main/java/com/booleanuk/api/models/User.java +++ b/src/main/java/com/booleanuk/api/models/User.java @@ -24,20 +24,24 @@ public class User { private String username; - @OneToMany - @JoinTable( - name = "user_blogpost", - joinColumns = @JoinColumn(name = "user_id"), - inverseJoinColumns = @JoinColumn(name = "blogpost_id") - ) +// @OneToMany +// @JoinTable( +// name = "user_blogpost", +// joinColumns = @JoinColumn(name = "user_id"), +// inverseJoinColumns = @JoinColumn(name = "blogpost_id") +// ) +// private List blogPosts = new ArrayList<>(); + @OneToMany(mappedBy = "publisher", cascade = CascadeType.ALL, orphanRemoval = true) private List blogPosts = new ArrayList<>(); - @OneToMany - @JoinTable( - name = "user_comment", - joinColumns = @JoinColumn(name = "user_id"), - inverseJoinColumns = @JoinColumn(name = "comment_id") - ) +// @OneToMany +// @JoinTable( +// name = "user_comment", +// joinColumns = @JoinColumn(name = "user_id"), +// inverseJoinColumns = @JoinColumn(name = "comment_id") +// ) +// private List comments = new ArrayList<>(); + @OneToMany(mappedBy = "publisher", cascade = CascadeType.ALL, orphanRemoval = true) private List comments = new ArrayList<>(); public User(String name, String username) { From a4a75d6fd660924d5c7935a35ab6c6ba020f928d Mon Sep 17 00:00:00 2001 From: shyye Date: Fri, 4 Oct 2024 10:02:38 +0200 Subject: [PATCH 10/11] Update simplified version, users can comment on different blogposts --- .../api/controllers/UserController.java | 118 ++++++++++++++---- .../com/booleanuk/api/models/BlogPost.java | 7 +- .../com/booleanuk/api/models/Comment.java | 8 ++ .../java/com/booleanuk/api/models/User.java | 22 +--- .../api/responses/BlogPostListResponse.java | 8 ++ .../api/responses/BlogPostResponse.java | 6 + .../api/responses/CommentResponse.java | 6 + 7 files changed, 129 insertions(+), 46 deletions(-) create mode 100644 src/main/java/com/booleanuk/api/responses/BlogPostListResponse.java create mode 100644 src/main/java/com/booleanuk/api/responses/BlogPostResponse.java create mode 100644 src/main/java/com/booleanuk/api/responses/CommentResponse.java diff --git a/src/main/java/com/booleanuk/api/controllers/UserController.java b/src/main/java/com/booleanuk/api/controllers/UserController.java index 2546d36..70286ba 100644 --- a/src/main/java/com/booleanuk/api/controllers/UserController.java +++ b/src/main/java/com/booleanuk/api/controllers/UserController.java @@ -1,14 +1,12 @@ package com.booleanuk.api.controllers; import com.booleanuk.api.models.BlogPost; +import com.booleanuk.api.models.Comment; import com.booleanuk.api.models.User; import com.booleanuk.api.repositories.BlogPostRepository; import com.booleanuk.api.repositories.CommentRepository; import com.booleanuk.api.repositories.UserRepository; -import com.booleanuk.api.responses.ErrorResponse; -import com.booleanuk.api.responses.Response; -import com.booleanuk.api.responses.UserListResponse; -import com.booleanuk.api.responses.UserResponse; +import com.booleanuk.api.responses.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -27,6 +25,7 @@ public class UserController { @Autowired private CommentRepository commentRepository; + // Create user @PostMapping public ResponseEntity create(@RequestBody User user) { this.userRepository.save(user); @@ -35,6 +34,7 @@ public ResponseEntity create(@RequestBody User user) { return new ResponseEntity<>(response, HttpStatus.CREATED); } + // Get all users @GetMapping public ResponseEntity getAll() { UserListResponse response = new UserListResponse(); @@ -42,6 +42,7 @@ public ResponseEntity getAll() { return ResponseEntity.ok(response); } + // Get specific user @GetMapping("{id}") public ResponseEntity> getSpecific(@PathVariable int id) { User user = this.userRepository.findById(id).orElse(null); @@ -55,6 +56,7 @@ public ResponseEntity> getSpecific(@PathVariable int id) { return ResponseEntity.ok(response); } + // Update user @PutMapping("{id}") public ResponseEntity> update(@PathVariable int id, @RequestBody User user) { User originalUser = this.userRepository.findById(id).orElse(null); @@ -76,6 +78,7 @@ public ResponseEntity> update(@PathVariable int id, @RequestBody Use return new ResponseEntity<>(response, HttpStatus.CREATED); } + // Delete user @DeleteMapping("{id}") public ResponseEntity> delete(@PathVariable int id) { User user = this.userRepository.findById(id).orElse(null); @@ -98,35 +101,102 @@ public ResponseEntity> delete(@PathVariable int id) { return ResponseEntity.ok(response); } - // Publish a blogpost for user with provided id + // Post blogpost for specific user @PostMapping("{userId}/blogposts") public ResponseEntity> publishBlogPostForUser( @PathVariable int userId, @RequestBody BlogPost blogpost) { - User user = this.userRepository.findById(userId).orElse(null); - if (user == null) { + try { + User user = this.userRepository.findById(userId).orElse(null); + if (user == null) { + ErrorResponse error = new ErrorResponse(); + error.set("A user with this id was not found."); + return new ResponseEntity<>(error, HttpStatus.NOT_FOUND); + } + + // Populate blogpost with publisher info and save + blogpost.setPublisher(user); + this.blogPostRepository.save(blogpost); + + // Add blogpost to user and save user + user.getBlogPosts().add(blogpost); + this.userRepository.save(user); + + BlogPostResponse response = new BlogPostResponse(); + response.set(blogpost); + return new ResponseEntity<>(response, HttpStatus.CREATED); + + } catch (Exception e) { ErrorResponse error = new ErrorResponse(); - error.set("A user with this id was not found."); - return new ResponseEntity<>(error, HttpStatus.NOT_FOUND); + error.set("An error occurred: " + e.getMessage()); + return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR); } + } - // Populate blogpost with publisher info - blogpost.setPublisher(user); - this.blogPostRepository.save(blogpost); + // Post comment on blogpost + // NOTE: simplified, could/should be done in other ways + @PostMapping("{userId}/blogposts/{blogpostId}/comment") + public ResponseEntity> publishCommentOnBlogPostForUser( + @PathVariable int userId, + @PathVariable int blogpostId, + @RequestBody Comment comment) { - // Add blogpost to user - user.getBlogPosts().add(blogpost); -// try { -// this.userRepository.save(user); -// } catch (Exception e) { -// ErrorResponse error = new ErrorResponse(); -// error.set("Bad request"); -// return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST); -// } + try { + // Find corresponding user (publisher) + User user = this.userRepository.findById(userId).orElse(null); + if (user == null) { + ErrorResponse error = new ErrorResponse(); + error.set("A user with this id was not found."); + return new ResponseEntity<>(error, HttpStatus.NOT_FOUND); + } + comment.setPublisher(user); + + // Find corresponding blogpost + BlogPost blogpost = this.blogPostRepository.findById(blogpostId).orElse(null); + if (blogpost == null) { + ErrorResponse error = new ErrorResponse(); + error.set("A blogpost with this id was not found."); + return new ResponseEntity<>(error, HttpStatus.NOT_FOUND); + } + blogpost.getComments().add(comment); + comment.setBlogPost(blogpost); + + this.commentRepository.save(comment); + + CommentResponse response = new CommentResponse(); + response.set(comment); + return new ResponseEntity<>(response, HttpStatus.CREATED); - UserResponse response = new UserResponse(); - response.set(user); - return new ResponseEntity<>(response, HttpStatus.CREATED); + } catch (Exception e) { + ErrorResponse error = new ErrorResponse(); + error.set("An error occurred: " + e.getMessage()); + return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + @GetMapping("blogposts") + public ResponseEntity getAllBlogposts() { + BlogPostListResponse response = new BlogPostListResponse(); + response.set(this.blogPostRepository.findAll()); + return ResponseEntity.ok(response); + } + + // Get all comments for a specific blogpost + @GetMapping("blogposts/{blogpostId}/comments") + public ResponseEntity> getCommentOnBlogPostForUser( + @PathVariable int blogpostId) { + + BlogPost blogpost = this.blogPostRepository.findById(blogpostId).orElse(null); + if (blogpost == null) { + ErrorResponse error = new ErrorResponse(); + error.set("A blogpost with this id was not found."); + return new ResponseEntity<>(error, HttpStatus.NOT_FOUND); + } + + BlogPostResponse response = new BlogPostResponse(); + response.set(blogpost); + return ResponseEntity.ok(response); } + } diff --git a/src/main/java/com/booleanuk/api/models/BlogPost.java b/src/main/java/com/booleanuk/api/models/BlogPost.java index 9acf3f5..84ee949 100644 --- a/src/main/java/com/booleanuk/api/models/BlogPost.java +++ b/src/main/java/com/booleanuk/api/models/BlogPost.java @@ -1,5 +1,6 @@ package com.booleanuk.api.models; +import com.fasterxml.jackson.annotation.JsonBackReference; import jakarta.persistence.*; import lombok.Data; import lombok.NoArgsConstructor; @@ -19,11 +20,9 @@ public class BlogPost { @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; -// @ManyToOne -// @JoinColumn -// private User publisher; @ManyToOne - @JoinColumn(name = "user_id") // This creates the foreign key in the BlogPost table + @JoinColumn + @JsonBackReference // To avoid recursion error private User publisher; @CreationTimestamp diff --git a/src/main/java/com/booleanuk/api/models/Comment.java b/src/main/java/com/booleanuk/api/models/Comment.java index f11af9b..14f9e94 100644 --- a/src/main/java/com/booleanuk/api/models/Comment.java +++ b/src/main/java/com/booleanuk/api/models/Comment.java @@ -1,5 +1,7 @@ package com.booleanuk.api.models; +import com.fasterxml.jackson.annotation.JsonBackReference; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import jakarta.persistence.*; import lombok.Data; import lombok.NoArgsConstructor; @@ -19,10 +21,12 @@ public class Comment { @ManyToOne // Many comments can be published by one user @JoinColumn + @JsonIgnoreProperties({"comment"}) private User publisher; @ManyToOne // Many comments can belong to one blog post @JoinColumn + @JsonBackReference // To avoid recursion error private BlogPost blogPost; @CreationTimestamp @@ -37,4 +41,8 @@ public Comment(User publisher, BlogPost blogPost, String text) { this.blogPost = blogPost; this.text = text; } + + public Comment(String text) { + this.text = text; + } } diff --git a/src/main/java/com/booleanuk/api/models/User.java b/src/main/java/com/booleanuk/api/models/User.java index 1710961..537498c 100644 --- a/src/main/java/com/booleanuk/api/models/User.java +++ b/src/main/java/com/booleanuk/api/models/User.java @@ -1,5 +1,7 @@ package com.booleanuk.api.models; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonManagedReference; import jakarta.persistence.*; import lombok.Data; import lombok.NoArgsConstructor; @@ -11,6 +13,7 @@ @NoArgsConstructor @Entity(name = "users") @Table +@JsonIgnoreProperties({"blogPosts"}) public class User { @Id @@ -23,27 +26,10 @@ public class User { @Column private String username; - -// @OneToMany -// @JoinTable( -// name = "user_blogpost", -// joinColumns = @JoinColumn(name = "user_id"), -// inverseJoinColumns = @JoinColumn(name = "blogpost_id") -// ) -// private List blogPosts = new ArrayList<>(); @OneToMany(mappedBy = "publisher", cascade = CascadeType.ALL, orphanRemoval = true) + @JsonManagedReference // To avoid recursion error private List blogPosts = new ArrayList<>(); -// @OneToMany -// @JoinTable( -// name = "user_comment", -// joinColumns = @JoinColumn(name = "user_id"), -// inverseJoinColumns = @JoinColumn(name = "comment_id") -// ) -// private List comments = new ArrayList<>(); - @OneToMany(mappedBy = "publisher", cascade = CascadeType.ALL, orphanRemoval = true) - private List comments = new ArrayList<>(); - public User(String name, String username) { this.name = name; this.username = username; diff --git a/src/main/java/com/booleanuk/api/responses/BlogPostListResponse.java b/src/main/java/com/booleanuk/api/responses/BlogPostListResponse.java new file mode 100644 index 0000000..1674c16 --- /dev/null +++ b/src/main/java/com/booleanuk/api/responses/BlogPostListResponse.java @@ -0,0 +1,8 @@ +package com.booleanuk.api.responses; + +import com.booleanuk.api.models.BlogPost; + +import java.util.List; + +public class BlogPostListResponse extends Response> { +} diff --git a/src/main/java/com/booleanuk/api/responses/BlogPostResponse.java b/src/main/java/com/booleanuk/api/responses/BlogPostResponse.java new file mode 100644 index 0000000..f796c6c --- /dev/null +++ b/src/main/java/com/booleanuk/api/responses/BlogPostResponse.java @@ -0,0 +1,6 @@ +package com.booleanuk.api.responses; + +import com.booleanuk.api.models.BlogPost; + +public class BlogPostResponse extends Response { +} diff --git a/src/main/java/com/booleanuk/api/responses/CommentResponse.java b/src/main/java/com/booleanuk/api/responses/CommentResponse.java new file mode 100644 index 0000000..0d7dccc --- /dev/null +++ b/src/main/java/com/booleanuk/api/responses/CommentResponse.java @@ -0,0 +1,6 @@ +package com.booleanuk.api.responses; + +import com.booleanuk.api.models.Comment; + +public class CommentResponse extends Response { +} From d6f44aaa5fbf35de3ad8c5303d669db72b326627 Mon Sep 17 00:00:00 2001 From: shyye Date: Fri, 4 Oct 2024 11:49:24 +0200 Subject: [PATCH 11/11] Add docker and docker compose --- .gitignore | 1 + Dockerfile | 9 +++++++++ build.gradle | 11 +++++++++++ docker-compose.yml | 21 +++++++++++++++++++++ 4 files changed, 42 insertions(+) create mode 100644 Dockerfile create mode 100644 docker-compose.yml diff --git a/.gitignore b/.gitignore index b3db3e2..fa56d76 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,4 @@ out/ .vscode/ application.yml +java.docker.day.2-0.0.1-SNAPSHOT.jar \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..ea842b5 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,9 @@ +FROM eclipse-temurin:18 + +WORKDIR /app + +COPY java.docker.day.2-0.0.1.jar /app/java.docker.day.2-0.0.1.jar + +EXPOSE 4000 + +ENTRYPOINT ["java", "-jar", "java.docker.day.2-0.0.1.jar"] \ No newline at end of file diff --git a/build.gradle b/build.gradle index fb070c4..0efd7da 100644 --- a/build.gradle +++ b/build.gradle @@ -31,3 +31,14 @@ dependencies { tasks.named('test') { useJUnitPlatform() } + +jar { + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + manifest { + attributes 'Main-Class': 'com.booleanuk.api.Main' + } + + from { + configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } + } +} \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..4b6aa6f --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,21 @@ +services: + app: + image: 'music-box:latest' + container_name: app + depends_on: + - db + ports: + - '4000:4000' + environment: + - SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/mypostgresuser + - SPRING_DATASOURCE_USERNAME=mypostgresuser + - SPRING_DATASOURCE_PASSWORD=mypostgrespassword + - SPRING_JPA_HIBERNATE_DDL_AUTO=update + + db: + image: 'postgres:latest' + container_name: db + environment: + - POSTGRES_USER=mypostgresuser + - POSTGRES_DATABASE=mypostgresuser + - POSTGRES_PASSWORD=mypostgrespassword \ No newline at end of file