From 324a96b2fd6bc19fed4b5f7fb21a44312b63ac03 Mon Sep 17 00:00:00 2001 From: Siustoster Date: Wed, 18 Sep 2024 23:48:49 +0300 Subject: [PATCH 1/4] =?UTF-8?q?=D1=8D=D1=82=D0=B0=D0=BF=203?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/AdminUserController.java | 9 ++ .../controller/PrivateEventController.java | 42 ++++++- .../mainservice/mappers/EventMapper.java | 44 +++++++- .../mainservice/mappers/UserMapper.java | 22 +++- .../mainservice/model/Constants.java | 2 + .../mainservice/model/event/Event.java | 2 + .../event/dto/EventFullDtoWithRating.java | 32 ++++++ .../event/dto/EventShortDtoWithRating.java | 25 +++++ .../mainservice/model/mark/Mark.java | 35 ++++++ .../mainservice/model/user/User.java | 2 + .../model/user/dto/UserDtoWithRating.java | 15 +++ .../user/dto/UserShortDtoWithRating.java | 13 +++ .../repository/EventRepository.java | 5 + .../repository/MarkRepository.java | 9 ++ .../repository/UserRepository.java | 5 + .../mainservice/service/EventService.java | 46 +++++++- .../mainservice/service/MarkService.java | 106 ++++++++++++++++++ .../mainservice/service/UserService.java | 11 ++ main-service/src/main/resources/schema.sql | 13 ++- 19 files changed, 424 insertions(+), 14 deletions(-) create mode 100644 main-service/src/main/java/ru/practicum/mainservice/model/event/dto/EventFullDtoWithRating.java create mode 100644 main-service/src/main/java/ru/practicum/mainservice/model/event/dto/EventShortDtoWithRating.java create mode 100644 main-service/src/main/java/ru/practicum/mainservice/model/mark/Mark.java create mode 100644 main-service/src/main/java/ru/practicum/mainservice/model/user/dto/UserDtoWithRating.java create mode 100644 main-service/src/main/java/ru/practicum/mainservice/model/user/dto/UserShortDtoWithRating.java create mode 100644 main-service/src/main/java/ru/practicum/mainservice/repository/MarkRepository.java create mode 100644 main-service/src/main/java/ru/practicum/mainservice/service/MarkService.java diff --git a/main-service/src/main/java/ru/practicum/mainservice/controller/AdminUserController.java b/main-service/src/main/java/ru/practicum/mainservice/controller/AdminUserController.java index 65113a8..1a30bc9 100644 --- a/main-service/src/main/java/ru/practicum/mainservice/controller/AdminUserController.java +++ b/main-service/src/main/java/ru/practicum/mainservice/controller/AdminUserController.java @@ -8,6 +8,7 @@ import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; import ru.practicum.mainservice.model.user.dto.UserDto; +import ru.practicum.mainservice.model.user.dto.UserDtoWithRating; import ru.practicum.mainservice.service.UserService; import java.util.List; @@ -40,4 +41,12 @@ public void deleteUser(@PathVariable @Positive Integer userId) { log.info("Контроллер админа получил запрос на удаление пользователя с id = {}", userId); userService.deleteUser(userId); } + + @GetMapping("/users/rating") + public List getUsersWithRating(@RequestParam(defaultValue = "0") @PositiveOrZero Integer from, + @RequestParam(defaultValue = "10") @Positive Integer size) { + log.info("Контроллер админа получил запрос на получение списка пользователей с информацией " + + "об их рейтинге и сортировкой по возрастанию рейтинга"); + return userService.getUsersWithRating(from, size); + } } diff --git a/main-service/src/main/java/ru/practicum/mainservice/controller/PrivateEventController.java b/main-service/src/main/java/ru/practicum/mainservice/controller/PrivateEventController.java index adfc0cf..fdb8967 100644 --- a/main-service/src/main/java/ru/practicum/mainservice/controller/PrivateEventController.java +++ b/main-service/src/main/java/ru/practicum/mainservice/controller/PrivateEventController.java @@ -1,20 +1,19 @@ package ru.practicum.mainservice.controller; import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Positive; import jakarta.validation.constraints.PositiveOrZero; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; -import ru.practicum.mainservice.model.event.dto.EventFullDto; -import ru.practicum.mainservice.model.event.dto.EventShortDto; -import ru.practicum.mainservice.model.event.dto.NewEventDto; -import ru.practicum.mainservice.model.event.dto.UpdateEventRequest; +import ru.practicum.mainservice.model.event.dto.*; import ru.practicum.mainservice.model.request.dto.EventRequestStatusUpdateRequest; import ru.practicum.mainservice.model.request.dto.EventRequestStatusUpdateResult; import ru.practicum.mainservice.model.request.dto.ParticipationRequestDto; import ru.practicum.mainservice.service.EventService; +import ru.practicum.mainservice.service.MarkService; import ru.practicum.mainservice.service.ParticipationRequestService; @@ -27,6 +26,7 @@ public class PrivateEventController { private final EventService eventService; private final ParticipationRequestService participationRequestService; + private final MarkService markService; @GetMapping("/events") public List getUserEvents(@PathVariable @Positive Integer userId, @@ -77,4 +77,38 @@ public EventRequestStatusUpdateResult updateRequestsStatus( "пользователя с id={}", eventId, userId); return participationRequestService.updateRequestsStatus(userId, eventId, eventRequestStatusUpdateRequest); } + + @PutMapping("/events/{eventId}/likes") + @ResponseStatus(HttpStatus.CREATED) + public void putMark(@PathVariable @Positive Integer userId, + @PathVariable @Positive Integer eventId, + @RequestParam @NotNull Boolean score) { + log.info("Запрос от private контроллера от пользователя с id={} на добавление реакции по событию с id={}", userId, eventId); + markService.putMark(userId, eventId, score); + } + + @DeleteMapping("/events/{eventId}/likes") + @ResponseStatus(HttpStatus.NO_CONTENT) + public void deleteMark(@PathVariable @Positive Integer userId, + @PathVariable @Positive Integer eventId) { + log.info("Запрос от private контроллера от пользователя с id={} на удаление реакции по событию с id={}", userId, eventId); + markService.deleteMark(userId, eventId); + } + + @GetMapping("/events/{eventId}/rating") + public EventFullDtoWithRating getUserEventWithRating(@PathVariable @Positive Integer userId, + @PathVariable @Positive Integer eventId) { + log.info("Запрос от private контроллера от пользователя с id={} на получение подробной информации о событии " + + "с указанием рейтинга события и его инициатора", userId); + return eventService.getEventOfUserWithRating(userId, eventId); + } + + @GetMapping("/events/rating") + public List getEventsWithRating(@PathVariable @Positive Integer userId, + @RequestParam(defaultValue = "0") @PositiveOrZero Integer from, + @RequestParam(defaultValue = "10") @Positive Integer size) { + log.info("Запрос от private контроллера от пользователя с id={} на получение списка событий с наличием рейтинга " + + "с указанием рейтингов событий и их инициаторов с сортировкой по убыванию рейтинга событий", userId); + return eventService.getEventsWithRating(userId, from, size); + } } diff --git a/main-service/src/main/java/ru/practicum/mainservice/mappers/EventMapper.java b/main-service/src/main/java/ru/practicum/mainservice/mappers/EventMapper.java index 4580df0..fb424ed 100644 --- a/main-service/src/main/java/ru/practicum/mainservice/mappers/EventMapper.java +++ b/main-service/src/main/java/ru/practicum/mainservice/mappers/EventMapper.java @@ -5,9 +5,7 @@ import ru.practicum.mainservice.model.enums.EventState; import ru.practicum.mainservice.model.event.Event; import ru.practicum.mainservice.model.event.Location; -import ru.practicum.mainservice.model.event.dto.EventFullDto; -import ru.practicum.mainservice.model.event.dto.EventShortDto; -import ru.practicum.mainservice.model.event.dto.NewEventDto; +import ru.practicum.mainservice.model.event.dto.*; import ru.practicum.mainservice.model.user.User; import java.time.LocalDateTime; @@ -29,7 +27,8 @@ public static Event toEvent(NewEventDto newEventDto, User initiator, Category ca LocalDateTime.now(), newEventDto.getRequestModeration() != null ? newEventDto.getRequestModeration() : true, EventState.PENDING, - newEventDto.getTitle() != null ? newEventDto.getTitle() : "" + newEventDto.getTitle() != null ? newEventDto.getTitle() : "", + 0 ); } @@ -81,4 +80,41 @@ public static EventShortDto toEventShortDto(Event event) { 0 ); } + + public static EventFullDtoWithRating toEventFullDtoWithRating(Event event) { + return new EventFullDtoWithRating( + event.getId(), + event.getAnnotation(), + CategoryMapper.toCategoryDto(event.getCategory()), + event.getConfirmedRequests(), + event.getCreatedOn().format(Constants.DATE_TIME_FORMAT), + event.getDescription(), + event.getEventDate().format(Constants.DATE_TIME_FORMAT), + UserMapper.toUserShortDtoWithRating(event.getInitiator()), + LocationMapper.toLocationDto(event.getLocation()), + event.getPaid(), + event.getParticipantLimit(), + event.getPublishedOn().format(Constants.DATE_TIME_FORMAT), + event.getRequestModeration(), + event.getState().toString(), + event.getTitle(), + 0, + event.getRating() + ); + } + + public static EventShortDtoWithRating toEventShortDtoWithRating(Event event) { + return new EventShortDtoWithRating( + event.getId(), + event.getAnnotation(), + CategoryMapper.toCategoryDto(event.getCategory()), + event.getConfirmedRequests(), + event.getEventDate().format(Constants.DATE_TIME_FORMAT), + UserMapper.toUserShortDtoWithRating(event.getInitiator()), + event.getPaid(), + event.getTitle(), + 0, + event.getRating() + ); + } } diff --git a/main-service/src/main/java/ru/practicum/mainservice/mappers/UserMapper.java b/main-service/src/main/java/ru/practicum/mainservice/mappers/UserMapper.java index 9f646cc..dca3789 100644 --- a/main-service/src/main/java/ru/practicum/mainservice/mappers/UserMapper.java +++ b/main-service/src/main/java/ru/practicum/mainservice/mappers/UserMapper.java @@ -2,7 +2,9 @@ import ru.practicum.mainservice.model.user.User; import ru.practicum.mainservice.model.user.dto.UserDto; +import ru.practicum.mainservice.model.user.dto.UserDtoWithRating; import ru.practicum.mainservice.model.user.dto.UserShortDto; +import ru.practicum.mainservice.model.user.dto.UserShortDtoWithRating; public class UserMapper { public static UserDto toUserDto(User user) { @@ -26,7 +28,25 @@ public static User toUser(UserDto userDto) { return new User( userDto.getId() != null ? userDto.getId() : 0, userDto.getName() != null ? userDto.getName() : "", - userDto.getEmail() != null ? (userDto.getEmail()) : "" + userDto.getEmail() != null ? (userDto.getEmail()) : "", + 0 + ); + } + + public static UserShortDtoWithRating toUserShortDtoWithRating(User user) { + return new UserShortDtoWithRating( + user.getId(), + user.getName(), + user.getRating() + ); + } + + public static UserDtoWithRating toUserDtoWithRating(User user) { + return new UserDtoWithRating( + user.getId(), + user.getName(), + user.getName(), + user.getRating() ); } } diff --git a/main-service/src/main/java/ru/practicum/mainservice/model/Constants.java b/main-service/src/main/java/ru/practicum/mainservice/model/Constants.java index fefd1dd..1c04c6f 100644 --- a/main-service/src/main/java/ru/practicum/mainservice/model/Constants.java +++ b/main-service/src/main/java/ru/practicum/mainservice/model/Constants.java @@ -7,4 +7,6 @@ public class Constants { public static final int FREE_TIME_INTERVAL = 100; public static final int UPDATE_TIME_LIMIT_ADMIN = 1; public static final int UPDATE_TIME_LIMIT_USER = 2; + public static final int CHANGING_RATING_WHEN_CHANGING_MARK = 2; + public static final int RATING_CHANGE_AT_NEW_MARK_OR_DELETE_MARK = 1; } diff --git a/main-service/src/main/java/ru/practicum/mainservice/model/event/Event.java b/main-service/src/main/java/ru/practicum/mainservice/model/event/Event.java index 3277690..e3a6942 100644 --- a/main-service/src/main/java/ru/practicum/mainservice/model/event/Event.java +++ b/main-service/src/main/java/ru/practicum/mainservice/model/event/Event.java @@ -60,4 +60,6 @@ public class Event { private EventState state; @Column(nullable = false) private String title; + @Column(nullable = false) + private int rating; } diff --git a/main-service/src/main/java/ru/practicum/mainservice/model/event/dto/EventFullDtoWithRating.java b/main-service/src/main/java/ru/practicum/mainservice/model/event/dto/EventFullDtoWithRating.java new file mode 100644 index 0000000..eb1e7b6 --- /dev/null +++ b/main-service/src/main/java/ru/practicum/mainservice/model/event/dto/EventFullDtoWithRating.java @@ -0,0 +1,32 @@ +package ru.practicum.mainservice.model.event.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import ru.practicum.mainservice.model.category.dto.CategoryDto; +import ru.practicum.mainservice.model.user.dto.UserShortDtoWithRating; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class EventFullDtoWithRating { + private Integer id; + private String annotation; + private CategoryDto category; + private Integer confirmedRequests; + private String createdOn; + private String description; + private String eventDate; + private UserShortDtoWithRating initiator; + private LocationDto location; + private Boolean paid; + private int participantLimit; + private String publishedOn; + private Boolean requestModeration; + private String state; + private String title; + private int views; + private int rating; +} \ No newline at end of file diff --git a/main-service/src/main/java/ru/practicum/mainservice/model/event/dto/EventShortDtoWithRating.java b/main-service/src/main/java/ru/practicum/mainservice/model/event/dto/EventShortDtoWithRating.java new file mode 100644 index 0000000..4dae80d --- /dev/null +++ b/main-service/src/main/java/ru/practicum/mainservice/model/event/dto/EventShortDtoWithRating.java @@ -0,0 +1,25 @@ +package ru.practicum.mainservice.model.event.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import ru.practicum.mainservice.model.category.dto.CategoryDto; +import ru.practicum.mainservice.model.user.dto.UserShortDtoWithRating; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class EventShortDtoWithRating { + protected Integer id; + protected String annotation; + protected CategoryDto category; + protected Integer confirmedRequests; + protected String eventDate; + protected UserShortDtoWithRating initiator; + protected Boolean paid; + protected String title; + protected int views; + protected int rating; +} diff --git a/main-service/src/main/java/ru/practicum/mainservice/model/mark/Mark.java b/main-service/src/main/java/ru/practicum/mainservice/model/mark/Mark.java new file mode 100644 index 0000000..0a4f15c --- /dev/null +++ b/main-service/src/main/java/ru/practicum/mainservice/model/mark/Mark.java @@ -0,0 +1,35 @@ +package ru.practicum.mainservice.model.mark; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.hibernate.type.NumericBooleanConverter; +import ru.practicum.mainservice.model.event.Event; +import ru.practicum.mainservice.model.user.User; + +@Entity +@Table(name = "MARKS", schema = "PUBLIC") +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class Mark { + @Id + @Column(name = "MARK_ID", nullable = false) + @GeneratedValue(strategy = GenerationType.IDENTITY) + protected int id; + @ManyToOne(fetch = FetchType.LAZY) + @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"}) + @JoinColumn(name = "EVALUATOR_ID") + protected User evaluator; + @ManyToOne(fetch = FetchType.LAZY) + @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"}) + @JoinColumn(name = "EVENT_ID") + protected Event event; + @Column(nullable = false) + @Convert(converter = NumericBooleanConverter.class) + protected Boolean score; +} diff --git a/main-service/src/main/java/ru/practicum/mainservice/model/user/User.java b/main-service/src/main/java/ru/practicum/mainservice/model/user/User.java index b22e5c0..6db4710 100644 --- a/main-service/src/main/java/ru/practicum/mainservice/model/user/User.java +++ b/main-service/src/main/java/ru/practicum/mainservice/model/user/User.java @@ -19,4 +19,6 @@ public class User { private String name; @Column(nullable = false) private String email; + @Column(nullable = false) + private int rating; } diff --git a/main-service/src/main/java/ru/practicum/mainservice/model/user/dto/UserDtoWithRating.java b/main-service/src/main/java/ru/practicum/mainservice/model/user/dto/UserDtoWithRating.java new file mode 100644 index 0000000..748422e --- /dev/null +++ b/main-service/src/main/java/ru/practicum/mainservice/model/user/dto/UserDtoWithRating.java @@ -0,0 +1,15 @@ +package ru.practicum.mainservice.model.user.dto; + +import lombok.*; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@ToString +public class UserDtoWithRating { + private int id; + private String name; + private String email; + private int rating; +} \ No newline at end of file diff --git a/main-service/src/main/java/ru/practicum/mainservice/model/user/dto/UserShortDtoWithRating.java b/main-service/src/main/java/ru/practicum/mainservice/model/user/dto/UserShortDtoWithRating.java new file mode 100644 index 0000000..c429bfb --- /dev/null +++ b/main-service/src/main/java/ru/practicum/mainservice/model/user/dto/UserShortDtoWithRating.java @@ -0,0 +1,13 @@ +package ru.practicum.mainservice.model.user.dto; + +import lombok.*; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class UserShortDtoWithRating { + private int id; + private String name; + private int rating; +} \ No newline at end of file diff --git a/main-service/src/main/java/ru/practicum/mainservice/repository/EventRepository.java b/main-service/src/main/java/ru/practicum/mainservice/repository/EventRepository.java index 2b1f9d2..a0862a3 100644 --- a/main-service/src/main/java/ru/practicum/mainservice/repository/EventRepository.java +++ b/main-service/src/main/java/ru/practicum/mainservice/repository/EventRepository.java @@ -42,4 +42,9 @@ Page findByParametersForAdmin(@Param("users") List users, @Param("categories") List categories, @Param("start") LocalDateTime rangeStart, @Param("end") LocalDateTime rangeEnd, Pageable pageable); + + @Query("SELECT e FROM Event AS e " + + "WHERE e.rating <> 0 " + + "ORDER BY e.rating DESC") + Page findAllWhereRatingNotEqualToZeroSortByRatingDesc(Pageable pageable); } diff --git a/main-service/src/main/java/ru/practicum/mainservice/repository/MarkRepository.java b/main-service/src/main/java/ru/practicum/mainservice/repository/MarkRepository.java new file mode 100644 index 0000000..b75b6aa --- /dev/null +++ b/main-service/src/main/java/ru/practicum/mainservice/repository/MarkRepository.java @@ -0,0 +1,9 @@ +package ru.practicum.mainservice.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import ru.practicum.mainservice.model.mark.Mark; + +public interface MarkRepository extends JpaRepository { + + Mark findOneByEvaluator_IdAndEvent_Id(int evaluatorId, int eventId); +} diff --git a/main-service/src/main/java/ru/practicum/mainservice/repository/UserRepository.java b/main-service/src/main/java/ru/practicum/mainservice/repository/UserRepository.java index f2202fe..4c9c07d 100644 --- a/main-service/src/main/java/ru/practicum/mainservice/repository/UserRepository.java +++ b/main-service/src/main/java/ru/practicum/mainservice/repository/UserRepository.java @@ -17,4 +17,9 @@ public interface UserRepository extends JpaRepository { Page findUsersForAdmin(@Param("ids") List ids, Pageable pageable); List findAllByEmail(String email); + + @Query("SELECT u FROM User AS u " + + "WHERE u.rating <> 0 " + + "ORDER BY u.rating") + Page findAllWhereRatingNotEqualToZeroSortByRating(Pageable pageable); } diff --git a/main-service/src/main/java/ru/practicum/mainservice/service/EventService.java b/main-service/src/main/java/ru/practicum/mainservice/service/EventService.java index a325f43..afd25b4 100644 --- a/main-service/src/main/java/ru/practicum/mainservice/service/EventService.java +++ b/main-service/src/main/java/ru/practicum/mainservice/service/EventService.java @@ -26,10 +26,7 @@ import ru.practicum.mainservice.model.enums.UserStateAction; import ru.practicum.mainservice.model.event.Event; import ru.practicum.mainservice.model.event.Location; -import ru.practicum.mainservice.model.event.dto.EventFullDto; -import ru.practicum.mainservice.model.event.dto.EventShortDto; -import ru.practicum.mainservice.model.event.dto.NewEventDto; -import ru.practicum.mainservice.model.event.dto.UpdateEventRequest; +import ru.practicum.mainservice.model.event.dto.*; import ru.practicum.mainservice.model.user.User; import ru.practicum.mainservice.repository.EventRepository; import ru.practicum.mainservice.searchparams.PresentationParameters; @@ -372,4 +369,45 @@ public List getEventsWithFilteringForAdmin(SearchParametersAdmin s public Event getEvent(int eventId) { return eventRepository.getReferenceById(eventId); } + + @Transactional(readOnly = true) + public EventFullDtoWithRating getEventOfUserWithRating(int userId, int eventId) { + Event event = getEvent(eventId); + if (event.getInitiator().getId() != userId) { + throw new ConflictValidationException("Нельзя просматривать чужие события"); + } + List urisInList = new ArrayList<>(); + urisInList.add("/events/" + eventId); + String[] uris = urisInList.toArray(new String[0]); + Map statistic = getHitsStatistic(uris); + EventFullDtoWithRating eventFullDtoWithRating = EventMapper.toEventFullDtoWithRating(event); + if (statistic.get(eventFullDtoWithRating.getId()) != null) { + eventFullDtoWithRating.setViews(statistic.get(eventFullDtoWithRating.getId())); + } + return eventFullDtoWithRating; + } + + @Transactional(readOnly = true) + public List getEventsWithRating(int userId, int from, int size) { + User user = userService.getUser(userId); + Pageable pageable = PageRequest.of(from / size, size); + Page events; + events = eventRepository.findAllWhereRatingNotEqualToZeroSortByRatingDesc(pageable); + List shortEventsDtoWithRating = events + .stream() + .map(EventMapper::toEventShortDtoWithRating) + .collect(Collectors.toList()); + List urisInList = new ArrayList<>(); + for (EventShortDtoWithRating event : shortEventsDtoWithRating) { + urisInList.add("/events/" + event.getId()); + } + String[] uris = urisInList.toArray(new String[0]); + Map statistic = getHitsStatistic(uris); + for (EventShortDtoWithRating eventShotDtoWithRating : shortEventsDtoWithRating) { + if (statistic.get(eventShotDtoWithRating.getId()) != null) { + eventShotDtoWithRating.setViews(statistic.get(eventShotDtoWithRating.getId())); + } + } + return shortEventsDtoWithRating; + } } diff --git a/main-service/src/main/java/ru/practicum/mainservice/service/MarkService.java b/main-service/src/main/java/ru/practicum/mainservice/service/MarkService.java new file mode 100644 index 0000000..af7b372 --- /dev/null +++ b/main-service/src/main/java/ru/practicum/mainservice/service/MarkService.java @@ -0,0 +1,106 @@ +package ru.practicum.mainservice.service; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import ru.practicum.mainservice.exception.BadRequestValidationException; +import ru.practicum.mainservice.model.Constants; +import ru.practicum.mainservice.model.event.Event; +import ru.practicum.mainservice.model.request.ParticipationRequest; +import ru.practicum.mainservice.model.user.User; +import ru.practicum.mainservice.repository.MarkRepository; +import ru.practicum.mainservice.model.mark.Mark; +import ru.practicum.mainservice.model.enums.ParticipationRequestStatus; + +@Slf4j +@Service +@RequiredArgsConstructor +public class MarkService { + private final MarkRepository markRepository; + private final EventService eventService; + private final UserService userService; + private final ParticipationRequestService participationRequestService; + + @Transactional + public void saveMark(Mark mark) { + markRepository.save(mark); + } + + @Transactional + public void deleteMark(Mark mark) { + markRepository.delete(mark); + } + + @Transactional(readOnly = true) + public Mark findMarkByEvaluatorAndEvent(int evaluatorId, int eventId) { + return markRepository.findOneByEvaluator_IdAndEvent_Id(evaluatorId, eventId); + } + + @Transactional + public void putMark(int userId, int eventId, Boolean score) { + Mark mark = markRepository.findOneByEvaluator_IdAndEvent_Id(userId, eventId); + ; + if (mark != null) { + Event event = eventService.getEvent(eventId); + User initiator = userService.getUser(event.getInitiator().getId()); + if (!mark.getScore().toString().equals(score.toString())) { + if (mark.getScore()) { + event.setRating(event.getRating() - Constants.CHANGING_RATING_WHEN_CHANGING_MARK); + initiator.setRating(initiator.getRating() - Constants.CHANGING_RATING_WHEN_CHANGING_MARK); + } else { + event.setRating(event.getRating() + Constants.CHANGING_RATING_WHEN_CHANGING_MARK); + initiator.setRating(initiator.getRating() + Constants.CHANGING_RATING_WHEN_CHANGING_MARK); + } + mark.setScore(score); + eventService.save(event); + markRepository.save(mark); + userService.saveUser(initiator); + } + } else { + ParticipationRequest request = participationRequestService.getRequestByEventAndRequester(eventId, userId); + if (request == null) { + throw new BadRequestValidationException("Оценивать событие могут только его участники"); + } + Event event = eventService.getEvent(eventId); + if (event.getParticipantLimit() == 0 || !event.getRequestModeration() || request.getStatus().equals(ParticipationRequestStatus.CONFIRMED)) { + User evaluator = userService.getUser(userId); + mark = new Mark(0, evaluator, event, score); + markRepository.save(mark); + User initiator = userService.getUser(event.getInitiator().getId()); + if (score) { + event.setRating(event.getRating() + Constants.RATING_CHANGE_AT_NEW_MARK_OR_DELETE_MARK); + initiator.setRating(initiator.getRating() + Constants.RATING_CHANGE_AT_NEW_MARK_OR_DELETE_MARK); + } else { + event.setRating(event.getRating() - Constants.RATING_CHANGE_AT_NEW_MARK_OR_DELETE_MARK); + initiator.setRating(initiator.getRating() - Constants.RATING_CHANGE_AT_NEW_MARK_OR_DELETE_MARK); + } + eventService.save(event); + markRepository.save(mark); + userService.saveUser(initiator); + } else { + throw new BadRequestValidationException("Оценивать событие могут только его участники"); + } + } + } + + @Transactional + public void deleteMark(int userId, int eventId) { + Mark mark = markRepository.findOneByEvaluator_IdAndEvent_Id(userId, eventId); + ; + if (mark != null) { + Event event = eventService.getEvent(eventId); + User initiator = userService.getUser(event.getInitiator().getId()); + if (mark.getScore()) { + event.setRating(event.getRating() - Constants.RATING_CHANGE_AT_NEW_MARK_OR_DELETE_MARK); + initiator.setRating(initiator.getRating() - Constants.RATING_CHANGE_AT_NEW_MARK_OR_DELETE_MARK); + } else { + event.setRating(event.getRating() + Constants.RATING_CHANGE_AT_NEW_MARK_OR_DELETE_MARK); + initiator.setRating(initiator.getRating() + Constants.RATING_CHANGE_AT_NEW_MARK_OR_DELETE_MARK); + } + eventService.save(event); + userService.saveUser(initiator); + markRepository.delete(mark); + } + } +} diff --git a/main-service/src/main/java/ru/practicum/mainservice/service/UserService.java b/main-service/src/main/java/ru/practicum/mainservice/service/UserService.java index 936a0be..52f4c3d 100644 --- a/main-service/src/main/java/ru/practicum/mainservice/service/UserService.java +++ b/main-service/src/main/java/ru/practicum/mainservice/service/UserService.java @@ -12,6 +12,7 @@ import ru.practicum.mainservice.mappers.UserMapper; import ru.practicum.mainservice.model.user.User; import ru.practicum.mainservice.model.user.dto.UserDto; +import ru.practicum.mainservice.model.user.dto.UserDtoWithRating; import ru.practicum.mainservice.repository.UserRepository; import java.util.List; @@ -60,4 +61,14 @@ public void deleteUser(int userId) { public User getUser(int userId) { return userRepository.getReferenceById(userId); } + + @Transactional(readOnly = true) + public List getUsersWithRating(int from, int size) { + Pageable pageable = PageRequest.of(from / size, size); + Page users; + users = userRepository.findAllWhereRatingNotEqualToZeroSortByRating(pageable); + return users.stream() + .map(UserMapper::toUserDtoWithRating) + .collect(Collectors.toList()); + } } diff --git a/main-service/src/main/resources/schema.sql b/main-service/src/main/resources/schema.sql index 9e0107b..f0a44d5 100644 --- a/main-service/src/main/resources/schema.sql +++ b/main-service/src/main/resources/schema.sql @@ -12,6 +12,7 @@ CREATE TABLE IF NOT EXISTS PUBLIC.USERS USER_ID INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, NAME VARCHAR(250) NOT NULL, EMAIL VARCHAR(254) NOT NULL, + RATING INTEGER NOT NULL, CONSTRAINT UQ_USER_EMAIL UNIQUE (EMAIL) ); @@ -52,7 +53,8 @@ CREATE TABLE IF NOT EXISTS PUBLIC.EVENTS PUBLISHED_ON TIMESTAMP WITHOUT TIME ZONE, REQUEST_MODERATION INTEGER NOT NULL, STATE INTEGER NOT NULL, - TITLE VARCHAR(120) NOT NULL + TITLE VARCHAR(120) NOT NULL, + RATING INTEGER NOT NULL ); @@ -65,6 +67,15 @@ CREATE TABLE IF NOT EXISTS PUBLIC.PARTICIPATION_REQUESTS STATUS INTEGER NOT NULL ); +CREATE TABLE IF NOT EXISTS PUBLIC.MARKS +( + MARK_ID INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + EVALUATOR_ID INTEGER REFERENCES PUBLIC.USERS (USER_ID) ON DELETE CASCADE, + EVENT_ID INTEGER REFERENCES PUBLIC.EVENTS (EVENT_ID) ON DELETE CASCADE, + SCORE INTEGER NOT NULL, + CONSTRAINT uq_evaluator_event UNIQUE (EVALUATOR_ID, EVENT_ID) +); + CREATE TABLE IF NOT EXISTS PUBLIC.EVENT_COMPILATIONS ( PAIR_ID INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, From af37be5c037424172014519e59ba423c9349632e Mon Sep 17 00:00:00 2001 From: Siustoster Date: Thu, 19 Sep 2024 00:37:53 +0300 Subject: [PATCH 2/4] =?UTF-8?q?=D1=8D=D1=82=D0=B0=D0=BF=203?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- postman/feature.json | 536 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 536 insertions(+) create mode 100644 postman/feature.json diff --git a/postman/feature.json b/postman/feature.json new file mode 100644 index 0000000..68ac92e --- /dev/null +++ b/postman/feature.json @@ -0,0 +1,536 @@ +{ + "info": { + "_postman_id": "1d725d38-0a3e-480d-98f8-39a6740f89c7", + "name": "feature", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "32844178" + }, + "item": [ + { + "name": "Добавление нового лайка", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Ответ должен содержать код статуса 201\", function () {", + " pm.response.to.have.status(201);", + "});" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "PUT", + "header": [], + "url": { + "raw": "http://localhost:8080/users/104/events/86/likes?score=true", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "users", + "104", + "events", + "86", + "likes" + ], + "query": [ + { + "key": "score", + "value": "true" + } + ] + } + }, + "response": [] + }, + { + "name": "Получение события с рейтингом", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Ответ должен содержать код статуса 200 и данные в формате json\", function () {", + " pm.response.to.have.status(200);", + " pm.response.to.be.withBody;", + " pm.response.to.be.json;", + "});" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "http://localhost:8080/users/103/events/86/rating", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "users", + "103", + "events", + "86", + "rating" + ] + } + }, + "response": [] + }, + { + "name": "Получение событий с рейтингом", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "test", + "script": { + "exec": [ + "const body = pm.response.json();", + "", + "pm.test(\"Ответ должен содержать код статуса 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Ответ должен содержать список объектов\", function () {", + " pm.expect(body).is.an('array');", + "});" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "http://localhost:8080/users/104/events/rating?from=0&size=20", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "users", + "104", + "events", + "rating" + ], + "query": [ + { + "key": "from", + "value": "0" + }, + { + "key": "size", + "value": "20" + } + ] + } + }, + "response": [] + }, + { + "name": "Получение пользователей с рейтингом", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "test", + "script": { + "exec": [ + "const body = pm.response.json();", + "", + "pm.test(\"Ответ должен содержать код статуса 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Ответ должен содержать список объектов\", function () {", + " pm.expect(body).is.an('array');", + "});" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "http://localhost:8080/admin/users/rating", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "admin", + "users", + "rating" + ] + } + }, + "response": [] + }, + { + "name": "Удаление лайка", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Ответ должен содержать код статуса 204\", function () {", + " pm.response.to.have.status(204);", + "});" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "const main = async () => {\r", + " const api = new API(pm);\r", + " const rnd = new RandomUtils();\r", + "\r", + " try {\r", + " const user = await api.addUser(rnd.getUser());\r", + " const category = await api.addCategory(rnd.getCategory());\r", + " let eventBody = rnd.getEvent(category.id);\r", + " eventBody['requestModeration'] = false\r", + " let event = await api.addEvent(user.id, eventBody);\r", + " event = await api.publishEvent(event.id);\r", + " const submittedUser = await api.addUser(rnd.getUser());\r", + " await api.publishParticipationRequest(event.id,submittedUser.id);\r", + " await api.addLike(event.id,submittedUser.id,\"true\");\r", + " pm.collectionVariables.set('uid',submittedUser.id);\r", + " pm.collectionVariables.set('eid', event.id);\r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " // выполняем наш скрипт\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "DELETE", + "header": [], + "url": { + "raw": "http://localhost:8080/users/:userId/events/:eventId/likes", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "users", + ":userId", + "events", + ":eventId", + "likes" + ], + "variable": [ + { + "key": "userId", + "value": "{{uid}}" + }, + { + "key": "eventId", + "value": "{{eid}}" + } + ] + } + }, + "response": [] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "packages": {}, + "exec": [ + "API = class {\r", + " constructor(postman, verbose = false, baseUrl = \"http://localhost:8080\") {\r", + " this.baseUrl = baseUrl;\r", + " this.pm = postman;\r", + " this._verbose = verbose;\r", + " }\r", + "\r", + " async addUser(user, verbose=null) {\r", + " return this.post(\"/admin/users\", user, \"Ошибка при добавлении нового пользователя: \", verbose);\r", + " }\r", + "\r", + " async addCategory(category, verbose=null) {\r", + " return this.post(\"/admin/categories\", category, \"Ошибка при добавлении новой категории: \", verbose);\r", + " }\r", + "\r", + " async addEvent(userId, event, verbose=null) {\r", + " return this.post(\"/users/\" + userId + \"/events\", event, \"Ошибка при добавлении нового события: \", verbose);\r", + " }\r", + "\r", + " async addCompilation(compilation, verbose=null) {\r", + " return this.post(\"/admin/compilations\", compilation, \"Ошибка при добавлении новой подборки: \", verbose);\r", + " }\r", + "\r", + " async publishParticipationRequest(eventId, userId, verbose=null) {\r", + " return this.post('/users/' + userId + '/requests?eventId=' + eventId, null, \"Ошибка при добавлении нового запроса на участие в событии\", verbose);\r", + " }\r", + "\r", + " async addLike(eventId, userId, bLike, verbose=null) {\r", + " return this.put('/users/' + userId + '/events/' + eventId + '/likes?score=' + bLike, \"Ошибка при добавлении лайка\", verbose);\r", + " }\r", + " async publishEvent(eventId, verbose=null) {\r", + " return this.patch('/admin/events/' + eventId, {stateAction: \"PUBLISH_EVENT\"}, \"Ошибка при публикации события\", verbose);\r", + " }\r", + " \r", + " async rejectEvent(eventId, verbose=null) {\r", + " return this.patch('/admin/events/' + eventId, {stateAction: \"REJECT_EVENT\"}, \"Ошибка при отмене события\", verbose);\r", + " }\r", + "\r", + " async acceptParticipationRequest(eventId, userId, reqId, verbose=null) {\r", + " return this.patch('/users/' + userId + '/events/' + eventId + '/requests', {requestIds:[reqId], status: \"CONFIRMED\"}, \"Ошибка при принятии заявки на участие в событии\", verbose);\r", + " }\r", + "\r", + " async findCategory(catId, verbose=null) {\r", + " return this.get('/categories/' + catId, null, \"Ошибка при поиске категории по id\", verbose);\r", + " }\r", + "\r", + " async findCompilation(compId, verbose=null) {\r", + " return this.get('/compilations/' + compId, null, \"Ошибка при поиске подборки по id\", verbose);\r", + " }\r", + "\r", + " async findEvent(eventId, verbose=null) {\r", + " return this.get('/events/' + eventId, null, \"Ошибка при поиске события по id\", verbose);\r", + " }\r", + "\r", + " async findUser(userId, verbose=null) {\r", + " return this.get('/admin/users?ids=' + userId, null, \"Ошибка при поиске пользователя по id\", verbose);\r", + " }\r", + "\r", + " async put(path, body, errorText = \"Ошибка при выполнении put-запроса: \", verbose=null) {\r", + " return this.sendRequest(\"PUT\", path, body, errorText, verbose);\r", + " }\r", + " async post(path, body, errorText = \"Ошибка при выполнении post-запроса: \", verbose=null) {\r", + " return this.sendRequest(\"POST\", path, body, errorText, verbose);\r", + " }\r", + "\r", + " async patch(path, body = null, errorText = \"Ошибка при выполнении patch-запроса: \", verbose=null) {\r", + " return this.sendRequest(\"PATCH\", path, body, errorText, verbose);\r", + " }\r", + "\r", + " async get(path, body = null, errorText = \"Ошибка при выполнении get-запроса: \", verbose=null) {\r", + " return this.sendRequest(\"GET\", path, body, errorText, verbose);\r", + " }\r", + " async sendRequest(method, path, body=null, errorText = \"Ошибка при выполнении запроса: \", verbose=null) {\r", + " return new Promise((resolve, reject) => {\r", + " verbose = verbose == null ? this._verbose : verbose;\r", + " const request = {\r", + " url: this.baseUrl + path,\r", + " method: method,\r", + " body: body == null ? \"\" : JSON.stringify(body),\r", + " header: { \"Content-Type\": \"application/json\" },\r", + " };\r", + " if(verbose) {\r", + " console.log(\"Отправляю запрос: \", request);\r", + " }\r", + "\r", + " try {\r", + " this.pm.sendRequest(request, (error, response) => {\r", + " if(error || (response.code >= 400 && response.code <= 599)) {\r", + " let err = error ? error : JSON.stringify(response.json());\r", + " console.error(\"При выполнении запроса к серверу возникла ошика.\\n\", err,\r", + " \"\\nДля отладки проблемы повторите такой же запрос к вашей программе \" + \r", + " \"на локальном компьютере. Данные запроса:\\n\", JSON.stringify(request));\r", + "\r", + " reject(new Error(errorText + err));\r", + " }\r", + " if(verbose) {\r", + " console.log(\"Результат обработки запроса: код состояния - \", response.code, \", тело: \", response.json());\r", + " }\r", + " if (response.stream.length === 0){\r", + " reject(new Error('Отправлено пустое тело ответа'))\r", + " }else{\r", + " resolve(response.json());\r", + " }\r", + " });\r", + " \r", + " } catch(err) {\r", + " if(verbose) {\r", + " console.error(errorText, err);\r", + " }\r", + " return Promise.reject(err);\r", + " }\r", + " });\r", + " }\r", + "};\r", + "\r", + "RandomUtils = class {\r", + " constructor() {}\r", + "\r", + " getUser() {\r", + " return {\r", + " name: pm.variables.replaceIn('{{$randomFullName}}'),\r", + " email: pm.variables.replaceIn('{{$randomEmail}}')\r", + " };\r", + " }\r", + "\r", + " getCategory() {\r", + " return {\r", + " name: pm.variables.replaceIn('{{$randomWord}}') + Math.floor(Math.random() * 10000 * Math.random()).toString()\r", + " };\r", + " }\r", + "\r", + " getEvent(categoryId) {\r", + " return {\r", + " annotation: pm.variables.replaceIn('{{$randomLoremParagraph}}'),\r", + " category: categoryId,\r", + " description: pm.variables.replaceIn('{{$randomLoremParagraphs}}'),\r", + " eventDate: this.getFutureDateTime(),\r", + " location: {\r", + " lat: parseFloat(pm.variables.replaceIn('{{$randomLatitude}}')),\r", + " lon: parseFloat(pm.variables.replaceIn('{{$randomLongitude}}')),\r", + " },\r", + " paid: pm.variables.replaceIn('{{$randomBoolean}}'),\r", + " participantLimit: pm.variables.replaceIn('{{$randomInt}}'),\r", + " requestModeration: pm.variables.replaceIn('{{$randomBoolean}}'),\r", + " title: pm.variables.replaceIn('{{$randomLoremSentence}}'),\r", + " }\r", + " }\r", + "\r", + " getCompilation(...eventIds) {\r", + " return {\r", + " title: pm.variables.replaceIn('{{$randomLoremSentence}}').slice(0, 50),\r", + " pinned: pm.variables.replaceIn('{{$randomBoolean}}'),\r", + " events: eventIds\r", + " };\r", + " }\r", + "\r", + "\r", + " getFutureDateTime(hourShift = 5, minuteShift=0, yearShift=0) {\r", + " let moment = require('moment');\r", + "\r", + " let m = moment();\r", + " m.add(hourShift, 'hour');\r", + " m.add(minuteShift, 'minute');\r", + " m.add(yearShift, 'year');\r", + "\r", + " return m.format('YYYY-MM-DD HH:mm:ss');\r", + " }\r", + "\r", + " getWord(length = 1) {\r", + " let result = '';\r", + " const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';\r", + " const charactersLength = characters.length;\r", + " let counter = 0;\r", + " while (counter < length) {\r", + " result += characters.charAt(Math.floor(Math.random() * charactersLength));\r", + " counter += 1;\r", + " }\r", + " return result;\r", + " }\r", + "}" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "packages": {}, + "exec": [ + "" + ] + } + } + ], + "variable": [ + { + "key": "userId", + "value": "104" + }, + { + "key": "userId", + "value": "" + }, + { + "key": "uid", + "value": "" + }, + { + "key": "eid", + "value": "" + } + ] +} \ No newline at end of file From bd3a0d495dde73bc360edf73b44f36fcf01d658d Mon Sep 17 00:00:00 2001 From: Siustoster Date: Thu, 19 Sep 2024 00:44:07 +0300 Subject: [PATCH 3/4] =?UTF-8?q?=D1=8D=D1=82=D0=B0=D0=BF=203?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- postman/feature.json | 104 +++++++++++++++++++++++++++++++++++++++---- 2 files changed, 97 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 18a246e..2410627 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,2 @@ # java-explore-with-me -Template repository for ExploreWithMe project. +https://github.com/Siustoster/java-explore-with-me/pull/3 diff --git a/postman/feature.json b/postman/feature.json index 68ac92e..cc0cc42 100644 --- a/postman/feature.json +++ b/postman/feature.json @@ -13,7 +13,41 @@ "listen": "prerequest", "script": { "exec": [ - "" + "const main = async () => {\r", + " const api = new API(pm);\r", + " const rnd = new RandomUtils();\r", + "\r", + " try {\r", + " const user = await api.addUser(rnd.getUser());\r", + " const category = await api.addCategory(rnd.getCategory());\r", + " let eventBody = rnd.getEvent(category.id);\r", + " eventBody['requestModeration'] = false\r", + " let event = await api.addEvent(user.id, eventBody);\r", + " event = await api.publishEvent(event.id);\r", + " const submittedUser = await api.addUser(rnd.getUser());\r", + " await api.publishParticipationRequest(event.id,submittedUser.id);\r", + " pm.collectionVariables.set('uid',submittedUser.id);\r", + " pm.collectionVariables.set('eid',event.id);\r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " // выполняем наш скрипт\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" ], "type": "text/javascript", "packages": {} @@ -36,7 +70,7 @@ "method": "PUT", "header": [], "url": { - "raw": "http://localhost:8080/users/104/events/86/likes?score=true", + "raw": "http://localhost:8080/users/:userId/events/:eid/likes?score=true", "protocol": "http", "host": [ "localhost" @@ -44,9 +78,9 @@ "port": "8080", "path": [ "users", - "104", + ":userId", "events", - "86", + ":eid", "likes" ], "query": [ @@ -54,6 +88,16 @@ "key": "score", "value": "true" } + ], + "variable": [ + { + "key": "userId", + "value": "{{uid}}" + }, + { + "key": "eid", + "value": "{{eid}}" + } ] } }, @@ -66,7 +110,41 @@ "listen": "prerequest", "script": { "exec": [ - "" + "const main = async () => {\r", + " const api = new API(pm);\r", + " const rnd = new RandomUtils();\r", + "\r", + " try {\r", + " const user = await api.addUser(rnd.getUser());\r", + " const category = await api.addCategory(rnd.getCategory());\r", + " let eventBody = rnd.getEvent(category.id);\r", + " eventBody['requestModeration'] = false\r", + " let event = await api.addEvent(user.id, eventBody);\r", + " event = await api.publishEvent(event.id);\r", + " const submittedUser = await api.addUser(rnd.getUser());\r", + " await api.publishParticipationRequest(event.id,submittedUser.id);\r", + " pm.collectionVariables.set('uid',user.id);\r", + " pm.collectionVariables.set('eid',event.id);\r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " // выполняем наш скрипт\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" ], "type": "text/javascript", "packages": {} @@ -91,7 +169,7 @@ "method": "GET", "header": [], "url": { - "raw": "http://localhost:8080/users/103/events/86/rating", + "raw": "http://localhost:8080/users/:uid/events/:eid/rating", "protocol": "http", "host": [ "localhost" @@ -99,10 +177,20 @@ "port": "8080", "path": [ "users", - "103", + ":uid", "events", - "86", + ":eid", "rating" + ], + "variable": [ + { + "key": "uid", + "value": "{{uid}}" + }, + { + "key": "eid", + "value": "{{eid}}" + } ] } }, From be1a04a367ae89afbaeb62bd7f9a43dbc34b6ca7 Mon Sep 17 00:00:00 2001 From: Siustoster Date: Thu, 19 Sep 2024 11:25:19 +0300 Subject: [PATCH 4/4] =?UTF-8?q?=D1=8D=D1=82=D0=B0=D0=BF=203=20=D0=BF=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B5=20=D1=80=D0=B5=D0=B2=D1=8C=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/PrivateEventController.java | 8 +- .../model/{mark/Mark.java => rate/Rate.java} | 12 +-- .../repository/MarkRepository.java | 9 --- .../repository/RateRepository.java | 9 +++ .../{MarkService.java => RateService.java} | 76 +++++++------------ 5 files changed, 47 insertions(+), 67 deletions(-) rename main-service/src/main/java/ru/practicum/mainservice/model/{mark/Mark.java => rate/Rate.java} (84%) delete mode 100644 main-service/src/main/java/ru/practicum/mainservice/repository/MarkRepository.java create mode 100644 main-service/src/main/java/ru/practicum/mainservice/repository/RateRepository.java rename main-service/src/main/java/ru/practicum/mainservice/service/{MarkService.java => RateService.java} (57%) diff --git a/main-service/src/main/java/ru/practicum/mainservice/controller/PrivateEventController.java b/main-service/src/main/java/ru/practicum/mainservice/controller/PrivateEventController.java index fdb8967..058c06a 100644 --- a/main-service/src/main/java/ru/practicum/mainservice/controller/PrivateEventController.java +++ b/main-service/src/main/java/ru/practicum/mainservice/controller/PrivateEventController.java @@ -13,7 +13,7 @@ import ru.practicum.mainservice.model.request.dto.EventRequestStatusUpdateResult; import ru.practicum.mainservice.model.request.dto.ParticipationRequestDto; import ru.practicum.mainservice.service.EventService; -import ru.practicum.mainservice.service.MarkService; +import ru.practicum.mainservice.service.RateService; import ru.practicum.mainservice.service.ParticipationRequestService; @@ -26,7 +26,7 @@ public class PrivateEventController { private final EventService eventService; private final ParticipationRequestService participationRequestService; - private final MarkService markService; + private final RateService rateService; @GetMapping("/events") public List getUserEvents(@PathVariable @Positive Integer userId, @@ -84,7 +84,7 @@ public void putMark(@PathVariable @Positive Integer userId, @PathVariable @Positive Integer eventId, @RequestParam @NotNull Boolean score) { log.info("Запрос от private контроллера от пользователя с id={} на добавление реакции по событию с id={}", userId, eventId); - markService.putMark(userId, eventId, score); + rateService.putMark(userId, eventId, score); } @DeleteMapping("/events/{eventId}/likes") @@ -92,7 +92,7 @@ public void putMark(@PathVariable @Positive Integer userId, public void deleteMark(@PathVariable @Positive Integer userId, @PathVariable @Positive Integer eventId) { log.info("Запрос от private контроллера от пользователя с id={} на удаление реакции по событию с id={}", userId, eventId); - markService.deleteMark(userId, eventId); + rateService.deleteMark(userId, eventId); } @GetMapping("/events/{eventId}/rating") diff --git a/main-service/src/main/java/ru/practicum/mainservice/model/mark/Mark.java b/main-service/src/main/java/ru/practicum/mainservice/model/rate/Rate.java similarity index 84% rename from main-service/src/main/java/ru/practicum/mainservice/model/mark/Mark.java rename to main-service/src/main/java/ru/practicum/mainservice/model/rate/Rate.java index 0a4f15c..1cdc996 100644 --- a/main-service/src/main/java/ru/practicum/mainservice/model/mark/Mark.java +++ b/main-service/src/main/java/ru/practicum/mainservice/model/rate/Rate.java @@ -1,4 +1,4 @@ -package ru.practicum.mainservice.model.mark; +package ru.practicum.mainservice.model.rate; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import jakarta.persistence.*; @@ -16,20 +16,20 @@ @Setter @AllArgsConstructor @NoArgsConstructor -public class Mark { +public class Rate { @Id @Column(name = "MARK_ID", nullable = false) @GeneratedValue(strategy = GenerationType.IDENTITY) - protected int id; + private int id; @ManyToOne(fetch = FetchType.LAZY) @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"}) @JoinColumn(name = "EVALUATOR_ID") - protected User evaluator; + private User evaluator; @ManyToOne(fetch = FetchType.LAZY) @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"}) @JoinColumn(name = "EVENT_ID") - protected Event event; + private Event event; @Column(nullable = false) @Convert(converter = NumericBooleanConverter.class) - protected Boolean score; + private Boolean score; } diff --git a/main-service/src/main/java/ru/practicum/mainservice/repository/MarkRepository.java b/main-service/src/main/java/ru/practicum/mainservice/repository/MarkRepository.java deleted file mode 100644 index b75b6aa..0000000 --- a/main-service/src/main/java/ru/practicum/mainservice/repository/MarkRepository.java +++ /dev/null @@ -1,9 +0,0 @@ -package ru.practicum.mainservice.repository; - -import org.springframework.data.jpa.repository.JpaRepository; -import ru.practicum.mainservice.model.mark.Mark; - -public interface MarkRepository extends JpaRepository { - - Mark findOneByEvaluator_IdAndEvent_Id(int evaluatorId, int eventId); -} diff --git a/main-service/src/main/java/ru/practicum/mainservice/repository/RateRepository.java b/main-service/src/main/java/ru/practicum/mainservice/repository/RateRepository.java new file mode 100644 index 0000000..3629a46 --- /dev/null +++ b/main-service/src/main/java/ru/practicum/mainservice/repository/RateRepository.java @@ -0,0 +1,9 @@ +package ru.practicum.mainservice.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import ru.practicum.mainservice.model.rate.Rate; + +public interface RateRepository extends JpaRepository { + + Rate findOneByEvaluator_IdAndEvent_Id(int evaluatorId, int eventId); +} diff --git a/main-service/src/main/java/ru/practicum/mainservice/service/MarkService.java b/main-service/src/main/java/ru/practicum/mainservice/service/RateService.java similarity index 57% rename from main-service/src/main/java/ru/practicum/mainservice/service/MarkService.java rename to main-service/src/main/java/ru/practicum/mainservice/service/RateService.java index af7b372..73212d8 100644 --- a/main-service/src/main/java/ru/practicum/mainservice/service/MarkService.java +++ b/main-service/src/main/java/ru/practicum/mainservice/service/RateService.java @@ -9,41 +9,25 @@ import ru.practicum.mainservice.model.event.Event; import ru.practicum.mainservice.model.request.ParticipationRequest; import ru.practicum.mainservice.model.user.User; -import ru.practicum.mainservice.repository.MarkRepository; -import ru.practicum.mainservice.model.mark.Mark; +import ru.practicum.mainservice.repository.RateRepository; +import ru.practicum.mainservice.model.rate.Rate; import ru.practicum.mainservice.model.enums.ParticipationRequestStatus; @Slf4j @Service @RequiredArgsConstructor -public class MarkService { - private final MarkRepository markRepository; +public class RateService { + private final RateRepository rateRepository; private final EventService eventService; private final UserService userService; private final ParticipationRequestService participationRequestService; - @Transactional - public void saveMark(Mark mark) { - markRepository.save(mark); - } - - @Transactional - public void deleteMark(Mark mark) { - markRepository.delete(mark); - } - - @Transactional(readOnly = true) - public Mark findMarkByEvaluatorAndEvent(int evaluatorId, int eventId) { - return markRepository.findOneByEvaluator_IdAndEvent_Id(evaluatorId, eventId); - } - @Transactional public void putMark(int userId, int eventId, Boolean score) { - Mark mark = markRepository.findOneByEvaluator_IdAndEvent_Id(userId, eventId); - ; + Rate mark = rateRepository.findOneByEvaluator_IdAndEvent_Id(userId, eventId); + Event event = eventService.getEvent(eventId); + User initiator = userService.getUser(event.getInitiator().getId()); if (mark != null) { - Event event = eventService.getEvent(eventId); - User initiator = userService.getUser(event.getInitiator().getId()); if (!mark.getScore().toString().equals(score.toString())) { if (mark.getScore()) { event.setRating(event.getRating() - Constants.CHANGING_RATING_WHEN_CHANGING_MARK); @@ -53,21 +37,16 @@ public void putMark(int userId, int eventId, Boolean score) { initiator.setRating(initiator.getRating() + Constants.CHANGING_RATING_WHEN_CHANGING_MARK); } mark.setScore(score); - eventService.save(event); - markRepository.save(mark); - userService.saveUser(initiator); } } else { ParticipationRequest request = participationRequestService.getRequestByEventAndRequester(eventId, userId); if (request == null) { throw new BadRequestValidationException("Оценивать событие могут только его участники"); } - Event event = eventService.getEvent(eventId); if (event.getParticipantLimit() == 0 || !event.getRequestModeration() || request.getStatus().equals(ParticipationRequestStatus.CONFIRMED)) { User evaluator = userService.getUser(userId); - mark = new Mark(0, evaluator, event, score); - markRepository.save(mark); - User initiator = userService.getUser(event.getInitiator().getId()); + mark = new Rate(0, evaluator, event, score); + rateRepository.save(mark); if (score) { event.setRating(event.getRating() + Constants.RATING_CHANGE_AT_NEW_MARK_OR_DELETE_MARK); initiator.setRating(initiator.getRating() + Constants.RATING_CHANGE_AT_NEW_MARK_OR_DELETE_MARK); @@ -75,32 +54,33 @@ public void putMark(int userId, int eventId, Boolean score) { event.setRating(event.getRating() - Constants.RATING_CHANGE_AT_NEW_MARK_OR_DELETE_MARK); initiator.setRating(initiator.getRating() - Constants.RATING_CHANGE_AT_NEW_MARK_OR_DELETE_MARK); } - eventService.save(event); - markRepository.save(mark); - userService.saveUser(initiator); } else { throw new BadRequestValidationException("Оценивать событие могут только его участники"); } } + eventService.save(event); + rateRepository.save(mark); + userService.saveUser(initiator); } @Transactional public void deleteMark(int userId, int eventId) { - Mark mark = markRepository.findOneByEvaluator_IdAndEvent_Id(userId, eventId); - ; - if (mark != null) { - Event event = eventService.getEvent(eventId); - User initiator = userService.getUser(event.getInitiator().getId()); - if (mark.getScore()) { - event.setRating(event.getRating() - Constants.RATING_CHANGE_AT_NEW_MARK_OR_DELETE_MARK); - initiator.setRating(initiator.getRating() - Constants.RATING_CHANGE_AT_NEW_MARK_OR_DELETE_MARK); - } else { - event.setRating(event.getRating() + Constants.RATING_CHANGE_AT_NEW_MARK_OR_DELETE_MARK); - initiator.setRating(initiator.getRating() + Constants.RATING_CHANGE_AT_NEW_MARK_OR_DELETE_MARK); - } - eventService.save(event); - userService.saveUser(initiator); - markRepository.delete(mark); + Rate mark = rateRepository.findOneByEvaluator_IdAndEvent_Id(userId, eventId); + if (mark == null) { + return; } + Event event = eventService.getEvent(eventId); + User initiator = userService.getUser(event.getInitiator().getId()); + if (mark.getScore()) { + event.setRating(event.getRating() - Constants.RATING_CHANGE_AT_NEW_MARK_OR_DELETE_MARK); + initiator.setRating(initiator.getRating() - Constants.RATING_CHANGE_AT_NEW_MARK_OR_DELETE_MARK); + } else { + event.setRating(event.getRating() + Constants.RATING_CHANGE_AT_NEW_MARK_OR_DELETE_MARK); + initiator.setRating(initiator.getRating() + Constants.RATING_CHANGE_AT_NEW_MARK_OR_DELETE_MARK); + } + eventService.save(event); + userService.saveUser(initiator); + rateRepository.delete(mark); + } }