diff --git a/README.md b/README.md index 18a246e..8ce5911 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,4 @@ # java-explore-with-me Template repository for ExploreWithMe project. + +https://github.com/flykeeperB/java-explore-with-me/pull/5 diff --git a/main-service/src/main/java/ru/practicum/ewm/comment/controller/admin/AdminCommentController.java b/main-service/src/main/java/ru/practicum/ewm/comment/controller/admin/AdminCommentController.java new file mode 100644 index 0000000..36566c3 --- /dev/null +++ b/main-service/src/main/java/ru/practicum/ewm/comment/controller/admin/AdminCommentController.java @@ -0,0 +1,37 @@ +package ru.practicum.ewm.comment.controller.admin; + +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import ru.practicum.ewm.comment.dto.CommentVersionDto; +import ru.practicum.ewm.comment.service.CommentService; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Positive; +import javax.validation.constraints.PositiveOrZero; +import java.util.List; + +@RestController +@Validated +@RequiredArgsConstructor +@RequestMapping("/admin/comments") +public class AdminCommentController { + + private final CommentService commentService; + + @DeleteMapping("/{commentId}") + @ResponseStatus(HttpStatus.NO_CONTENT) + public void deleteCommentByAdmin(@PathVariable @NotNull Long commentId) { + + commentService.deleteCommentByAdmin(commentId); + } + + @GetMapping("/history/{commentId}") + public List getHistoryOfCommentByAdmin(@PathVariable @NotNull Long commentId, + @RequestParam(required = false, defaultValue = "0") @PositiveOrZero Integer from, + @RequestParam(required = false, defaultValue = "10") @Positive Integer size) { + + return commentService.getCommentsHistoryForAdmin(commentId, size, from); + } +} diff --git a/main-service/src/main/java/ru/practicum/ewm/comment/controller/priv/PrivateCommentController.java b/main-service/src/main/java/ru/practicum/ewm/comment/controller/priv/PrivateCommentController.java new file mode 100644 index 0000000..5a2262b --- /dev/null +++ b/main-service/src/main/java/ru/practicum/ewm/comment/controller/priv/PrivateCommentController.java @@ -0,0 +1,67 @@ +package ru.practicum.ewm.comment.controller.priv; + +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import ru.practicum.ewm.comment.dto.CommentDto; +import ru.practicum.ewm.comment.dto.CommentVersionDto; +import ru.practicum.ewm.comment.dto.NewCommentDto; +import ru.practicum.ewm.comment.dto.UpdateCommentDto; +import ru.practicum.ewm.comment.service.CommentService; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Positive; +import javax.validation.constraints.PositiveOrZero; +import java.util.List; + +@RestController +@Validated +@RequiredArgsConstructor +@RequestMapping("/users/{userId}/comments") +public class PrivateCommentController { + + private final CommentService commentService; + + @PostMapping + @ResponseStatus(HttpStatus.CREATED) + public CommentDto createComment(@PathVariable @NotNull Long userId, + @RequestBody @Valid NewCommentDto newCommentDto) { + return commentService.createCommentByUser(userId, newCommentDto); + } + + @PatchMapping("/{commentId}") + public CommentDto updateCommentByUser(@PathVariable @NotNull Long userId, + @RequestBody @Valid UpdateCommentDto updateCommentDto) { + + return commentService.updateCommentByUser(userId, updateCommentDto); + } + + @GetMapping + public List getAllCommentsOfUser(@PathVariable @NotNull Long userId, + @RequestParam(required = false, defaultValue = "0") + @PositiveOrZero Integer from, + @RequestParam(required = false, defaultValue = "10") + @Positive Integer size) { + + return commentService.getCommentsByUserId(userId, size, from); + } + + @GetMapping("/history/{commentId}") + public List getHistoryOfComment(@PathVariable @NotNull Long userId, + @PathVariable @NotNull Long commentId, + @RequestParam(required = false, defaultValue = "0") @PositiveOrZero Integer from, + @RequestParam(required = false, defaultValue = "10") @Positive Integer size) { + + return commentService.getCommentsHistory(userId, commentId, size, from); + } + + @DeleteMapping("/{commentId}") + @ResponseStatus(HttpStatus.NO_CONTENT) + public void deleteComment(@PathVariable @NotNull Long userId, + @PathVariable @NotNull Long commentId) { + + commentService.deleteCommentByUser(userId, commentId); + } +} diff --git a/main-service/src/main/java/ru/practicum/ewm/comment/controller/publ/PublicCommentController.java b/main-service/src/main/java/ru/practicum/ewm/comment/controller/publ/PublicCommentController.java new file mode 100644 index 0000000..15887cb --- /dev/null +++ b/main-service/src/main/java/ru/practicum/ewm/comment/controller/publ/PublicCommentController.java @@ -0,0 +1,37 @@ +package ru.practicum.ewm.comment.controller.publ; + +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import ru.practicum.ewm.comment.dto.CommentDto; +import ru.practicum.ewm.comment.service.CommentService; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Positive; +import javax.validation.constraints.PositiveOrZero; +import java.util.List; + +@RestController +@Validated +@RequiredArgsConstructor +@RequestMapping("/comments") +public class PublicCommentController { + + private final CommentService commentService; + + @GetMapping("/{commentId}") + public CommentDto getCommentById(@PathVariable @NotNull Long commentId) { + + return commentService.getCommentById(commentId); + } + + @GetMapping("/events/{eventId}") + public List getAllCommentsByEventId(@PathVariable @NotNull Long eventId, + @RequestParam(required = false, defaultValue = "0") + @PositiveOrZero Integer from, + @RequestParam(required = false, defaultValue = "10") + @Positive Integer size) { + + return commentService.getCommentsByEventId(eventId, size, from); + } +} diff --git a/main-service/src/main/java/ru/practicum/ewm/comment/dto/CommentDto.java b/main-service/src/main/java/ru/practicum/ewm/comment/dto/CommentDto.java new file mode 100644 index 0000000..4bb4f10 --- /dev/null +++ b/main-service/src/main/java/ru/practicum/ewm/comment/dto/CommentDto.java @@ -0,0 +1,29 @@ +package ru.practicum.ewm.comment.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class CommentDto { + private Long id; + + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime created; + + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime lastChanged; + + private String authorName; + private Long authorId; + private Long eventId; + private Long replyToCommentId; + private String text; +} diff --git a/main-service/src/main/java/ru/practicum/ewm/comment/dto/CommentVersionDto.java b/main-service/src/main/java/ru/practicum/ewm/comment/dto/CommentVersionDto.java new file mode 100644 index 0000000..e252d20 --- /dev/null +++ b/main-service/src/main/java/ru/practicum/ewm/comment/dto/CommentVersionDto.java @@ -0,0 +1,25 @@ +package ru.practicum.ewm.comment.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class CommentVersionDto { + private Long id; + + private Long commentId; + + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime changed; + + private Long replyToCommentId; + private String text; +} diff --git a/main-service/src/main/java/ru/practicum/ewm/comment/dto/NewCommentDto.java b/main-service/src/main/java/ru/practicum/ewm/comment/dto/NewCommentDto.java new file mode 100644 index 0000000..b47814e --- /dev/null +++ b/main-service/src/main/java/ru/practicum/ewm/comment/dto/NewCommentDto.java @@ -0,0 +1,22 @@ +package ru.practicum.ewm.comment.dto; + +import lombok.*; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class NewCommentDto { + @NotNull + private Long eventId; + + private Long replyToCommentId; + + @NotBlank + @Size(min = 5, max = 1000) + private String text; +} diff --git a/main-service/src/main/java/ru/practicum/ewm/comment/dto/UpdateCommentDto.java b/main-service/src/main/java/ru/practicum/ewm/comment/dto/UpdateCommentDto.java new file mode 100644 index 0000000..d5cf889 --- /dev/null +++ b/main-service/src/main/java/ru/practicum/ewm/comment/dto/UpdateCommentDto.java @@ -0,0 +1,22 @@ +package ru.practicum.ewm.comment.dto; + +import lombok.*; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class UpdateCommentDto { + @NotNull + private Long id; + + private Long replyToCommentId; + + @NotBlank + @Size(min = 5, max = 1000) + private String text; +} diff --git a/main-service/src/main/java/ru/practicum/ewm/comment/mapper/CommentMapper.java b/main-service/src/main/java/ru/practicum/ewm/comment/mapper/CommentMapper.java new file mode 100644 index 0000000..4c97a52 --- /dev/null +++ b/main-service/src/main/java/ru/practicum/ewm/comment/mapper/CommentMapper.java @@ -0,0 +1,28 @@ +package ru.practicum.ewm.comment.mapper; + +import ru.practicum.ewm.comment.dto.CommentDto; +import ru.practicum.ewm.comment.dto.CommentVersionDto; +import ru.practicum.ewm.comment.dto.NewCommentDto; +import ru.practicum.ewm.comment.model.Comment; +import ru.practicum.ewm.comment.model.CommentVersion; +import ru.practicum.ewm.event.model.Event; +import ru.practicum.ewm.user.model.User; + +import java.util.List; + +public interface CommentMapper { + Comment mapToComment(NewCommentDto newCommentDto, + User author, + Event event, + Comment replyToComment); + + CommentDto mapToCommentDto(Comment comment); + + List mapToCommentDto(List comments); + + CommentVersion mapToCommentVersion(Comment comment); + + CommentVersionDto mapToCommentVersionDto(CommentVersion commentVersion); + + List mapToCommentVersionDto(List commentsHistory); +} diff --git a/main-service/src/main/java/ru/practicum/ewm/comment/mapper/impl/CommentMapperImpl.java b/main-service/src/main/java/ru/practicum/ewm/comment/mapper/impl/CommentMapperImpl.java new file mode 100644 index 0000000..3ca4808 --- /dev/null +++ b/main-service/src/main/java/ru/practicum/ewm/comment/mapper/impl/CommentMapperImpl.java @@ -0,0 +1,84 @@ +package ru.practicum.ewm.comment.mapper.impl; + +import org.springframework.stereotype.Service; +import ru.practicum.ewm.comment.dto.CommentDto; +import ru.practicum.ewm.comment.dto.CommentVersionDto; +import ru.practicum.ewm.comment.dto.NewCommentDto; +import ru.practicum.ewm.comment.mapper.CommentMapper; +import ru.practicum.ewm.comment.model.Comment; +import ru.practicum.ewm.comment.model.CommentVersion; +import ru.practicum.ewm.event.model.Event; +import ru.practicum.ewm.user.model.User; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +public class CommentMapperImpl implements CommentMapper { + @Override + public Comment mapToComment(NewCommentDto newCommentDto, + User author, + Event event, + Comment replyToComment) { + return Comment.builder() + .author(author) + .event(event) + .replyToComment(replyToComment) + .actualText(newCommentDto.getText()) + .build(); + } + + @Override + public CommentDto mapToCommentDto(Comment comment) { + CommentDto result = CommentDto.builder() + .id(comment.getId()) + .authorId(comment.getAuthor().getId()) + .authorName(comment.getAuthor().getName()) + .created(comment.getCreated()) + .eventId(comment.getEvent().getId()) + .lastChanged(comment.getLastChanged()) + .text(comment.getActualText()) + .build(); + if (comment.getReplyToComment() != null) { + result.setReplyToCommentId(comment.getReplyToComment().getId()); + } + + return result; + } + + @Override + public List mapToCommentDto(List comments) { + return comments.stream().map(this::mapToCommentDto).collect(Collectors.toList()); + } + + @Override + public CommentVersion mapToCommentVersion(Comment comment) { + return CommentVersion.builder() + .comment(comment) + .changed(comment.getLastChanged()) + .replyToComment(comment.getReplyToComment()) + .text(comment.getActualText()) + .build(); + } + + @Override + public CommentVersionDto mapToCommentVersionDto(CommentVersion commentVersion) { + CommentVersionDto result = CommentVersionDto.builder() + .id(commentVersion.getId()) + .changed(commentVersion.getChanged()) + .commentId(commentVersion.getComment().getId()) + .text(commentVersion.getText()) + .build(); + + if (commentVersion.getReplyToComment() != null) { + result.setReplyToCommentId(commentVersion.getReplyToComment().getId()); + } + + return result; + } + + @Override + public List mapToCommentVersionDto(List commentsHistory) { + return commentsHistory.stream().map(this::mapToCommentVersionDto).collect(Collectors.toList()); + } +} diff --git a/main-service/src/main/java/ru/practicum/ewm/comment/model/Comment.java b/main-service/src/main/java/ru/practicum/ewm/comment/model/Comment.java new file mode 100644 index 0000000..9d9cad6 --- /dev/null +++ b/main-service/src/main/java/ru/practicum/ewm/comment/model/Comment.java @@ -0,0 +1,59 @@ +package ru.practicum.ewm.comment.model; + +import lombok.*; +import org.hibernate.validator.constraints.Length; +import ru.practicum.ewm.event.model.Event; +import ru.practicum.ewm.user.model.User; + +import javax.persistence.*; +import java.time.LocalDateTime; + +@Entity +@Table(name = "comments") +@Builder +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class Comment { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Long id; + + @Column(nullable = false) + private LocalDateTime created; + + @Column(nullable = false) + private LocalDateTime lastChanged; + + @ManyToOne + @JoinColumn(name = "author_id", nullable = false) + private User author; + + @ManyToOne + @JoinColumn(name = "event_id", nullable = false) + private Event event; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "reply_to_comment_id") + private Comment replyToComment; + + @Length(min = 2, max = 1000) + @Column(nullable = false) + private String actualText; + + @Column(nullable = false) + private Boolean deleted = false; + + @PrePersist + protected void onCreate() { + created = LocalDateTime.now(); + lastChanged = created; + } + + @PreUpdate + protected void onUpdate() { + lastChanged = LocalDateTime.now(); + } +} diff --git a/main-service/src/main/java/ru/practicum/ewm/comment/model/CommentVersion.java b/main-service/src/main/java/ru/practicum/ewm/comment/model/CommentVersion.java new file mode 100644 index 0000000..4746bfd --- /dev/null +++ b/main-service/src/main/java/ru/practicum/ewm/comment/model/CommentVersion.java @@ -0,0 +1,37 @@ +package ru.practicum.ewm.comment.model; + +import lombok.*; +import org.hibernate.validator.constraints.Length; + +import javax.persistence.*; +import java.time.LocalDateTime; + +@Entity +@Table(name = "comments_versions") +@Builder +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class CommentVersion { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Long id; + + @ManyToOne + @JoinColumn(name = "comment_id", nullable = false) + private Comment comment; + + @Column + private LocalDateTime changed; + + @ManyToOne + @JoinColumn(name = "reply_to_comment_id") + private Comment replyToComment; + + @Length(min = 2, max = 1000) + @Column(nullable = false) + private String text; + +} diff --git a/main-service/src/main/java/ru/practicum/ewm/comment/repository/CommentHistoryRepository.java b/main-service/src/main/java/ru/practicum/ewm/comment/repository/CommentHistoryRepository.java new file mode 100644 index 0000000..5184d92 --- /dev/null +++ b/main-service/src/main/java/ru/practicum/ewm/comment/repository/CommentHistoryRepository.java @@ -0,0 +1,11 @@ +package ru.practicum.ewm.comment.repository; + +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import ru.practicum.ewm.comment.model.CommentVersion; + +import java.util.List; + +public interface CommentHistoryRepository extends JpaRepository { + List findAllByCommentIdOrderByChanged(Long commentId, Pageable pageable); +} diff --git a/main-service/src/main/java/ru/practicum/ewm/comment/repository/CommentRepository.java b/main-service/src/main/java/ru/practicum/ewm/comment/repository/CommentRepository.java new file mode 100644 index 0000000..9e27865 --- /dev/null +++ b/main-service/src/main/java/ru/practicum/ewm/comment/repository/CommentRepository.java @@ -0,0 +1,17 @@ +package ru.practicum.ewm.comment.repository; + +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import ru.practicum.ewm.comment.model.Comment; + +import java.util.List; +import java.util.Optional; + +public interface CommentRepository extends JpaRepository { + + Optional findByIdAndDeleted(Long commentId, Boolean deleted); + + List findAllByEventIdAndDeletedOrderById(Long eventId, Boolean deleted, Pageable pageable); + + List findAllByAuthorIdAndDeletedOrderById(Long authorId, Boolean deleted, Pageable pageable); +} diff --git a/main-service/src/main/java/ru/practicum/ewm/comment/service/CommentService.java b/main-service/src/main/java/ru/practicum/ewm/comment/service/CommentService.java new file mode 100644 index 0000000..7e3e104 --- /dev/null +++ b/main-service/src/main/java/ru/practicum/ewm/comment/service/CommentService.java @@ -0,0 +1,28 @@ +package ru.practicum.ewm.comment.service; + +import ru.practicum.ewm.comment.dto.CommentDto; +import ru.practicum.ewm.comment.dto.CommentVersionDto; +import ru.practicum.ewm.comment.dto.UpdateCommentDto; +import ru.practicum.ewm.comment.dto.NewCommentDto; + +import java.util.List; + +public interface CommentService { + CommentDto createCommentByUser(Long userId, NewCommentDto newCommentDto); + + CommentDto updateCommentByUser(Long userId, UpdateCommentDto updateCommentDto); + + void deleteCommentByUser(Long userId, Long commentId); + + CommentDto getCommentById(Long commentId); + + List getCommentsHistory(Long userId, Long commentId, int size, int from); + + List getCommentsHistoryForAdmin(Long commentId, int size, int from); + + List getCommentsByUserId(Long userId, int size, int from); + + void deleteCommentByAdmin(Long commentId); + + List getCommentsByEventId(Long eventId, int size, int from); +} diff --git a/main-service/src/main/java/ru/practicum/ewm/comment/service/impl/CommentServiceImpl.java b/main-service/src/main/java/ru/practicum/ewm/comment/service/impl/CommentServiceImpl.java new file mode 100644 index 0000000..abfb349 --- /dev/null +++ b/main-service/src/main/java/ru/practicum/ewm/comment/service/impl/CommentServiceImpl.java @@ -0,0 +1,217 @@ +package ru.practicum.ewm.comment.service.impl; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.domain.PageRequest; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import ru.practicum.ewm.comment.dto.CommentDto; +import ru.practicum.ewm.comment.dto.CommentVersionDto; +import ru.practicum.ewm.comment.dto.UpdateCommentDto; +import ru.practicum.ewm.comment.dto.NewCommentDto; +import ru.practicum.ewm.comment.mapper.CommentMapper; +import ru.practicum.ewm.comment.model.Comment; +import ru.practicum.ewm.comment.model.CommentVersion; +import ru.practicum.ewm.comment.repository.CommentHistoryRepository; +import ru.practicum.ewm.comment.repository.CommentRepository; +import ru.practicum.ewm.comment.service.CommentService; +import ru.practicum.ewm.event.model.Event; +import ru.practicum.ewm.event.repository.EventRepository; +import ru.practicum.ewm.exception.ConflictException; +import ru.practicum.ewm.exception.NotFoundException; +import ru.practicum.ewm.user.model.User; +import ru.practicum.ewm.user.repository.UserRepository; + +import java.util.List; +import java.util.Optional; + +@Service +@Slf4j +@RequiredArgsConstructor +public class CommentServiceImpl implements CommentService { + + public static final String DELETE_MARK = "[* DELETED *]"; + + private final CommentRepository commentRepository; + private final CommentHistoryRepository commentHistoryRepository; + private final UserRepository userRepository; + private final EventRepository eventRepository; + + private final CommentMapper commentMapper; + + + @Override + @Transactional + public CommentDto createCommentByUser(Long userId, NewCommentDto newCommentDto) { + log.info(String.format("createCommentByUser userId-%d newCommentDto-%s", userId, newCommentDto)); + + User user = userRepository.findById(userId).orElseThrow( + () -> new NotFoundException("Пользователь не найден.")); + + Event event = eventRepository.findById(newCommentDto.getEventId()).orElseThrow( + () -> new NotFoundException("Cобытие не найдено.")); + + Comment replyToComment = null; + if (newCommentDto.getReplyToCommentId() != null) { + replyToComment = commentRepository.findByIdAndDeleted(newCommentDto.getReplyToCommentId(), false).orElseThrow( + () -> new NotFoundException("Комментарий, на который ссылается создаваемый, не найден.")); + } + + Comment comment = commentMapper.mapToComment(newCommentDto, user, event, replyToComment); + + comment.setDeleted(false); + + Comment createdComment = saveComment(comment); + return commentMapper.mapToCommentDto(createdComment); + } + + @Override + @Transactional + public CommentDto updateCommentByUser(Long userId, UpdateCommentDto updateCommentDto) { + log.info(String.format("updateCommentByUser userId-%d newCommentDto-%s", userId, updateCommentDto)); + + User user = userRepository.findById(userId).orElseThrow( + () -> new NotFoundException("Пользователь не найден.")); + + Comment comment = commentRepository.findByIdAndDeleted(updateCommentDto.getId(), false).orElseThrow( + () -> new NotFoundException("Редактируемый комментарий не найден")); + + if (!user.getId().equals(comment.getAuthor().getId())) { + throw new ConflictException("Обновить комментарий вправе только автор или администратор (модератор)"); + } + + comment.setActualText(updateCommentDto.getText()); + + comment.setReplyToComment(null); + if (updateCommentDto.getReplyToCommentId() != null) { + Optional replyComment = commentRepository + .findByIdAndDeleted(updateCommentDto.getReplyToCommentId(), false); + + replyComment.ifPresent(comment::setReplyToComment); + } + + Comment updatedComment = commentRepository.save(comment); + + CommentVersion commentVersion = commentMapper.mapToCommentVersion(updatedComment); + commentHistoryRepository.save(commentVersion); + + return commentMapper.mapToCommentDto(updatedComment); + } + + @Override + @Transactional + public void deleteCommentByUser(Long userId, Long commentId) { + log.info(String.format("deleteCommentByUser userId-%d commentId-%d", userId, commentId)); + + Comment comment = commentRepository.findByIdAndDeleted(commentId, false).orElseThrow( + () -> new NotFoundException("Удаляемый комментарий не найден")); + + User user = userRepository.findById(userId).orElseThrow( + () -> new NotFoundException("Пользователь не найден.")); + + if (!user.getId().equals(comment.getAuthor().getId())) { + throw new ConflictException("Удалить комментарий вправе только автор или администратор (модератор)"); + } + + deleteComment(comment); + } + + @Override + @Transactional(readOnly = true) + public CommentDto getCommentById(Long commentId) { + log.info(String.format("getCommentById commentId-%d", commentId)); + + Comment comment = commentRepository.findByIdAndDeleted(commentId, false).orElseThrow( + () -> new NotFoundException("Комментарий не найден.")); + + return commentMapper.mapToCommentDto(comment); + } + + @Override + @Transactional(readOnly = true) + public List getCommentsHistory(Long userId, Long commentId, int size, int from) { + int offset = from > 0 ? from / size : 0; + PageRequest page = PageRequest.of(offset, size); + + User user = userRepository.findById(userId).orElseThrow( + () -> new NotFoundException("Пользователь не найден.")); + + Comment comment = commentRepository.findByIdAndDeleted(commentId, false).orElseThrow( + () -> new NotFoundException("Комментарий не найден.")); + + if (!user.getId().equals(comment.getAuthor().getId())) { + throw new ConflictException("Просмотр версий комментария доступно только автору или администратору (модератору)"); + } + + List commentsHistory = commentHistoryRepository + .findAllByCommentIdOrderByChanged(commentId, page); + + return commentMapper.mapToCommentVersionDto(commentsHistory); + } + + @Override + @Transactional(readOnly = true) + public List getCommentsHistoryForAdmin(Long commentId, int size, int from) { + int offset = from > 0 ? from / size : 0; + PageRequest page = PageRequest.of(offset, size); + + List commentsHistory = commentHistoryRepository + .findAllByCommentIdOrderByChanged(commentId, page); + + return commentMapper.mapToCommentVersionDto(commentsHistory); + } + + @Override + @Transactional + public List getCommentsByUserId(Long userId, int size, int from) { + int offset = from > 0 ? from / size : 0; + PageRequest page = PageRequest.of(offset, size); + + userRepository.findById(userId).orElseThrow( + () -> new NotFoundException("Пользователь не найден.")); + + List comments = commentRepository + .findAllByAuthorIdAndDeletedOrderById(userId, false, page); + + return commentMapper.mapToCommentDto(comments); + } + + @Override + @Transactional + public void deleteCommentByAdmin(Long commentId) { + log.info(String.format("deleteCommentByAdmin commentId-%d", commentId)); + + deleteComment(commentRepository.findByIdAndDeleted(commentId, false) + .orElseThrow(() -> new NotFoundException("Удаляемый комментарий не найден."))); + } + + @Override + @Transactional(readOnly = true) + public List getCommentsByEventId(Long eventId, int size, int from) { + int offset = from > 0 ? from / size : 0; + PageRequest page = PageRequest.of(offset, size); + + List comments = commentRepository.findAllByEventIdAndDeletedOrderById(eventId, false, page); + + return commentMapper.mapToCommentDto(comments); + } + + private void deleteComment(Comment deleteComment) { + + deleteComment.setActualText(DELETE_MARK); + deleteComment.setDeleted(true); + + Comment deletedComment = commentRepository.save(deleteComment); + + CommentVersion commentVersion = commentMapper.mapToCommentVersion(deletedComment); + commentHistoryRepository.save(commentVersion); + } + + private Comment saveComment(Comment comment) { + Comment result = commentRepository.save(comment); + CommentVersion commentVersion = commentMapper.mapToCommentVersion(result); + + commentHistoryRepository.save(commentVersion); + return result; + } +} diff --git a/main-service/src/main/resources/schema.sql b/main-service/src/main/resources/schema.sql index c5c79fa..f1d6aef 100644 --- a/main-service/src/main/resources/schema.sql +++ b/main-service/src/main/resources/schema.sql @@ -77,4 +77,44 @@ CREATE TABLE IF NOT EXISTS requests REFERENCES events (id), CONSTRAINT fk_requests_requester FOREIGN KEY (requester_id) REFERENCES users (id) +); + +CREATE TABLE IF NOT EXISTS comments +( + id BIGINT NOT NULL GENERATED BY DEFAULT AS IDENTITY, + created TIMESTAMP WITHOUT TIME ZONE, + last_changed TIMESTAMP WITHOUT TIME ZONE, + author_id BIGINT NOT NULL, + event_id BIGINT NOT NULL, + reply_to_comment_id BIGINT, + actual_text VARCHAR(1000) NOT NULL, + deleted BOOLEAN DEFAULT FALSE NOT NULL, + + CONSTRAINT pk_comments PRIMARY KEY (id), + + CONSTRAINT fk_comments_author FOREIGN KEY (author_id) + REFERENCES users (id), + CONSTRAINT fk_comments_event FOREIGN KEY (event_id) + REFERENCES events (id), + + CONSTRAINT fk_comments_reply_to FOREIGN KEY (reply_to_comment_id) + REFERENCES comments (id) +); + +CREATE TABLE IF NOT EXISTS comments_versions +( + id BIGINT NOT NULL GENERATED BY DEFAULT AS IDENTITY, + comment_id BIGINT NOT NULL, + changed TIMESTAMP WITHOUT TIME ZONE, + reply_to_comment_id BIGINT, + text VARCHAR(1000) NOT NULL, + deleted BOOLEAN DEFAULT FALSE, + + CONSTRAINT pk_comments_versions PRIMARY KEY (id), + + CONSTRAINT fk_comments_versions_link FOREIGN KEY (comment_id) + REFERENCES comments (id), + + CONSTRAINT fk_comments_versions_reply_to FOREIGN KEY (reply_to_comment_id) + REFERENCES comments (id) ); \ No newline at end of file diff --git a/postman/feature.json b/postman/feature.json new file mode 100644 index 0000000..431dd02 --- /dev/null +++ b/postman/feature.json @@ -0,0 +1,3397 @@ +{ + "info": { + "_postman_id": "4bfa78d3-b70f-4e1f-9a1f-ade41f5e5feb", + "name": "EWM_Comments", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "26565535", + "_collection_link": "https://galactic-astronaut-619069.postman.co/workspace/Team-Workspace~f22c46b4-2697-4866-84ed-d5cd7c530f2e/collection/26565535-4bfa78d3-b70f-4e1f-9a1f-ade41f5e5feb?action=share&source=collection_link&creator=26565535" + }, + "item": [ + { + "name": "Добавление нового пользователя", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Ответ должен содержать код статуса 201 или 201 и данные в формате json\", function() {\r", + " pm.expect(pm.response.code).to.be.oneOf([200,201]);; // код ответа должен быть равен 201 OK\r", + " pm.response.to.be.withBody; // ответ должен содержать тело\r", + " pm.response.to.be.json; // и тело ответа должно быть в формате JSON\r", + "}); \r", + "const source = JSON.parse(pm.request.body.raw);\r", + "const target = pm.response.json();\r", + "\r", + "pm.test(\"Пользователь должен содержать поля: id, name, email\", function () {\r", + "pm.expect(target).to.have.property('id');\r", + "pm.expect(target).to.have.property('name');\r", + "pm.expect(target).to.have.property('email');\r", + "});\r", + "\r", + "pm.test(\"Данные в ответе должны соответствовать данным в запросе\", function () {\r", + " pm.expect(target.id).to.not.be.null;\r", + " pm.expect(source.name).equal(target.name, 'Имя пользователя должно соответствовать отправленному в запросе');\r", + " pm.expect(source.email).equal(target.email, 'Почта пользователя должна соответствовать отправленной в запросе');\r", + "});\r", + "pm.collectionVariables.set(\"userId\", target.id);" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "const main = async () => {\r", + " const api = new API(pm);\r", + " const rnd = new RandomUtils();\r", + "\r", + " let user;\r", + " try {\r", + " user = rnd.getUser();\r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "\r", + " pm.request.body.update({\r", + " mode: 'raw',\r", + " raw: JSON.stringify(user),\r", + " options: { raw: { language: 'json' } }\r", + " });\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{{request_body}}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8080/admin/users", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "admin", + "users" + ] + } + }, + "response": [] + }, + { + "name": "Добавление пользователя 2", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "const main = async () => {\r", + " const api = new API(pm);\r", + " const rnd = new RandomUtils();\r", + "\r", + " let user;\r", + " try {\r", + " user = rnd.getUser();\r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "\r", + " pm.request.body.update({\r", + " mode: 'raw',\r", + " raw: JSON.stringify(user),\r", + " options: { raw: { language: 'json' } }\r", + " });\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Ответ должен содержать код статуса 201 или 201 и данные в формате json\", function() {\r", + " pm.expect(pm.response.code).to.be.oneOf([200,201]);; // код ответа должен быть равен 201 OK\r", + " pm.response.to.be.withBody; // ответ должен содержать тело\r", + " pm.response.to.be.json; // и тело ответа должно быть в формате JSON\r", + "}); \r", + "const source = JSON.parse(pm.request.body.raw);\r", + "const target = pm.response.json();\r", + "\r", + "pm.test(\"Пользователь должен содержать поля: id, name, email\", function () {\r", + "pm.expect(target).to.have.property('id');\r", + "pm.expect(target).to.have.property('name');\r", + "pm.expect(target).to.have.property('email');\r", + "});\r", + "\r", + "pm.test(\"Данные в ответе должны соответствовать данным в запросе\", function () {\r", + " pm.expect(target.id).to.not.be.null;\r", + " pm.expect(source.name).equal(target.name, 'Имя пользователя должно соответствовать отправленному в запросе');\r", + " pm.expect(source.email).equal(target.email, 'Почта пользователя должна соответствовать отправленной в запросе');\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{{request_body}}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8080/admin/users", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "admin", + "users" + ] + } + }, + "response": [] + }, + { + "name": "Добавление новой категории", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "const main = async () => {\r", + " const api = new API(pm);\r", + " const rnd = new RandomUtils();\r", + "\r", + " let category;\r", + " try {\r", + " category = rnd.getCategory();\r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "\r", + " pm.request.body.update({\r", + " mode: 'raw',\r", + " raw: JSON.stringify(category),\r", + " options: { raw: { language: 'json' } }\r", + " });\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Ответ должен содержать код статуса 201 и данные в формате json\", function () {\r", + " pm.response.to.have.status(201);\r", + " pm.response.to.be.withBody;\r", + " pm.response.to.be.json;\r", + "});\r", + "\r", + "const source = JSON.parse(pm.request.body.raw);\r", + "const target = pm.response.json();\r", + "\r", + "pm.test(\"Категория должна содержать поля: id, name\", function () {\r", + "pm.expect(target).to.have.property('id');\r", + "pm.expect(target).to.have.property('name');\r", + "});\r", + "\r", + "pm.test(\"Данные в ответе должны соответствовать данным в запросе\", function () {\r", + " pm.expect(target.id).to.not.be.null;\r", + " pm.expect(source.name).equal(target.name, 'Название категории должно совпадать с отправленным');\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{{request_body}}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8080/admin/categories", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "admin", + "categories" + ] + } + }, + "response": [] + }, + { + "name": "Добавление нового события", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "const main = async () => {\r", + " const api = new API(pm);\r", + " const rnd = new RandomUtils();\r", + "\r", + " let event;\r", + " try {\r", + " const user = await api.addUser(rnd.getUser());\r", + " pm.collectionVariables.set(\"uid\", user.id)\r", + " const category = await api.addCategory(rnd.getCategory());\r", + " event = rnd.getEvent(category.id);\r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "\r", + " pm.request.body.update({\r", + " mode: 'raw',\r", + " raw: JSON.stringify(event),\r", + " options: { raw: { language: 'json' } }\r", + " });\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Ответ должен содержать код статуса 201 и данные в формате json\", function () {\r", + " pm.response.to.have.status(201); \r", + " pm.response.to.be.withBody;\r", + " pm.response.to.be.json;\r", + "});\r", + "\r", + "const source = JSON.parse(pm.request.body.raw);\r", + "const target = pm.response.json();\r", + "\r", + "pm.test(\"Событие должно содержать поля: id, title, annotation, category, paid, eventDate, initiator, description, participantLimit, state, createdOn, location, requestModeration\", function () {\r", + "pm.expect(target).to.have.property('id');\r", + "pm.expect(target).to.have.property('title');\r", + "pm.expect(target).to.have.property('annotation');\r", + "pm.expect(target).to.have.property('category');\r", + "pm.expect(target).to.have.property('paid');\r", + "pm.expect(target).to.have.property('eventDate');\r", + "pm.expect(target).to.have.property('initiator');\r", + "pm.expect(target).to.have.property('description');\r", + "pm.expect(target).to.have.property('participantLimit');\r", + "pm.expect(target).to.have.property('state');\r", + "pm.expect(target).to.have.property('createdOn');\r", + "pm.expect(target).to.have.property('location');\r", + "pm.expect(target).to.have.property('requestModeration');\r", + "});\r", + "\r", + "pm.test(\"Данные в ответе должны соответствовать данным в запросе\", function () {\r", + " pm.expect(target.id).to.not.be.null;\r", + " pm.expect(target.title).equal(source.title, 'Название события должно соответствовать названию события в запросе');\r", + " pm.expect(target.annotation).equal(source.annotation, 'Аннотация события должна соответствовать аннотации события в запросе');\r", + " pm.expect(target.paid.toString()).equal(source.paid.toString(), 'Стоимость события должна соответствовать стоимости события в запросе');\r", + " pm.expect(target.eventDate).equal(source.eventDate, 'Дата проведения события должна соответствовать дате проведения события в запросе');\r", + " pm.expect(target.description).equal(source.description, 'Описание события должно соответствовать описание события в запросе');\r", + " pm.expect(target.participantLimit.toString()).equal(source.participantLimit.toString(), 'Лимит участников события должно соответствовать лимиту участников события в запросе');\r", + " pm.expect(target.location.lat.toString()).equal(source.location.lat.toString(), 'Широта локации проведения события должна соответствовать широте локации проведения события в запросе');\r", + " pm.expect(target.location.lon.toString()).equal(source.location.lon.toString(), 'Долгота локации проведения события должна соответствовать долготе локации проведения события в запросе');\r", + " pm.expect(target.requestModeration.toString()).equal(source.requestModeration.toString(), 'Необходимость модерации события должна соответствовать необходимости модерации события в запросе');\r", + "});\r", + "pm.collectionVariables.set(\"eventId\", target.id);\r", + "\r", + "pm.collectionVariables.set(\"rootEvent\", target.event);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{{request_body}}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8080/users/:userId/events", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "users", + ":userId", + "events" + ], + "variable": [ + { + "key": "userId", + "value": "{{userId}}", + "description": "(Required) id текущего пользователя" + } + ] + } + }, + "response": [] + }, + { + "name": "Добавление нового комментария к событию", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "var moment = require('moment');\r", + "\r", + "var start = moment();\r", + "pm.environment.set('currentDateTime', start.format('YYYY-MM-DDTHH:mm:ss'));\r", + "\r", + "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", + " pm.collectionVariables.set(\"uid\", user.id)\r", + " const category = await api.addCategory(rnd.getCategory());\r", + " let event = await api.addEvent(user.id, rnd.getEvent(category.id));\r", + " event = await api.publishEvent(event.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", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Ответ должен содержать код статуса 201 или 201 и данные в формате json\", function() {\r", + " pm.expect(pm.response.code).to.be.oneOf([200,201]);; // код ответа должен быть равен 201 OK\r", + " pm.response.to.be.withBody; // ответ должен содержать тело\r", + " pm.response.to.be.json; // и тело ответа должно быть в формате JSON\r", + "}); \r", + "const source = JSON.parse(pm.request.body.raw);\r", + "const target = pm.response.json();\r", + "\r", + "\r", + " pm.test(\"Комментарий должен содержать поля: text, authorName, created\", function () {\r", + " pm.expect(target).to.have.property('text');\r", + " pm.expect(target).to.have.property('authorName');\r", + " pm.expect(target).to.have.property('created');\r", + " });\r", + "\r", + "pm.test(\"Данные в ответе должны соответствовать данным в запросе\", function () {\r", + " pm.expect(target.text).to.not.be.null;\r", + " pm.expect(source.text).equal(target.text, 'Текст комментария должен совпадать с отправленным');\r", + " });\r", + " pm.collectionVariables.set(\"commentId\", target.id);\r", + "pm.collectionVariables.set(\"authorId\", target.author);\r", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"text\": \"Add comment from user1\",\r\n \"eventId\":{{eid}}\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8080/users/:userId/comments", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "users", + ":userId", + "comments" + ], + "variable": [ + { + "key": "userId", + "value": "{{uid}}", + "description": "(Required) id текущего пользователя" + } + ] + } + }, + "response": [] + }, + { + "name": "Получение комментария по идентификатору", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "var moment = require('moment');\r", + "\r", + "var start = moment();\r", + "pm.environment.set('currentDateTime', start.format('YYYY-MM-DDTHH:mm:ss'));\r", + "\r", + "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", + " \r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Ответ должен содержать код статуса 200 и данные в формате json\", function () {\r", + " pm.response.to.be.ok; \r", + " pm.response.to.be.withBody;\r", + " pm.response.to.be.json;\r", + "});\r", + "\r", + "\r", + "\r", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "http://localhost:8080/comments/:commentId", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "comments", + ":commentId" + ], + "variable": [ + { + "key": "commentId", + "value": "{{commentId}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Получение комментариев по идентификатору события", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "var moment = require('moment');\r", + "\r", + "var start = moment();\r", + "pm.environment.set('currentDateTime', start.format('YYYY-MM-DDTHH:mm:ss'));\r", + "\r", + "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", + " \r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Ответ должен содержать код статуса 200 и данные в формате json\", function () {\r", + " pm.response.to.be.ok; \r", + " pm.response.to.be.withBody;\r", + " pm.response.to.be.json;\r", + "});\r", + "\r", + "\r", + "\r", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "http://localhost:8080/comments/events/:eventId", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "comments", + "events", + ":eventId" + ], + "variable": [ + { + "key": "eventId", + "value": "{{eid}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Получение комментария по неправильному идентификатору", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Ответ должен содержать код статуса 404 и данные в формате json\", function () {\r", + " pm.response.to.be.notFound; \r", + " pm.response.to.be.withBody;\r", + " pm.response.to.be.json;\r", + "});\r", + "\r", + "\r", + "\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "var moment = require('moment');\r", + "\r", + "var start = moment();\r", + "pm.environment.set('currentDateTime', start.format('YYYY-MM-DDTHH:mm:ss'));\r", + "\r", + "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", + " //pm.collectionVariables.set(\"uid\", user.id)\r", + " //const category = await api.addCategory(rnd.getCategory());\r", + " //let event = await api.addEvent(user.id, rnd.getEvent(category.id));\r", + " //event = await api.publishEvent(event.id);\r", + " //pm.collectionVariables.set(\"eid\", event.id);\r", + " //let comment = {\r", + " // eventId : event.id,\r", + " // text : \"Новый комментарий\"\r", + " //}\r", + " // newComment = await api.();\r", + " //pm.collectionVariables.set(\"commentId\", newComment.id);\r", + " \r", + " \r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "http://localhost:8080/comments/:commentId", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "comments", + ":commentId" + ], + "variable": [ + { + "key": "commentId", + "value": "-33" + } + ] + } + }, + "response": [] + }, + { + "name": "Получение комментария без указания идентификатора", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "var moment = require('moment');\r", + "\r", + "var start = moment();\r", + "pm.environment.set('currentDateTime', start.format('YYYY-MM-DDTHH:mm:ss'));\r", + "\r", + "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", + " \r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Ответ должен содержать код статуса 400 и данные в формате json\", function () {\r", + " pm.response.to.have.status(400); \r", + " pm.response.to.be.withBody;\r", + " pm.response.to.be.json;\r", + "});\r", + "\r", + "\r", + "\r", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "http://localhost:8080/comments/:commentId", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "comments", + ":commentId" + ], + "variable": [ + { + "key": "commentId", + "value": "" + } + ] + } + }, + "response": [] + }, + { + "name": "Обновление комментария без текста", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Ответ должен содержать код статуса 400 и данные в формате json\", function () {\r", + " pm.response.to.have.status(400);\r", + " pm.response.to.be.withBody;\r", + " pm.response.to.be.json;\r", + " });\r", + " " + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PATCH", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \r\n \"text\": \"\" \r\n\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8080/users/:userId/comments/:commentId", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "users", + ":userId", + "comments", + ":commentId" + ], + "variable": [ + { + "key": "userId", + "value": "{{uid}}", + "description": "(Required) id текущего пользователя" + }, + { + "key": "commentId", + "value": "{{commentId}}", + "description": "(Required) id комментария" + } + ] + } + }, + "response": [] + }, + { + "name": "Удаление комментария", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Ответ должен содержать код статуса 204\", function () {\r", + " pm.response.to.have.status(204);\r", + " });" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "DELETE", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8080/users/:userId/comments/:commentId", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "users", + ":userId", + "comments", + ":commentId" + ], + "variable": [ + { + "key": "userId", + "value": "{{uid}}", + "description": "(Required) id текущего пользователя" + }, + { + "key": "commentId", + "value": "{{commentId}}", + "description": "(Required) id комментария" + } + ] + } + }, + "response": [] + }, + { + "name": "Удаление несуществующего комментария", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Ответ должен содержать код статуса 404 и данные в формате json\", function () {\r", + " pm.response.to.have.status(404);\r", + " pm.response.to.be.withBody;\r", + " pm.response.to.be.json;\r", + " });" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "DELETE", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8080/users/:userId/comments/:commentId", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "users", + ":userId", + "comments", + ":commentId" + ], + "variable": [ + { + "key": "userId", + "value": "{{uid}}", + "description": "(Required) id текущего пользователя" + }, + { + "key": "commentId", + "value": "-33", + "description": "(Required) id комментария" + } + ] + } + }, + "response": [] + }, + { + "name": "Добавление нового комментария к событию2", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "var moment = require('moment');\r", + "\r", + "var start = moment();\r", + "pm.environment.set('currentDateTime', start.format('YYYY-MM-DDTHH:mm:ss'));\r", + "\r", + "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", + " pm.collectionVariables.set(\"uid\", user.id)\r", + " const category = await api.addCategory(rnd.getCategory());\r", + " let event = await api.addEvent(user.id, rnd.getEvent(category.id));\r", + " event = await api.publishEvent(event.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", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Ответ должен содержать код статуса 201 или 201 и данные в формате json\", function() {\r", + " pm.expect(pm.response.code).to.be.oneOf([200,201]);; // код ответа должен быть равен 201 OK\r", + " pm.response.to.be.withBody; // ответ должен содержать тело\r", + " pm.response.to.be.json; // и тело ответа должно быть в формате JSON\r", + "}); \r", + "const source = JSON.parse(pm.request.body.raw);\r", + "const target = pm.response.json();\r", + "\r", + "\r", + " pm.test(\"Комментарий должен содержать поля: text, authorName, created\", function () {\r", + " pm.expect(target).to.have.property('text');\r", + " pm.expect(target).to.have.property('authorName');\r", + " pm.expect(target).to.have.property('created');\r", + " });\r", + "\r", + "pm.test(\"Данные в ответе должны соответствовать данным в запросе\", function () {\r", + " pm.expect(target.text).to.not.be.null;\r", + " pm.expect(source.text).equal(target.text, 'Текст комментария должен совпадать с отправленным');\r", + " });\r", + " pm.collectionVariables.set(\"commentId\", target.id);\r", + "pm.collectionVariables.set(\"authorId\", target.author);\r", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"text\": \"Add comment from user1\",\r\n \"eventId\":{{eid}}\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8080/users/:userId/comments", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "users", + ":userId", + "comments" + ], + "variable": [ + { + "key": "userId", + "value": "{{uid}}", + "description": "(Required) id текущего пользователя" + } + ] + } + }, + "response": [] + }, + { + "name": "Добавление комментария в ответ на другой комментарий", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Ответ должен содержать код статуса 201 или 201 и данные в формате json\", function() {\r", + " pm.expect(pm.response.code).to.be.oneOf([200,201]);; // код ответа должен быть равен 201 OK\r", + " pm.response.to.be.withBody; // ответ должен содержать тело\r", + " pm.response.to.be.json; // и тело ответа должно быть в формате JSON\r", + "}); \r", + "const source = JSON.parse(pm.request.body.raw);\r", + "const target = pm.response.json();\r", + "\r", + "\r", + " pm.test(\"Комментарий должен содержать поля: text, authorName, created\", function () {\r", + " pm.expect(target).to.have.property('text');\r", + " pm.expect(target).to.have.property('authorName');\r", + " pm.expect(target).to.have.property('created');\r", + " });\r", + "\r", + "pm.test(\"Данные в ответе должны соответствовать данным в запросе\", function () {\r", + " pm.expect(target.text).to.not.be.null;\r", + " pm.expect(source.text).equal(target.text, 'Текст комментария должен совпадать с отправленным');\r", + " });\r", + " pm.collectionVariables.set(\"commentId\", target.id);\r", + "pm.collectionVariables.set(\"authorId\", target.author);\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "var moment = require('moment');\r", + "\r", + "var start = moment();\r", + "pm.environment.set('currentDateTime', start.format('YYYY-MM-DDTHH:mm:ss'));\r", + "\r", + "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", + " pm.collectionVariables.set(\"uid\", user.id)\r", + " const category = await api.addCategory(rnd.getCategory());\r", + " let event = await api.addEvent(user.id, rnd.getEvent(category.id));\r", + " event = await api.publishEvent(event.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", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"eventId\": 1,\r\n \"replyToCommentId\": {{commentId}},\r\n \"text\": \"Answer to previews comment\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8080/users/:userId/comments", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "users", + ":userId", + "comments" + ], + "variable": [ + { + "key": "userId", + "value": "{{uid}}", + "description": "(Required) id текущего пользователя" + } + ] + } + }, + "response": [] + }, + { + "name": "Обновление комментария пользователем", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Ответ должен содержать код статуса 201 или 201 и данные в формате json\", function() {\r", + " pm.expect(pm.response.code).to.be.oneOf([200,201]);; // код ответа должен быть равен 201 OK\r", + " pm.response.to.be.withBody; // ответ должен содержать тело\r", + " pm.response.to.be.json; // и тело ответа должно быть в формате JSON\r", + "}); \r", + "const source = JSON.parse(pm.request.body.raw);\r", + "const target = pm.response.json();\r", + "\r", + "\r", + " pm.test(\"Комментарий должен содержать поля: text, authorName, created\", function () {\r", + " pm.expect(target).to.have.property('text');\r", + " pm.expect(target).to.have.property('authorName');\r", + " pm.expect(target).to.have.property('created');\r", + " });\r", + "\r", + "pm.test(\"Данные в ответе должны соответствовать данным в запросе\", function () {\r", + " pm.expect(target.text).to.not.be.null;\r", + " pm.expect(source.text).equal(target.text, 'Текст комментария должен совпадать с отправленным');\r", + " });\r", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PATCH", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"id\": {{commentId}},\r\n \"text\": \"Update comment from author\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8080/users/:userId/comments/:commentId", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "users", + ":userId", + "comments", + ":commentId" + ], + "variable": [ + { + "key": "userId", + "value": "{{uid}}", + "description": "(Required) id автора комментария" + }, + { + "key": "commentId", + "value": "{{commentId}}", + "description": "(Required) id комментария" + } + ] + } + }, + "response": [] + }, + { + "name": "удаление комментария админом", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "var moment = require('moment');\r", + "\r", + "var start = moment();\r", + "pm.environment.set('currentDateTime', start.format('YYYY-MM-DDTHH:mm:ss'));\r", + "\r", + "const main = async () => {\r", + " const api = new API(pm);\r", + " const rnd = new RandomUtils();\r", + "\r", + " try {\r", + "\r", + " const category = await api.addCategory(rnd.getCategory());\r", + " let event = await api.addEvent(user.id, rnd.getEvent(category.id));\r", + " event = await api.publishEvent(event.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", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Ответ должен содержать код статуса 204\", function() {\r", + " pm.response.to.have.status(204); \r", + "}); \r", + "\r", + "\r", + "\r", + " " + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "DELETE", + "header": [], + "url": { + "raw": "http://localhost:8080/admin/comments/:commentId", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "admin", + "comments", + ":commentId" + ], + "variable": [ + { + "key": "commentId", + "value": "{{commentId}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Создание комментария снова", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "var moment = require('moment');\r", + "\r", + "var start = moment();\r", + "pm.environment.set('currentDateTime', start.format('YYYY-MM-DDTHH:mm:ss'));\r", + "\r", + "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", + " pm.collectionVariables.set(\"uid\", user.id)\r", + " const category = await api.addCategory(rnd.getCategory());\r", + " let event = await api.addEvent(user.id, rnd.getEvent(category.id));\r", + " event = await api.publishEvent(event.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", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Ответ должен содержать код статуса 201 или 201 и данные в формате json\", function() {\r", + " pm.expect(pm.response.code).to.be.oneOf([200,201]);; // код ответа должен быть равен 201 OK\r", + " pm.response.to.be.withBody; // ответ должен содержать тело\r", + " pm.response.to.be.json; // и тело ответа должно быть в формате JSON\r", + "}); \r", + "const source = JSON.parse(pm.request.body.raw);\r", + "const target = pm.response.json();\r", + "\r", + "\r", + " pm.test(\"Комментарий должен содержать поля: text, authorName, created\", function () {\r", + " pm.expect(target).to.have.property('text');\r", + " pm.expect(target).to.have.property('authorName');\r", + " pm.expect(target).to.have.property('created');\r", + " });\r", + "\r", + "pm.test(\"Данные в ответе должны соответствовать данным в запросе\", function () {\r", + " pm.expect(target.text).to.not.be.null;\r", + " pm.expect(source.text).equal(target.text, 'Текст комментария должен совпадать с отправленным');\r", + " });\r", + " pm.collectionVariables.set(\"commentId\", target.id);\r", + "pm.collectionVariables.set(\"authorId\", target.author);\r", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"eventId\":{{eid}},\r\n \"text\": \"Add comment from user\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8080/users/:userId/comments", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "users", + ":userId", + "comments" + ], + "variable": [ + { + "key": "userId", + "value": "{{uid}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Удаление комментария автором", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "var moment = require('moment');\r", + "\r", + "var start = moment();\r", + "pm.environment.set('currentDateTime', start.format('YYYY-MM-DDTHH:mm:ss'));\r", + "\r", + "const main = async () => {\r", + " const api = new API(pm);\r", + " const rnd = new RandomUtils();\r", + "\r", + " try {\r", + "\r", + " const category = await api.addCategory(rnd.getCategory());\r", + " let event = await api.addEvent(user.id, rnd.getEvent(category.id));\r", + " event = await api.publishEvent(event.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", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Ответ должен содержать код статуса 204\", function() {\r", + " pm.response.to.have.status(204);\r", + "}); \r", + "\r", + "\r", + "\r", + " " + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "DELETE", + "header": [], + "url": { + "raw": "http://localhost:8080/users/:userId/comments/:commentId", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "users", + ":userId", + "comments", + ":commentId" + ], + "variable": [ + { + "key": "userId", + "value": "{{uid}}" + }, + { + "key": "commentId", + "value": "{{commentId}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Добавление комментария с текстом, превышающим ограничение по длине", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "var moment = require('moment');\r", + "\r", + "var start = moment();\r", + "pm.environment.set('currentDateTime', start.format('YYYY-MM-DDTHH:mm:ss'));\r", + "\r", + "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", + " pm.collectionVariables.set(\"uid\", user.id)\r", + " const category = await api.addCategory(rnd.getCategory());\r", + " let event = await api.addEvent(user.id, rnd.getEvent(category.id));\r", + " event = await api.publishEvent(event.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", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Ответ должен содержать код статуса 400 и данные в формате json\", function () {\r", + " pm.response.to.have.status(400);\r", + " pm.response.to.be.withBody;\r", + " pm.response.to.be.json;\r", + " });" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"eventId\":{{eid}},\r\n \"text\": \"Чек-лист - это следующий этап нашего комментария. Да, его стоит прикреплять. Это можно делать по-разному: можно написать проверки в самом комментарии (не обязательно идеально подробный, но хотя бы с логическими делениями), но обязательно со статусами проверок; можно прикреплять excel-файл с чек-листами; можно прикреплять ссылку на тест-ран запущенный на специальной платформе (какое-то время я крепил pdf-файл выгруженный из qase после прохождения тест-рана - он был достаточно информативный и читабельный) - подойдут разные варианты, но важно, чтобы любой разработчик или менеджер мог всегда просмотреть проверки, которые были проведены, даже через несколько лет после вашего ухода из компании. Обнаруженные дефекты (список багов в формате что? где? когда?). Если во время тестирования были обнаружены дефекты, то они обязательно должны быть отображены в комментариях. Недостаточно просто написать, что они есть. Нужно хотя бы тезисно их перечислить. Идеальный формат, по моему мнению, что тезисы должны отвечать на вопросы что? где? когда?. Например, Не работает кнопка Отправить(что происходит?) в модальном окне Новое сообщение (где?) при нажатии (когда?). Такие баги будут понятные даже без шагов воспроизведения, ожидаемых результатов и прочего. Если по багу заведен баг-репорт, в таком случае, можно указать ссылку на тикет с дефектом.\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8080/users/:userId/comments", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "users", + ":userId", + "comments" + ], + "variable": [ + { + "key": "userId", + "value": "{{uid}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Добавление комментария с текстом, длиной менее минимальной", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "var moment = require('moment');\r", + "\r", + "var start = moment();\r", + "pm.environment.set('currentDateTime', start.format('YYYY-MM-DDTHH:mm:ss'));\r", + "\r", + "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", + " pm.collectionVariables.set(\"uid\", user.id)\r", + " const category = await api.addCategory(rnd.getCategory());\r", + " let event = await api.addEvent(user.id, rnd.getEvent(category.id));\r", + " event = await api.publishEvent(event.id);\r", + " pm.collectionVariables.set(\"eid\", event.id)\r", + " comment.text = rnd.getWord(1);\r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Ответ должен содержать код статуса 400 и данные в формате json\", function () {\r", + " pm.response.to.have.status(400);\r", + " pm.response.to.be.withBody;\r", + " pm.response.to.be.json;\r", + " });" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{{request_body}}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8080/users/:userId/comments", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "users", + ":userId", + "comments" + ], + "variable": [ + { + "key": "userId", + "value": "{{uid}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Добавление комментария к событию", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "var moment = require('moment');\r", + "\r", + "var start = moment();\r", + "pm.environment.set('currentDateTime', start.format('YYYY-MM-DDTHH:mm:ss'));\r", + "\r", + "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", + " pm.collectionVariables.set(\"uid\", user.id)\r", + " const category = await api.addCategory(rnd.getCategory());\r", + " let event = await api.addEvent(user.id, rnd.getEvent(category.id));\r", + " event = await api.publishEvent(event.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", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Ответ должен содержать код статуса 201 или 201 и данные в формате json\", function() {\r", + " pm.expect(pm.response.code).to.be.oneOf([200,201]);; // код ответа должен быть равен 201 OK\r", + " pm.response.to.be.withBody; // ответ должен содержать тело\r", + " pm.response.to.be.json; // и тело ответа должно быть в формате JSON\r", + "}); \r", + "const source = JSON.parse(pm.request.body.raw);\r", + "const target = pm.response.json();\r", + "\r", + "\r", + " pm.test(\"Комментарий должен содержать поля: text, authorName, created\", function () {\r", + " pm.expect(target).to.have.property('text');\r", + " pm.expect(target).to.have.property('authorName');\r", + " pm.expect(target).to.have.property('created');\r", + " });\r", + "\r", + "pm.test(\"Данные в ответе должны соответствовать данным в запросе\", function () {\r", + " pm.expect(target.text).to.not.be.null;\r", + " pm.expect(source.text).equal(target.text, 'Текст комментария должен совпадать с отправленным');\r", + " });\r", + " pm.collectionVariables.set(\"commentId\", target.id);\r", + "pm.collectionVariables.set(\"authorId\", target.author);\r", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"eventId\":{{eid}},\r\n \"text\": \"Add comment from user new1\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8080/users/:userId/comments", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "users", + ":userId", + "comments" + ], + "variable": [ + { + "key": "userId", + "value": "{{uid}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Создание события", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "const main = async () => {\r", + " const api = new API(pm);\r", + " const rnd = new RandomUtils();\r", + "\r", + " let event;\r", + " try {\r", + " const user = await api.addUser(rnd.getUser());\r", + " pm.collectionVariables.set(\"uid\", user.id)\r", + " const category = await api.addCategory(rnd.getCategory());\r", + " event = rnd.getEvent(category.id);\r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "\r", + " pm.request.body.update({\r", + " mode: 'raw',\r", + " raw: JSON.stringify(event),\r", + " options: { raw: { language: 'json' } }\r", + " });\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Ответ должен содержать код статуса 201 и данные в формате json\", function () {\r", + " pm.response.to.have.status(201); \r", + " pm.response.to.be.withBody;\r", + " pm.response.to.be.json;\r", + "});\r", + "\r", + "const source = JSON.parse(pm.request.body.raw);\r", + "const target = pm.response.json();\r", + "\r", + "pm.test(\"Событие должно содержать поля: id, title, annotation, category, paid, eventDate, initiator, description, participantLimit, state, createdOn, location, requestModeration\", function () {\r", + "pm.expect(target).to.have.property('id');\r", + "pm.expect(target).to.have.property('title');\r", + "pm.expect(target).to.have.property('annotation');\r", + "pm.expect(target).to.have.property('category');\r", + "pm.expect(target).to.have.property('paid');\r", + "pm.expect(target).to.have.property('eventDate');\r", + "pm.expect(target).to.have.property('initiator');\r", + "pm.expect(target).to.have.property('description');\r", + "pm.expect(target).to.have.property('participantLimit');\r", + "pm.expect(target).to.have.property('state');\r", + "pm.expect(target).to.have.property('createdOn');\r", + "pm.expect(target).to.have.property('location');\r", + "pm.expect(target).to.have.property('requestModeration');\r", + "});\r", + "\r", + "pm.test(\"Данные в ответе должны соответствовать данным в запросе\", function () {\r", + " pm.expect(target.id).to.not.be.null;\r", + " pm.expect(target.title).equal(source.title, 'Название события должно соответствовать названию события в запросе');\r", + " pm.expect(target.annotation).equal(source.annotation, 'Аннотация события должна соответствовать аннотации события в запросе');\r", + " pm.expect(target.paid.toString()).equal(source.paid.toString(), 'Стоимость события должна соответствовать стоимости события в запросе');\r", + " pm.expect(target.eventDate).equal(source.eventDate, 'Дата проведения события должна соответствовать дате проведения события в запросе');\r", + " pm.expect(target.description).equal(source.description, 'Описание события должно соответствовать описание события в запросе');\r", + " pm.expect(target.participantLimit.toString()).equal(source.participantLimit.toString(), 'Лимит участников события должно соответствовать лимиту участников события в запросе');\r", + " pm.expect(target.location.lat.toString()).equal(source.location.lat.toString(), 'Широта локации проведения события должна соответствовать широте локации проведения события в запросе');\r", + " pm.expect(target.location.lon.toString()).equal(source.location.lon.toString(), 'Долгота локации проведения события должна соответствовать долготе локации проведения события в запросе');\r", + " pm.expect(target.requestModeration.toString()).equal(source.requestModeration.toString(), 'Необходимость модерации события должна соответствовать необходимости модерации события в запросе');\r", + "});\r", + "pm.collectionVariables.set(\"eventId\", target.id);\r", + "\r", + "pm.collectionVariables.set(\"rootEvent\", target.event);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{{request_body}}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8080/users/:userId/events", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "users", + ":userId", + "events" + ], + "variable": [ + { + "key": "userId", + "value": "{{uid}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Добавление комментария", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "var moment = require('moment');\r", + "\r", + "var start = moment();\r", + "pm.environment.set('currentDateTime', start.format('YYYY-MM-DDTHH:mm:ss'));\r", + "\r", + "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", + " pm.collectionVariables.set(\"uid\", user.id)\r", + " const category = await api.addCategory(rnd.getCategory());\r", + " let event = await api.addEvent(user.id, rnd.getEvent(category.id));\r", + " event = await api.publishEvent(event.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", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Ответ должен содержать код статуса 201 и данные в формате json\", function() {\r", + " pm.expect(pm.response.code).to.be.oneOf([200, 201]);; // код ответа должен быть равен 201 OK\r", + " pm.response.to.be.withBody; // ответ должен содержать тело\r", + " pm.response.to.be.json; // и тело ответа должно быть в формате JSON\r", + "}); \r", + "const source = JSON.parse(pm.request.body.raw);\r", + "const target = pm.response.json();\r", + "pm.collectionVariables.set(\"commentId\", target.id);\r", + "\r", + "\r", + " pm.test(\"Комментарий должен содержать поля: text, authorName, created\", function () {\r", + " pm.expect(target).to.have.property('text');\r", + " pm.expect(target).to.have.property('authorName');\r", + " pm.expect(target).to.have.property('created');\r", + " });\r", + "\r", + "pm.test(\"Данные в ответе должны соответствовать данным в запросе\", function () {\r", + " pm.expect(target.text).to.not.be.null;\r", + " pm.expect(source.text).equal(target.text, 'Текст комментария должен совпадать с отправленным');\r", + " });\r", + " pm.collectionVariables.set(\"commentId\", target.id);\r", + "pm.collectionVariables.set(\"authorId\", target.author);\r", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"eventId\": {{eid}},\r\n \"text\": \"Add comment from user new\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8080/users/:userId/comments", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "users", + ":userId", + "comments" + ], + "variable": [ + { + "key": "userId", + "value": "{{uid}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Обновление комментария несуществующим пользователем", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Ответ должен содержать код статуса 404 и данные в формате json\", function () {\r", + " pm.response.to.be.notFound; \r", + " pm.response.to.be.withBody;\r", + " pm.response.to.be.json;\r", + "});" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "pm.collectionVariables.set(\"wrongUid\", -33)" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PATCH", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"id\": {{commentId}},\r\n \"text\": \"Update comment 2\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8080/users/:userId/comments/:commentId", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "users", + ":userId", + "comments", + ":commentId" + ], + "variable": [ + { + "key": "userId", + "value": "{{wrongUid}}", + "description": "(Required) id автора комментария" + }, + { + "key": "commentId", + "value": "{{commentId}}", + "description": "(Required) id комментария" + } + ] + } + }, + "response": [] + }, + { + "name": "Обновление комментария другим пользователем", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "const main = async () => {\r", + " const api = new API(pm);\r", + " const rnd = new RandomUtils();\r", + "\r", + " let event;\r", + " try {\r", + " const user = await api.addUser(rnd.getUser());\r", + " pm.collectionVariables.set(\"wrongUid\", user.id)\r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Ответ должен содержать код статуса 409 и данные в формате json\", function () {\r", + " pm.response.to.have.status(409); \r", + " pm.response.to.be.withBody;\r", + " pm.response.to.be.json;\r", + "});\r", + "\r", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PATCH", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"id\": {{commentId}},\r\n \"text\": \"Update comment 1\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8080/users/:userId/comments/:commentId", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "users", + ":userId", + "comments", + ":commentId" + ], + "variable": [ + { + "key": "userId", + "value": "{{wrongUid}}", + "description": "(Required) id автора комментария" + }, + { + "key": "commentId", + "value": "{{commentId}}", + "description": "(Required) id комментария" + } + ] + } + }, + "response": [] + }, + { + "name": "Удаление комментария несуществующим пользователем", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "pm.collectionVariables.set(\"wrongUid\", -33)" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Ответ должен содержать код статуса 404\", function() {\r", + " pm.response.to.have.status(404);\r", + "}); \r", + "\r", + "\r", + "\r", + " " + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "DELETE", + "header": [], + "url": { + "raw": "http://localhost:8080/users/:userId/comments/:commentId", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "users", + ":userId", + "comments", + ":commentId" + ], + "variable": [ + { + "key": "userId", + "value": "{{wrongUid}}" + }, + { + "key": "commentId", + "value": "{{commentId}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Удаление комментария другим пользователем", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "const main = async () => {\r", + " const api = new API(pm);\r", + " const rnd = new RandomUtils();\r", + "\r", + " let event;\r", + " try {\r", + " const user = await api.addUser(rnd.getUser());\r", + " pm.collectionVariables.set(\"wrongUid\", user.id)\r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Ответ должен содержать код статуса 409\", function() {\r", + " pm.response.to.have.status(409);\r", + "}); \r", + "\r", + "\r", + "\r", + " " + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "DELETE", + "header": [], + "url": { + "raw": "http://localhost:8080/users/:userId/comments/:commentId", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "users", + ":userId", + "comments", + ":commentId" + ], + "variable": [ + { + "key": "userId", + "value": "{{wrongUid}}" + }, + { + "key": "commentId", + "value": "{{commentId}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Добавление комментария (проверка версий)", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "var moment = require('moment');\r", + "\r", + "var start = moment();\r", + "pm.environment.set('currentDateTime', start.format('YYYY-MM-DDTHH:mm:ss'));\r", + "\r", + "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", + " pm.collectionVariables.set(\"uid\", user.id)\r", + " const category = await api.addCategory(rnd.getCategory());\r", + " let event = await api.addEvent(user.id, rnd.getEvent(category.id));\r", + " event = await api.publishEvent(event.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", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Ответ должен содержать код статуса 201 и данные в формате json\", function() {\r", + " pm.expect(pm.response.code).to.be.oneOf([200, 201]);; // код ответа должен быть равен 201 OK\r", + " pm.response.to.be.withBody; // ответ должен содержать тело\r", + " pm.response.to.be.json; // и тело ответа должно быть в формате JSON\r", + "}); \r", + "const source = JSON.parse(pm.request.body.raw);\r", + "const target = pm.response.json();\r", + "pm.collectionVariables.set(\"commentId\", target.id);\r", + "\r", + "\r", + " pm.test(\"Комментарий должен содержать поля: text, authorName, created\", function () {\r", + " pm.expect(target).to.have.property('text');\r", + " pm.expect(target).to.have.property('authorName');\r", + " pm.expect(target).to.have.property('created');\r", + " });\r", + "\r", + "pm.test(\"Данные в ответе должны соответствовать данным в запросе\", function () {\r", + " pm.expect(target.text).to.not.be.null;\r", + " pm.expect(source.text).equal(target.text, 'Текст комментария должен совпадать с отправленным');\r", + " });\r", + " pm.collectionVariables.set(\"commentId\", target.id);\r", + "pm.collectionVariables.set(\"authorId\", target.author);\r", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"eventId\": {{eid}},\r\n \"text\": \"Add comment from user new\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8080/users/:userId/comments", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "users", + ":userId", + "comments" + ], + "variable": [ + { + "key": "userId", + "value": "{{uid}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Обновление комментария пользователем Copy", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Ответ должен содержать код статуса 201 или 201 и данные в формате json\", function() {\r", + " pm.expect(pm.response.code).to.be.oneOf([200,201]);; // код ответа должен быть равен 201 OK\r", + " pm.response.to.be.withBody; // ответ должен содержать тело\r", + " pm.response.to.be.json; // и тело ответа должно быть в формате JSON\r", + "}); \r", + "const source = JSON.parse(pm.request.body.raw);\r", + "const target = pm.response.json();\r", + "\r", + "\r", + " pm.test(\"Комментарий должен содержать поля: text, authorName, created\", function () {\r", + " pm.expect(target).to.have.property('text');\r", + " pm.expect(target).to.have.property('authorName');\r", + " pm.expect(target).to.have.property('created');\r", + " });\r", + "\r", + "pm.test(\"Данные в ответе должны соответствовать данным в запросе\", function () {\r", + " pm.expect(target.text).to.not.be.null;\r", + " pm.expect(source.text).equal(target.text, 'Текст комментария должен совпадать с отправленным');\r", + " });\r", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PATCH", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"id\": {{commentId}},\r\n \"text\": \"Update comment 1\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8080/users/:userId/comments/:commentId", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "users", + ":userId", + "comments", + ":commentId" + ], + "variable": [ + { + "key": "userId", + "value": "{{uid}}", + "description": "(Required) id автора комментария" + }, + { + "key": "commentId", + "value": "{{commentId}}", + "description": "(Required) id комментария" + } + ] + } + }, + "response": [] + }, + { + "name": "Обновление комментария пользователем Copy 2", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Ответ должен содержать код статуса 201 или 201 и данные в формате json\", function() {\r", + " pm.expect(pm.response.code).to.be.oneOf([200,201]);; // код ответа должен быть равен 201 OK\r", + " pm.response.to.be.withBody; // ответ должен содержать тело\r", + " pm.response.to.be.json; // и тело ответа должно быть в формате JSON\r", + "}); \r", + "const source = JSON.parse(pm.request.body.raw);\r", + "const target = pm.response.json();\r", + "\r", + "\r", + " pm.test(\"Комментарий должен содержать поля: text, authorName, created\", function () {\r", + " pm.expect(target).to.have.property('text');\r", + " pm.expect(target).to.have.property('authorName');\r", + " pm.expect(target).to.have.property('created');\r", + " });\r", + "\r", + "pm.test(\"Данные в ответе должны соответствовать данным в запросе\", function () {\r", + " pm.expect(target.text).to.not.be.null;\r", + " pm.expect(source.text).equal(target.text, 'Текст комментария должен совпадать с отправленным');\r", + " });\r", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PATCH", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"id\": {{commentId}},\r\n \"text\": \"Update comment 2\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8080/users/:userId/comments/:commentId", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "users", + ":userId", + "comments", + ":commentId" + ], + "variable": [ + { + "key": "userId", + "value": "{{uid}}", + "description": "(Required) id автора комментария" + }, + { + "key": "commentId", + "value": "{{commentId}}", + "description": "(Required) id комментария" + } + ] + } + }, + "response": [] + }, + { + "name": "Получение версии комментариев по идентификатору", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "var moment = require('moment');\r", + "\r", + "var start = moment();\r", + "pm.environment.set('currentDateTime', start.format('YYYY-MM-DDTHH:mm:ss'));\r", + "\r", + "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", + " \r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Ответ должен содержать код статуса 200 и данные в формате json\", function () {\r", + " pm.response.to.be.ok; \r", + " pm.response.to.be.withBody;\r", + " pm.response.to.be.json;\r", + "});\r", + "\r", + "pm.test(\"Test list item response\", function () {\r", + " pm.response.to.be.withBody;\r", + " pm.response.to.be.json;\r", + " var jsonData = pm.response.json();\r", + " pm.expect(jsonData.length, 'List length must be 3').to.eql(3);\r", + "});\r", + "\r", + "pm.test(\"Test item[0] 'id' field\", function () {\r", + " var jsonData = pm.response.json();\r", + " pm.expect(jsonData[0]).to.have.property('id');\r", + "});\r", + "\r", + "pm.test(\"Test item[0] 'commentId' field\", function () {\r", + " var jsonData = pm.response.json();\r", + " pm.expect(jsonData[0]).to.have.property('commentId');\r", + " pm.expect(jsonData[0].commentId, '\"commentId\" must be '+pm.collectionVariables.get(\"commentId\")).to.eql(pm.collectionVariables.get(\"commentId\"));\r", + "});\r", + "\r", + "pm.test(\"Test item[0] 'text' field\", function () {\r", + " var jsonData = pm.response.json();\r", + " pm.expect(jsonData[0]).to.have.property('text');\r", + " pm.expect(jsonData[0].text, '\"text\" must be \"Add comment from user new\"').to.eql('Add comment from user new');\r", + "});\r", + "\r", + "pm.test(\"Test item[2] 'text' field\", function () {\r", + " var jsonData = pm.response.json();\r", + " pm.expect(jsonData[2]).to.have.property('text');\r", + " pm.expect(jsonData[2].text, '\"text\" must be \"Update comment 2\"').to.eql('Update comment 2');\r", + "});\r", + "\r", + "\r", + "\r", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "http://localhost:8080/users/:userId/comments/history/:comment", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "users", + ":userId", + "comments", + "history", + ":comment" + ], + "variable": [ + { + "key": "userId", + "value": "{{uid}}" + }, + { + "key": "comment", + "value": "{{commentId}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Получение версии комментариев по идентификатору с неправильным идентификатором пользователя", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "var moment = require('moment');\r", + "\r", + "var start = moment();\r", + "pm.environment.set('currentDateTime', start.format('YYYY-MM-DDTHH:mm:ss'));\r", + "\r", + "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", + " \r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Ответ должен содержать код статуса 404 и данные в формате json\", function () {\r", + " pm.response.to.have.status(404); \r", + " pm.response.to.be.withBody;\r", + " pm.response.to.be.json;\r", + "});\r", + "\r", + "\r", + "\r", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "http://localhost:8080/users/:userId/comments/history/:comment", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "users", + ":userId", + "comments", + "history", + ":comment" + ], + "variable": [ + { + "key": "userId", + "value": "0" + }, + { + "key": "comment", + "value": "{{commentId}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Получение версии комментариев по идентификатору администратором", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "var moment = require('moment');\r", + "\r", + "var start = moment();\r", + "pm.environment.set('currentDateTime', start.format('YYYY-MM-DDTHH:mm:ss'));\r", + "\r", + "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", + " \r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Ответ должен содержать код статуса 200 и данные в формате json\", function () {\r", + " pm.response.to.be.ok; \r", + " pm.response.to.be.withBody;\r", + " pm.response.to.be.json;\r", + "});\r", + "\r", + "pm.test(\"Test list item response\", function () {\r", + " pm.response.to.be.withBody;\r", + " pm.response.to.be.json;\r", + " var jsonData = pm.response.json();\r", + " pm.expect(jsonData.length, 'List length must be 3').to.eql(3);\r", + "});\r", + "\r", + "pm.test(\"Test item[0] 'id' field\", function () {\r", + " var jsonData = pm.response.json();\r", + " pm.expect(jsonData[0]).to.have.property('id');\r", + "});\r", + "\r", + "pm.test(\"Test item[0] 'commentId' field\", function () {\r", + " var jsonData = pm.response.json();\r", + " pm.expect(jsonData[0]).to.have.property('commentId');\r", + " pm.expect(jsonData[0].commentId, '\"commentId\" must be '+pm.collectionVariables.get(\"commentId\")).to.eql(pm.collectionVariables.get(\"commentId\"));\r", + "});\r", + "\r", + "pm.test(\"Test item[0] 'text' field\", function () {\r", + " var jsonData = pm.response.json();\r", + " pm.expect(jsonData[0]).to.have.property('text');\r", + " pm.expect(jsonData[0].text, '\"text\" must be \"Add comment from user new\"').to.eql('Add comment from user new');\r", + "});\r", + "\r", + "pm.test(\"Test item[2] 'text' field\", function () {\r", + " var jsonData = pm.response.json();\r", + " pm.expect(jsonData[2]).to.have.property('text');\r", + " pm.expect(jsonData[2].text, '\"text\" must be \"Update comment 2\"').to.eql('Update comment 2');\r", + "});\r", + "\r", + "\r", + "\r", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "http://localhost:8080/admin/comments/history/:comment", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "admin", + "comments", + "history", + ":comment" + ], + "variable": [ + { + "key": "comment", + "value": "{{commentId}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Получение списка комментариев с неверными параметрами пагинации", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 400\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([500,400]);\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "http://localhost:8080/comments/events/:eventId?from=0&size=-1", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "comments", + "events", + ":eventId" + ], + "query": [ + { + "key": "from", + "value": "0" + }, + { + "key": "size", + "value": "-1" + } + ], + "variable": [ + { + "key": "eventId", + "value": "{{eid}}" + } + ] + } + }, + "response": [] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "API = class {", + " constructor(postman, verbose = false, baseUrl = \"http://localhost:8080\") {", + " this.baseUrl = baseUrl;", + " this.pm = postman;", + " this._verbose = verbose;", + " }", + "", + " async addUser(user, verbose=null) {", + " return this.post(\"/admin/users\", user, \"Ошибка при добавлении нового пользователя: \", verbose);", + " }", + "", + " async addCategory(category, verbose=null) {", + " return this.post(\"/admin/categories\", category, \"Ошибка при добавлении новой категории: \", verbose);", + " }", + "", + " async addEvent(userId, event, verbose=null) {", + " return this.post(\"/users/\" + userId + \"/events\", event, \"Ошибка при добавлении нового события: \", verbose);", + " }", + "", + " async addCompilation(compilation, verbose=null) {", + " return this.post(\"/admin/compilations\", compilation, \"Ошибка при добавлении новой подборки: \", verbose);", + " }", + "", + " async publishParticipationRequest(eventId, userId, verbose=null) {", + " return this.post('/users/' + userId + '/requests?eventId=' + eventId, null, \"Ошибка при добавлении нового запроса на участие в событии\", verbose);", + " }", + "", + " async publishEvent(eventId, verbose=null) {", + " return this.patch('/admin/events/' + eventId, {stateAction: \"PUBLISH_EVENT\"}, \"Ошибка при публикации события\", verbose);", + " }", + " ", + " async rejectEvent(eventId, verbose=null) {", + " return this.patch('/admin/events/' + eventId, {stateAction: \"REJECT_EVENT\"}, \"Ошибка при отмене события\", verbose);", + " }", + "", + " async acceptParticipationRequest(eventId, userId, reqId, verbose=null) {", + " return this.patch('/users/' + userId + '/events/' + eventId + '/requests/', {requestIds:[reqId], status: \"CONFIRMED\"}, \"Ошибка при принятии заявки на участие в событии\", verbose);", + " }", + "", + " async findCategory(catId, verbose=null) {", + " return this.get('/categories/' + catId, null, \"Ошибка при поиске категории по id\", verbose);", + " }", + "", + " async findCompilation(compId, verbose=null) {", + " return this.get('/compilations/' + compId, null, \"Ошибка при поиске подборки по id\", verbose);", + " }", + "", + " async findEvent(eventId, verbose=null) {", + " return this.get('/events/' + eventId, null, \"Ошибка при поиске события по id\", verbose);", + " }", + "", + " async findUser(userId, verbose=null) {", + " return this.get('/admin/users?ids=' + userId, null, \"Ошибка при поиске пользователя по id\", verbose);", + " }", + "", + " async addComment(userId, comment, replyToComment, verbose=null) {", + " return this.post('/users/' + userId + '/comments', comment, \"Ошибка при добавлении нового комментария\", verbose);", + " }", + "", + " async post(path, body, errorText = \"Ошибка при выполнении post-запроса: \", verbose=null) {", + " return this.sendRequest(\"POST\", path, body, errorText, verbose);", + " }", + "", + " async patch(path, body = null, errorText = \"Ошибка при выполнении patch-запроса: \", verbose=null) {", + " return this.sendRequest(\"PATCH\", path, body, errorText, verbose);", + " }", + "", + " async get(path, body = null, errorText = \"Ошибка при выполнении get-запроса: \", verbose=null) {", + " return this.sendRequest(\"GET\", path, body, errorText, verbose);", + " }", + "", + " async sendRequest(method, path, body=null, errorText = \"Ошибка при выполнении запроса: \", verbose=null) {", + " return new Promise((resolve, reject) => {", + " verbose = verbose == null ? this._verbose : verbose;", + "", + " const request = {", + " url: this.baseUrl + path,", + " method: method,", + " body: body == null ? \"\" : JSON.stringify(body),", + " header: { \"Content-Type\": \"application/json\" },", + " };", + "", + " if(verbose) {", + " console.log(\"Отправляю запрос: \", request);", + " }", + "", + " try {", + " this.pm.sendRequest(request, (error, response) => {", + " if(error || (response.code >= 400 && response.code <= 599)) {", + " let err = error ? error : JSON.stringify(response.json());", + " console.error(\"При выполнении запроса к серверу возникла ошика.\\n\", err,", + " \"\\nДля отладки проблемы повторите такой же запрос к вашей программе \" + ", + " \"на локальном компьютере. Данные запроса:\\n\", JSON.stringify(request));", + "", + " reject(new Error(errorText + err));", + " }", + "", + " if(verbose) {", + " console.log(\"Результат обработки запроса: код состояния - \", response.code, \", тело: \", response.json());", + " }", + "", + " resolve(response.json());", + " });", + " } catch(err) {", + " if(verbose) {", + " console.error(errorText, err);", + " }", + " return Promise.reject(err);", + " }", + " });", + " }", + "};", + "", + "RandomUtils = class {", + " constructor() {}", + "", + " getUser() {", + " return {", + " name: pm.variables.replaceIn('{{$randomFullName}}'),", + " email: pm.variables.replaceIn('{{$randomEmail}}')", + " };", + " }", + "", + " getCategory() {", + " return {", + " name: pm.variables.replaceIn('{{$randomWord}}') + Math.floor(Math.random() * 100).toString()", + " };", + " }", + "", + " getEvent(categoryId) {", + " return {", + " annotation: pm.variables.replaceIn('{{$randomLoremParagraph}}'),", + " category: categoryId,", + " description: pm.variables.replaceIn('{{$randomLoremParagraphs}}'),", + " eventDate: this.getFutureDateTime(),", + " location: {", + " lat: parseFloat(pm.variables.replaceIn('{{$randomLatitude}}')),", + " lon: parseFloat(pm.variables.replaceIn('{{$randomLongitude}}')),", + " },", + " paid: pm.variables.replaceIn('{{$randomBoolean}}'),", + " participantLimit: pm.variables.replaceIn('{{$randomInt}}'),", + " requestModeration: pm.variables.replaceIn('{{$randomBoolean}}'),", + " title: pm.variables.replaceIn('{{$randomLoremSentence}}'),", + " }", + " }", + "", + " getCompilation(...eventIds) {", + " return {", + " title: pm.variables.replaceIn('{{$randomLoremSentence}}').slice(0, 50),", + " pinned: pm.variables.replaceIn('{{$randomBoolean}}'),", + " events: eventIds", + " };", + " }", + "", + "", + " getFutureDateTime(hourShift = 5, minuteShift=0, yearShift=0) {", + " let moment = require('moment');", + "", + " let m = moment();", + " m.add(hourShift, 'hour');", + " m.add(minuteShift, 'minute');", + " m.add(yearShift, 'year');", + "", + " return m.format('YYYY-MM-DD HH:mm:ss');", + " }", + "", + " getWord(length = 1) {", + " let result = '';", + " const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';", + " const charactersLength = characters.length;", + " let counter = 0;", + " while (counter < length) {", + " result += characters.charAt(Math.floor(Math.random() * charactersLength));", + " counter += 1;", + " }", + " return result;", + " }", + "}" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ], + "variable": [ + { + "key": "userId", + "value": "" + }, + { + "key": "uid", + "value": "" + }, + { + "key": "response", + "value": "" + }, + { + "key": "eid", + "value": "" + }, + { + "key": "eventId", + "value": "" + }, + { + "key": "commentId", + "value": "" + }, + { + "key": "authorId", + "value": "" + }, + { + "key": "rootEvent", + "value": "" + }, + { + "key": "wrongUid", + "value": "0" + } + ] +} \ No newline at end of file