Skip to content

Commit

Permalink
feat: add review table
Browse files Browse the repository at this point in the history
  • Loading branch information
lcaohoanq committed Dec 14, 2024
1 parent fa78db5 commit 838a3a1
Show file tree
Hide file tree
Showing 30 changed files with 498 additions and 40 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.lcaohoanq.shoppe.base.entity;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.persistence.Column;
import jakarta.persistence.MappedSuperclass;
import jakarta.persistence.PrePersist;
import jakarta.persistence.PreUpdate;
import java.time.LocalDateTime;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.SuperBuilder;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@MappedSuperclass //avoid direct persistence of this class, any entity that extends this class will have these fields
@SuperBuilder
public class BaseMedia {

@Column(name="created_at")
@JsonProperty("created_at")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSSSSS")
private LocalDateTime createdAt;

@Column(name="updated_at")
@JsonProperty("updated_at")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSSSSS")
private LocalDateTime updatedAt;

@PrePersist
protected void onCreate() {
createdAt = LocalDateTime.now();
updatedAt = LocalDateTime.now();
}

@PreUpdate
protected void onUpdate() {
updatedAt = LocalDateTime.now();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -245,9 +245,9 @@ private Otp getOtpByEmailOtp(String email, String otp) {
@Transactional
@Override
public void verifyOtpIsCorrect(Long userId, String otp) throws Exception {
User user = userService.findUserById(userId);
UserResponse user = userService.findUserById(userId);

Otp otpEntity = getOtpByEmailOtp(user.getEmail(), otp);
Otp otpEntity = getOtpByEmailOtp(user.email(), otp);

//check the otp is expired or not
if (otpEntity.getExpiredAt().isBefore(LocalDateTime.now())) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
Expand Down Expand Up @@ -69,7 +71,7 @@ public ResponseEntity<ApiResponse<CartResponse>> getCartByUserId(
);
}

@PostMapping("/item")
@PostMapping("/add-to-cart")
@PreAuthorize("hasRole('ROLE_MEMBER')")
public ResponseEntity<ApiResponse<CartItemResponse>> addItem(
@Valid @RequestBody CartItemDTO cartItemDTO,
Expand All @@ -93,5 +95,46 @@ public ResponseEntity<ApiResponse<CartItemResponse>> addItem(
.build()
);
}

@PostMapping("/buy-products")
@PreAuthorize("hasRole('ROLE_MEMBER')")
public ResponseEntity<ApiResponse<CartResponse>> buyProducts(
) {
return ResponseEntity.ok(
ApiResponse.<CartResponse>builder()
.message("Buy products successfully")
.statusCode(HttpStatus.OK.value())
.isSuccess(true)
.build()
);
}

@PutMapping("/update-purchase")
@PreAuthorize("hasRole('ROLE_MEMBER')")
public ResponseEntity<ApiResponse<CartResponse>> updatePurchases(
) {
return ResponseEntity.ok(
ApiResponse.<CartResponse>builder()
.message("Update purchases successfully")
.statusCode(HttpStatus.OK.value())
.isSuccess(true)
.build()
);
}

@DeleteMapping("/{id}")
@PreAuthorize("hasRole('ROLE_MEMBER')")
public ResponseEntity<ApiResponse<CartResponse>> deleteCart(
@PathVariable(value = "id") Long id
) {
// cartService.deleteCart(id);
return ResponseEntity.ok(
ApiResponse.<CartResponse>builder()
.message("Delete cart successfully")
.statusCode(HttpStatus.OK.value())
.isSuccess(true)
.build()
);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
import com.lcaohoanq.shoppe.base.exception.DataNotFoundException;
import com.lcaohoanq.shoppe.domain.user.IUserService;
import com.lcaohoanq.shoppe.domain.user.User;
import com.lcaohoanq.shoppe.domain.user.UserResponse;
import com.lcaohoanq.shoppe.exception.MalformBehaviourException;
import com.lcaohoanq.shoppe.mapper.CartMapper;
import com.lcaohoanq.shoppe.mapper.UserMapper;
import com.lcaohoanq.shoppe.util.PaginationConverter;
import java.util.ArrayList;
import lombok.RequiredArgsConstructor;
Expand All @@ -21,6 +23,7 @@ public class CartService implements ICartService, PaginationConverter {
private final IUserService userService;
private final CartRepository cartRepository;
private final CartMapper cartMapper;
private final UserMapper userMapper;

@Override
public CartResponse create(long userId) {
Expand All @@ -33,10 +36,10 @@ public CartResponse create(long userId) {
throw new MalformBehaviourException("Cart existed for user with id: " + userId);
}

User existedUser = userService.findUserById(userId);
UserResponse existedUser = userService.findUserById(userId);

Cart newCart = Cart.builder()
.user(existedUser)
.user(userMapper.toUser(existedUser))
.totalPrice(0)
.totalQuantity(0)
.cartItems(new ArrayList<>())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,10 @@
"updated_at"
})
public record CategoryResponse(
@JsonProperty("id")
Long id,
@JsonProperty("name")
String name,

@JsonProperty("subcategories") TreeSet<Subcategory> subcategories,
TreeSet<Subcategory> subcategories,

@JsonIgnore
@JsonProperty("created_at")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,4 @@ public class OrderDetail extends BaseEntity {
@Column(name = "total_money", nullable = false)
private Float totalMoney;

// @Column(name = "color")
// private String color;

}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,4 @@ public class OrderDetailResponse {

@JsonProperty("total_money")
private Float totalMoney;

private String color;
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public record ProductResponse(
Double rating,

@JsonProperty("status") ProductStatus status,
@JsonProperty("is_active") Boolean isActive,
@JsonProperty("is_active") boolean isActive,

@JsonProperty("created_at")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSSSSS")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.lcaohoanq.shoppe.domain.review;


import java.util.List;
import java.util.Optional;

public interface IReviewService {
ReviewResponse create(ReviewDTO reviewDTO);
List<ReviewResponse> getAll();
ReviewResponse update(long id, ReviewDTO reviewDTO);
void delete (long id);
Optional<ReviewResponse> getById(long id);
Optional<ReviewResponse> getByOrderId(long orderId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package com.lcaohoanq.shoppe.domain.review;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.lcaohoanq.shoppe.base.entity.BaseEntity;
import com.lcaohoanq.shoppe.domain.order.Order;
import com.lcaohoanq.shoppe.domain.user.User;
import com.lcaohoanq.shoppe.metadata.MediaMeta;
import jakarta.persistence.AttributeOverride;
import jakarta.persistence.AttributeOverrides;
import jakarta.persistence.Column;
import jakarta.persistence.Embedded;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.SuperBuilder;

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "reviews")
@SuperBuilder
@AttributeOverrides({
@AttributeOverride(name = "createdAt", column = @Column(name = "review_created_at")),
@AttributeOverride(name = "updatedAt", column = @Column(name = "review_updated_at"))
})
public class Review extends BaseEntity {

@Id
@SequenceGenerator(name = "reviews_seq", sequenceName = "reviews_id_seq", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "reviews_seq")
@Column(name="id", unique=true, nullable=false)
@JsonProperty("id")
private Long id;

@Column(name = "content")
private String content;

@Column(name = "rating")
private Integer rating;

@Column(name = "is_hidden", columnDefinition = "boolean default false")
private boolean isHidden; //hide username

@Column(name = "product_quality")
private String productQuality;

@Column(name = "match_description")
private String matchDescription;

@Embedded
private MediaMeta mediaMeta;

@ManyToOne
@JoinColumn(name = "user_id", nullable = false)
private User user;

@ManyToOne
@JoinColumn(name = "order_id", nullable = false)
private Order order;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.lcaohoanq.shoppe.domain.review;

import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.validation.constraints.NotNull;

public record ReviewDTO(
@JsonProperty("content") String content,
@JsonProperty("rating") int rating,
@JsonProperty("user_id") @NotNull long userId,
@JsonProperty("order_id") @NotNull long orderId)
{ }
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package com.lcaohoanq.shoppe.domain.review;

import com.lcaohoanq.shoppe.base.exception.DataNotFoundException;
import com.lcaohoanq.shoppe.component.LocalizationUtils;
import com.lcaohoanq.shoppe.domain.order.IOrderService;
import com.lcaohoanq.shoppe.domain.order.OrderResponse;
import com.lcaohoanq.shoppe.enums.OrderStatus;
import com.lcaohoanq.shoppe.mapper.ReviewMapper;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.graphql.data.method.annotation.Argument;
import org.springframework.graphql.data.method.annotation.MutationMapping;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;

@Controller
@RequiredArgsConstructor
public class ReviewGraphQLController {

private final IReviewService reviewService;
private final LocalizationUtils localizationUtils;
private final IOrderService orderService;
private final ReviewMapper reviewMapper;

@QueryMapping
@PreAuthorize("permitAll()")
public List<ReviewResponse> getAllFeedbacks() {
return reviewService.getAll();
}

@QueryMapping
public ReviewResponse getFeedbackById(@Argument Long id) {
return reviewService
.getById(id)
.orElseThrow(() -> new DataNotFoundException("Feedback not found: " + id));
}

@QueryMapping
public ReviewResponse getFeedbackByOrderId(@Argument Long orderId) {
return reviewService
.getByOrderId(orderId)
.orElseThrow(() -> new DataNotFoundException("Feedback not found for order: " + orderId));
}

@MutationMapping
public ReviewResponse createFeedback(@Argument ReviewDTO review) {
// Check if the order is in DELIVERED status
OrderResponse order = orderService.getById(review.orderId());
if (order.getStatus() != OrderStatus.DELIVERED) {
throw new IllegalStateException("Feedback can only be submitted for delivered orders.");
}

// Check if review already exists for this order
if (reviewService.getByOrderId(review.orderId()).isPresent()) {
throw new IllegalStateException("Feedback has already been submitted for this order.");
}

return reviewService.create(review);
}

@MutationMapping
public ReviewResponse updateFeedback(@Argument Long id, @Argument ReviewDTO review) {
return reviewService.update(id, review);
}

@MutationMapping
public Boolean deleteFeedback(@Argument Long id) {
try {
reviewService.delete(id);
return true;
} catch (Exception e) {
return false;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.lcaohoanq.shoppe.domain.review;

import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;

public interface ReviewRepository extends JpaRepository<Review, Long> {

Boolean existsByUserIdAndOrderId(Long userId, Long orderId);
Optional<Review> findByOrderId(Long orderId);

}
Loading

0 comments on commit 838a3a1

Please sign in to comment.