Skip to content
Open
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
464 changes: 0 additions & 464 deletions .Postman/Stats-server.postman_collection.json

This file was deleted.

2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
# java-explore-with-me
Template repository for ExploreWithMe project.
---
https://github.com/SugarFoxy/java-explore-with-me/pull/3
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package ru.practicum.events.comments.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import ru.practicum.events.comments.dto.InputCommentDto;
import ru.practicum.events.comments.dto.OutCommentDto;
import ru.practicum.events.comments.service.CommentPrivateService;
import ru.practicum.util.exception.handler.CustomExceptionHandler;

@RestController
@RequestMapping("/users/{userId}/comments")
@CustomExceptionHandler
public class ControllerPrivateComment {
private final CommentPrivateService service;

@Autowired
public ControllerPrivateComment(CommentPrivateService service) {
this.service = service;
}

@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public OutCommentDto createComment(@PathVariable Long userId,

This comment was marked as resolved.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Спасибо что подсказал. Не дружу с английским. Поэтому и названия кривые

@RequestBody InputCommentDto dto) {
return service.createComment(userId, dto);
}

@PatchMapping("/{commId}")
public OutCommentDto updateComment(@PathVariable Long userId,
@PathVariable Long commId,
@RequestBody InputCommentDto dto) {
return service.updateComment(userId, commId, dto);
}

@DeleteMapping("/{commId}")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Может на commentId всё-таки переделаем?

@ResponseStatus(HttpStatus.NO_CONTENT)
public void deleteComment(@PathVariable Long userId,
@PathVariable Long commId) {
service.deleteComment(userId, commId);
}

@PostMapping("/{commId}/like")
@ResponseStatus(HttpStatus.CREATED)
public OutCommentDto leaveRating(@PathVariable Long userId,
@PathVariable Long commId,
@RequestParam Boolean grade) {
return service.leaveRating(userId, commId, grade);
}

@DeleteMapping("/{commId}/like")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void deleteRating(@PathVariable Long userId,
@PathVariable Long commId) {
service.deleteRating(userId, commId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package ru.practicum.events.comments.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import ru.practicum.events.comments.dto.OutCommentDto;
import ru.practicum.events.comments.service.CommentPublicService;
import ru.practicum.util.exception.handler.CustomExceptionHandler;

import javax.validation.constraints.NotNull;
import javax.validation.constraints.Positive;
import javax.validation.constraints.PositiveOrZero;
import java.util.List;

@RestController
@RequestMapping("/comment")
@CustomExceptionHandler
public class ControllerPublicComment {
private final CommentPublicService service;

@Autowired
public ControllerPublicComment(CommentPublicService service) {
this.service = service;
}

@GetMapping
public List<OutCommentDto> getCommentByEvent(@NotNull @RequestParam Long eventId,
@RequestParam(defaultValue = "false") Boolean rating,
@PositiveOrZero @RequestParam(defaultValue = "0") int from,
@Positive @RequestParam(defaultValue = "10") int size) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Почему какие-то поля объектные, а какие-то примитивные, тем более если eventId не может быть null. Во всех контроллерах это вижу, давай к какому-то одному стилю придем

return service.getCommentByEvent(eventId, rating, from, size);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package ru.practicum.events.comments.dto;

import lombok.*;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;

@Setter
@Getter
@NoArgsConstructor

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Вот это ты где-то используешь? Если нет, то лучше удалить это из всех классов

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Когда дто приходи и десериализуется требует конструкторы. Неужели это так нагружает систему? Могу удалить билдер он тут не нужен.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

На самом деле систему это не нагружает, тут проблема в том, что такой доступный зоопарк возможностей по конструированию объекта приводит к тому, что каждый разработчик создает объекты по своему и это больно потом одному человеку сводить, когда надо довести горящий релиз до логического завершения.

А так в целом билдер это отличный шаблон, очень удобно с ним работать, и вообще это довольно интересная концепция.

@AllArgsConstructor
@Builder

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

И Setter, и Builder, и AllArgsConstructor, может от чего-то можно отказаться?

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

только от билдера. Хотя для написания тестов он был бы удобен. (очень он мне полюбился)

public class InputCommentDto {
@NotNull
@NotBlank
private String text;
private Long eventId;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package ru.practicum.events.comments.dto;

import lombok.*;
import ru.practicum.users.dto.UserShortDto;

import java.time.LocalDateTime;

@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class OutCommentDto {
private Long id;
private UserShortDto commentator;
private String text;
private LocalDateTime commentTime;
private Long rating;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package ru.practicum.events.comments.mapper;

import ru.practicum.events.comments.dto.InputCommentDto;
import ru.practicum.events.comments.dto.OutCommentDto;
import ru.practicum.events.comments.model.Comment;
import ru.practicum.events.event.model.Event;
import ru.practicum.users.mapper.UserMapper;
import ru.practicum.users.model.User;

import java.time.LocalDateTime;

public class CommentMapper {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Если все методы статические, то лучше сделать пустой конструктор этого класса приватным, чтобы везде гарантированно использовать его, как синглтон:

https://en.wikipedia.org/wiki/Singleton_pattern

Либо можно вместо класса использовать enum, как синглтон. Кстати, чтобы никто не испортил поведение нашего класса, то лучше пометить его как final, чтобы у него не могло быть наследников.

https://www.geeksforgeeks.org/advantages-and-disadvantages-of-using-enum-as-singleton-in-java/

public static OutCommentDto toDto(Comment comment) {
return OutCommentDto.builder()
.commentator(UserMapper.toShortDto(comment.getCommentator()))
.commentTime(comment.getCommentTime())
.id(comment.getId())
.text(comment.getText())
.build();
}

public static OutCommentDto toDto(Comment comment, Long rating) {
return OutCommentDto.builder()
.commentator(UserMapper.toShortDto(comment.getCommentator()))
.commentTime(comment.getCommentTime())
.id(comment.getId())
.text(comment.getText())
.rating(rating)
.build();
}

public static Comment toComment(InputCommentDto dto, LocalDateTime time, User commentator, Event event) {
return Comment.builder()
.commentator(commentator)
.text(dto.getText())
.commentTime(time)
.event(event)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package ru.practicum.events.comments.model;

import lombok.*;
import ru.practicum.events.event.model.Event;
import ru.practicum.users.model.User;

import javax.persistence.*;
import java.time.LocalDateTime;

@Setter
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "comments")
public class Comment {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "comment_text")
private String text;
@ManyToOne()
@JoinColumn(name = "user_id")
private User commentator;
@ManyToOne()
@JoinColumn(name = "event_id")
private Event event;
@Column(name = "comment_time")
private LocalDateTime commentTime;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package ru.practicum.events.comments.rating.model;

import lombok.*;
import ru.practicum.events.comments.model.Comment;
import ru.practicum.users.model.User;

import javax.persistence.*;

@Setter
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "rating")
public class Grade {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne()
@JoinColumn(name = "user_id")
private User rater;
@ManyToOne()
@JoinColumn(name = "comment_id")
private Comment comment;
private Boolean grade;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package ru.practicum.events.comments.rating.storage;

import org.springframework.data.jpa.repository.JpaRepository;
import ru.practicum.events.comments.model.Comment;
import ru.practicum.events.comments.rating.model.Grade;
import ru.practicum.users.model.User;

public interface RatingRepository extends JpaRepository<Grade, Long> {
Long countGradeByCommentAndGrade(Comment comment, Boolean grade);

Boolean existsByCommentAndRater(Comment comment, User rater);

void deleteByCommentAndRater(Comment comment, User user);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package ru.practicum.events.comments.service;

import ru.practicum.events.comments.dto.InputCommentDto;
import ru.practicum.events.comments.dto.OutCommentDto;

public interface CommentPrivateService {
OutCommentDto createComment(Long userId, InputCommentDto dto);

OutCommentDto updateComment(Long userId, Long commentId, InputCommentDto dto);

void deleteComment(Long userId, Long commentId);

OutCommentDto leaveRating(Long userId, Long commentId, Boolean grade);

void deleteRating(Long userId, Long commentId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package ru.practicum.events.comments.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import ru.practicum.events.comments.dto.InputCommentDto;
import ru.practicum.events.comments.dto.OutCommentDto;
import ru.practicum.events.comments.mapper.CommentMapper;
import ru.practicum.events.comments.model.Comment;
import ru.practicum.events.comments.rating.model.Grade;
import ru.practicum.events.comments.rating.storage.RatingRepository;
import ru.practicum.events.comments.storage.CommentRepository;
import ru.practicum.events.event.model.Event;
import ru.practicum.users.model.User;
import ru.practicum.util.RepositoryObjectCreator;
import ru.practicum.util.exception.BadRequestException;
import ru.practicum.util.exception.ConflictException;

import java.time.LocalDateTime;

@Service
public class CommentPrivateServiceImpl implements CommentPrivateService {
private final CommentRepository commentRepository;
private final RepositoryObjectCreator objectCreator;
private final RatingRepository ratingRepository;

@Autowired
public CommentPrivateServiceImpl(CommentRepository commentRepository,
RepositoryObjectCreator objectCreator,
RatingRepository ratingRepository) {
this.commentRepository = commentRepository;
this.objectCreator = objectCreator;
this.ratingRepository = ratingRepository;
}

@Override
public OutCommentDto createComment(Long userId, InputCommentDto dto) {
Event event = objectCreator.getEventById(dto.getEventId());
if (!event.getCommentSwitch()) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Наверное лучше commentAvailable, чтобы было понятнее, а то switch немного пугает

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Это не я, это гугл переводчик тебя испугал))))).

Я буду скучать по твоим ревью :`(
Спасибо большое за твой труд и прости за кровавые слезы при прочтении моего кода =D

throw new ConflictException("Невозможно добавить комментарий! У события отключены комментарии!");
}
return CommentMapper.toDto(commentRepository.save(CommentMapper.toComment(
dto,
LocalDateTime.now(),
objectCreator.getUserById(userId),
event)
));
}

@Override
public OutCommentDto updateComment(Long userId, Long commentId, InputCommentDto dto) {
Comment comment = objectCreator.getCommentById(commentId);

if (!comment.getCommentator().getId().equals(userId)) {
throw new BadRequestException(String
.format("Только комментатор может изменить коментарий id = %d ", commentId));
}
if (!comment.getEvent().getId().equals(dto.getEventId())) {
throw new BadRequestException(String
.format("У события id = %d отсутствует коментарий id = %d", userId, commentId));
}

comment.setText(dto.getText());
return CommentMapper.toDto(commentRepository.save(comment));
}

@Override
public void deleteComment(Long userId, Long commId) {
Comment comment = objectCreator.getCommentById(commId);

if (!comment.getCommentator().getId().equals(userId)) {
throw new BadRequestException(String
.format("Только комментатор может удалить коментарий id = %d ", commId));
}
commentRepository.deleteById(commId);
}

@Override
public OutCommentDto leaveRating(Long userId, Long commentId, Boolean grade) {
if (ratingRepository
.existsByCommentAndRater(objectCreator.getCommentById(commentId), objectCreator.getUserById(userId))) {
throw new ConflictException("Отавить оценку комментарию можно один раз");
}
ratingRepository.save(Grade.builder()
.comment(objectCreator.getCommentById(commentId))
.rater(objectCreator.getUserById(userId))
.grade(grade)
.build());
Comment comment = objectCreator.getCommentById(commentId);
return CommentMapper.toDto(comment, ratingRepository.countGradeByCommentAndGrade(comment, true)
- ratingRepository.countGradeByCommentAndGrade(comment, false));
}

@Override
@Transactional
public void deleteRating(Long userId, Long commentId) {
Comment comment = objectCreator.getCommentById(commentId);
User user = objectCreator.getUserById(userId);
if (!ratingRepository.existsByCommentAndRater(comment, user)) {
throw new BadRequestException(String.format("Невозможно удалеть лайк! " +
"Пользователь id = %d не ставил оценку комментарию id = %d", userId, commentId));
}
ratingRepository
.deleteByCommentAndRater(comment, user);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package ru.practicum.events.comments.service;

import ru.practicum.events.comments.dto.OutCommentDto;

import java.util.List;

public interface CommentPublicService {
List<OutCommentDto> getCommentByEvent(Long eventId, Boolean rating, int from, int size);
}
Loading