diff --git a/nekontakte/src/main/java/com/example/nekontakte/core/api/HomeCotroller.java b/nekontakte/src/main/java/com/example/nekontakte/core/api/HomeCotroller.java index 735ee85..1357be7 100644 --- a/nekontakte/src/main/java/com/example/nekontakte/core/api/HomeCotroller.java +++ b/nekontakte/src/main/java/com/example/nekontakte/core/api/HomeCotroller.java @@ -2,9 +2,13 @@ package com.example.nekontakte.core.api; import java.util.ArrayList; import java.util.List; +import java.util.Map; + +import com.example.nekontakte.core.configurations.Constants; import com.example.nekontakte.posts.api.PostDTO; import com.example.nekontakte.posts.model.PostEntity; +import org.springframework.data.domain.Page; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; @@ -13,8 +17,6 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import com.example.nekontakte.posts.service.PostService; -import com.example.nekontakte.users.api.UserDTO; -import com.example.nekontakte.users.api.UserEditDTO; import com.example.nekontakte.users.service.UserService; @Controller @@ -23,6 +25,7 @@ public class HomeCotroller { public static final String URL = "/"; private static final String PAGE_ATTRIBUTE = "page"; private static final String POSTS_ATTRIBUTE = "posts"; + private static final String POST_ATTRIBUTE = "post"; private static final String FEED_VIEW = "feed"; private static final String SUBS_VIEW = "subs"; private static final String USER_PROFILE_VIEW = "user-profile"; @@ -37,14 +40,18 @@ public class HomeCotroller { @GetMapping("/feed") public String getFeed(@RequestParam(name = PAGE_ATTRIBUTE, defaultValue = "0") int page, Model model) { - List posts = postsService.getAll(); + Page pageEntities = postsService.getAll(page, 4); + List posts = pageEntities.getContent(); List postDTOs = new ArrayList(); for (PostEntity postEntity : posts) { PostDTO postDTO = PostDTO.createFromEntity(postEntity); postDTOs.add(postDTO); } + model.addAttribute("totalPages", pageEntities.getTotalPages()); + model.addAttribute("currentPage", pageEntities.getNumber()); model.addAttribute(PAGE_ATTRIBUTE, page); model.addAttribute(POSTS_ATTRIBUTE, postDTOs); + model.addAttribute(POST_ATTRIBUTE, new PostDTO()); return FEED_VIEW; } diff --git a/nekontakte/src/main/java/com/example/nekontakte/posts/api/PostController.java b/nekontakte/src/main/java/com/example/nekontakte/posts/api/PostController.java deleted file mode 100644 index e4ef5ab..0000000 --- a/nekontakte/src/main/java/com/example/nekontakte/posts/api/PostController.java +++ /dev/null @@ -1,81 +0,0 @@ -package com.example.nekontakte.posts.api; - -import com.example.nekontakte.core.api.PageDto; -import com.example.nekontakte.core.api.PageDtoMapper; -import com.example.nekontakte.core.configurations.Constants; - -import org.apache.coyote.BadRequestException; -import org.modelmapper.ModelMapper; -import org.springframework.data.domain.PageRequest; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import com.example.nekontakte.posts.model.PostEntity; -import com.example.nekontakte.posts.service.PostService; -import com.example.nekontakte.users.service.UserService; - -import jakarta.validation.Valid; - -@RestController -@RequestMapping(Constants.API_URL + "/post") -public class PostController { - - private final PostService postService; - private final ModelMapper modelMapper; - - public PostController(PostService postService, ModelMapper modelMapper, UserService userService) { - this.modelMapper = modelMapper; - this.postService = postService; - } - - private PostEntity toEntity(PostDTO dto) { - return modelMapper.map(dto, PostEntity.class); - } - - private PostDTO toDTO(PostEntity entity) { - return modelMapper.map(entity, PostDTO.class); - } - - @GetMapping - public PageDto getAll(@RequestParam(name = "pageNumber", defaultValue = "0") Integer pageNumber, - @RequestParam(name = "pageSize", defaultValue = "5") Integer pageSize) { - PageRequest pageRequest = PageRequest.of(pageNumber, pageSize); - return PageDtoMapper.toDto(postService.getAll(pageRequest), this::toDTO); - } - - @GetMapping("/user/{userId}") - public PageDto getAllByUserId(@PathVariable(name = "userId") Integer userId, - @RequestParam(name = "pageNumber", defaultValue = "0") Integer pageNumber, - @RequestParam(name = "pageSize", defaultValue = "5") Integer pageSize) { - PageRequest pageRequest = PageRequest.of(pageNumber, pageSize); - return PageDtoMapper.toDto(postService.getAllByUserId(userId, pageRequest), this::toDTO); - } - - @GetMapping("/{id}") - public PostDTO get(@PathVariable(name = "id") Integer id) { - return toDTO(postService.get(id)); - } - - @PostMapping - public PostDTO create(@RequestBody @Valid PostDTO PostDTO) throws BadRequestException { - return toDTO(postService.create(toEntity(PostDTO))); - } - - @PutMapping("/{id}") - public PostDTO update(@PathVariable(name = "id") Integer id, @RequestBody PostDTO PostDTO) { - return toDTO(postService.update(id, toEntity(PostDTO))); - } - - @DeleteMapping("/{id}") - public PostDTO delete(@PathVariable(name = "id") Integer id) { - return toDTO(postService.delete(id)); - } - -} diff --git a/nekontakte/src/main/java/com/example/nekontakte/posts/api/PostDTO.java b/nekontakte/src/main/java/com/example/nekontakte/posts/api/PostDTO.java index e31c556..4a66a49 100644 --- a/nekontakte/src/main/java/com/example/nekontakte/posts/api/PostDTO.java +++ b/nekontakte/src/main/java/com/example/nekontakte/posts/api/PostDTO.java @@ -1,7 +1,10 @@ package com.example.nekontakte.posts.api; +import java.time.LocalDateTime; import java.util.Date; +import org.springframework.format.annotation.DateTimeFormat; + import com.example.nekontakte.posts.model.PostEntity; import com.example.nekontakte.users.api.UserDTO; import com.fasterxml.jackson.annotation.JsonProperty; @@ -28,11 +31,20 @@ public class PostDTO { } @NotNull - private Date pubDate; + @DateTimeFormat(pattern = "dd-MM-yyyy HH:mm") + private LocalDateTime pubDate; private String image; - private String html; + private String text; + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } public Integer getId() { return id; @@ -42,11 +54,11 @@ public class PostDTO { this.id = id; } - public Date getPubDate() { + public LocalDateTime getPubDate() { return pubDate; } - public void setPubDate(Date pubDate) { + public void setPubDate(LocalDateTime pubDate) { this.pubDate = pubDate; } @@ -58,14 +70,6 @@ public class PostDTO { this.image = image; } - public String getHtml() { - return html; - } - - public void setHtml(String html) { - this.html = html; - } - public Integer getUserId() { return userId; } @@ -78,7 +82,7 @@ public class PostDTO { PostDTO post = new PostDTO(); post.setId(entity.getId()); post.setUserId(entity.getUser().getId()); - post.setHtml(entity.getHtml()); + post.setText(entity.getHtml()); post.setImage(entity.getImage()); post.setPubDate(entity.getPubDate()); post.setUserDTO(UserDTO.createFromEntity(entity.getUser())); diff --git a/nekontakte/src/main/java/com/example/nekontakte/posts/api/PostsController.java b/nekontakte/src/main/java/com/example/nekontakte/posts/api/PostsController.java new file mode 100644 index 0000000..0d60960 --- /dev/null +++ b/nekontakte/src/main/java/com/example/nekontakte/posts/api/PostsController.java @@ -0,0 +1,83 @@ +package com.example.nekontakte.posts.api; + +import com.example.nekontakte.core.configurations.Constants; + +import org.apache.coyote.BadRequestException; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.servlet.mvc.support.RedirectAttributes; + +import com.example.nekontakte.posts.model.PostEntity; +import com.example.nekontakte.posts.service.PostService; +import com.example.nekontakte.users.service.UserService; + +import jakarta.validation.Valid; + +@Controller +@RequestMapping(PostsController.URL) +public class PostsController { + public static final String URL = "/posts"; + private static final String PAGE_ATTRIBUTE = "page"; + private static final String POST_ATTRIBUTE = "post"; + + private final PostService postService; + private final UserService userService; + + public PostsController(PostService postService, UserService userService) { + this.userService = userService; + this.postService = postService; + } + + private PostEntity toEntity(PostDTO dto) { + PostEntity entity = new PostEntity(); + entity.setId(dto.getId()); + entity.setHtml(dto.getText()); + entity.setImage(dto.getImage()); + entity.setPubDate(dto.getPubDate()); + entity.setUser(userService.get(dto.getUserId())); + return entity; + } + + private PostDTO toDTO(PostEntity entity) { + return PostDTO.createFromEntity(entity); + } + + @PostMapping("/create/{username}") + public String create(Model model, + @PathVariable(name = "username") String username, + @RequestParam(name = PAGE_ATTRIBUTE, defaultValue = "0") int page, + @ModelAttribute(name = POST_ATTRIBUTE) @Valid PostDTO postDTO, + RedirectAttributes redirectAttributes) throws BadRequestException { + + postDTO.setUserId(userService.getByUsername(username).getId()); + + postService.create(toEntity(postDTO)); + + redirectAttributes.addAttribute(PAGE_ATTRIBUTE, page); + + return Constants.REDIRECT_VIEW + "/feed"; + } + + @PostMapping("/{id}") + public PostDTO update(@PathVariable(name = "id") Integer id, @RequestBody PostDTO PostDTO) { + return toDTO(postService.update(id, toEntity(PostDTO))); + } + + @PostMapping("/delete/{id}") + public String delete(@PathVariable(name = "id") Integer id, + @RequestParam(name = PAGE_ATTRIBUTE, defaultValue = "0") int page, + RedirectAttributes redirectAttributes, + Model model) { + postService.delete(id); + redirectAttributes.addAttribute(PAGE_ATTRIBUTE, page); + return Constants.REDIRECT_VIEW + "/feed"; + } + +} diff --git a/nekontakte/src/main/java/com/example/nekontakte/posts/model/PostEntity.java b/nekontakte/src/main/java/com/example/nekontakte/posts/model/PostEntity.java index 0f8c79d..6d0fbd2 100644 --- a/nekontakte/src/main/java/com/example/nekontakte/posts/model/PostEntity.java +++ b/nekontakte/src/main/java/com/example/nekontakte/posts/model/PostEntity.java @@ -1,5 +1,6 @@ package com.example.nekontakte.posts.model; +import java.time.LocalDateTime; import java.util.Date; import java.util.Objects; @@ -21,9 +22,9 @@ public class PostEntity extends BaseEntity { @JoinColumn(name = "userId", nullable = false) private UserEntity user; - @Temporal(value = TemporalType.DATE) + @Temporal(value = TemporalType.TIMESTAMP) @Column(nullable = false) - private Date pubDate; + private LocalDateTime pubDate; @Column private String image; @@ -42,11 +43,11 @@ public class PostEntity extends BaseEntity { this.user = user; } - public Date getPubDate() { + public LocalDateTime getPubDate() { return pubDate; } - public void setPubDate(Date pubDate) { + public void setPubDate(LocalDateTime pubDate) { this.pubDate = pubDate; } diff --git a/nekontakte/src/main/java/com/example/nekontakte/posts/repository/PostRepository.java b/nekontakte/src/main/java/com/example/nekontakte/posts/repository/PostRepository.java index 1d51ad1..0905aff 100644 --- a/nekontakte/src/main/java/com/example/nekontakte/posts/repository/PostRepository.java +++ b/nekontakte/src/main/java/com/example/nekontakte/posts/repository/PostRepository.java @@ -2,6 +2,7 @@ package com.example.nekontakte.posts.repository; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.PagingAndSortingRepository; diff --git a/nekontakte/src/main/java/com/example/nekontakte/posts/service/PostService.java b/nekontakte/src/main/java/com/example/nekontakte/posts/service/PostService.java index 0e0323f..1b82f4f 100644 --- a/nekontakte/src/main/java/com/example/nekontakte/posts/service/PostService.java +++ b/nekontakte/src/main/java/com/example/nekontakte/posts/service/PostService.java @@ -2,13 +2,19 @@ package com.example.nekontakte.posts.service; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; +import org.springframework.data.domain.Sort.Direction; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.Random; + import com.example.nekontakte.core.errors.NotFoundException; import com.example.nekontakte.posts.model.PostEntity; import com.example.nekontakte.posts.repository.PostRepository; +import java.time.LocalDateTime; +import java.util.Comparator; import java.util.List; import java.util.stream.StreamSupport; @@ -20,6 +26,15 @@ public class PostService { this.repository = repository; } + public List getSorted(List posts) { + posts.sort(new Comparator() { + public int compare(PostEntity o1, PostEntity o2) { + return o1.getPubDate().compareTo(o2.getPubDate()); + } + }); + return posts; + } + @Transactional(readOnly = true) public Page getAllByUserId(Integer userId, PageRequest pageRequest) { return repository.findByUserId(userId, pageRequest); @@ -30,6 +45,12 @@ public class PostService { return repository.findByUserId(userId); } + @Transactional(readOnly = true) + public Page getAll(Integer pageNumber, Integer pageSize) { + PageRequest pageRequest = PageRequest.of(pageNumber, pageSize, Sort.by(Direction.DESC, "pubDate")); + return repository.findAll(pageRequest); + } + @Transactional(readOnly = true) public Page getAll(PageRequest pageRequest) { return repository.findAll(pageRequest); @@ -49,6 +70,11 @@ public class PostService { if (entity.getImage() == null && entity.getHtml() == null) { throw new org.apache.coyote.BadRequestException("Image or Html must be not null"); } + entity.setPubDate(LocalDateTime.now()); + Random rand = new Random(); + if (rand.nextBoolean()) { + entity.setImage("https://loremflickr.com/240/320?lock=" + Integer.toString(rand.nextInt(0, 1000000))); + } return repository.save(entity); } diff --git a/nekontakte/src/main/java/com/example/nekontakte/users/api/AdminUserController.java b/nekontakte/src/main/java/com/example/nekontakte/users/api/AdminUserController.java index 4906d61..8a23a56 100644 --- a/nekontakte/src/main/java/com/example/nekontakte/users/api/AdminUserController.java +++ b/nekontakte/src/main/java/com/example/nekontakte/users/api/AdminUserController.java @@ -143,7 +143,7 @@ public class AdminUserController { } return Constants.REDIRECT_VIEW + URL; } - + @PostMapping("/delete/{id}") public String postDeleteView( @PathVariable(name = "id") Integer id, diff --git a/nekontakte/src/main/java/com/example/nekontakte/users/service/UserService.java b/nekontakte/src/main/java/com/example/nekontakte/users/service/UserService.java index 6c19f9e..c85c3e5 100644 --- a/nekontakte/src/main/java/com/example/nekontakte/users/service/UserService.java +++ b/nekontakte/src/main/java/com/example/nekontakte/users/service/UserService.java @@ -68,6 +68,9 @@ public class UserService implements UserDetailsService { throw new IllegalArgumentException( String.format("User with username %s is already exists", entity.getUsername())); } + if (entity.getAvatarImg() == null) { + entity.setAvatarImg("https://i.pravatar.cc/150?u=" + entity.getUsername()); + } return repository.save(entity); } @@ -78,6 +81,7 @@ public class UserService implements UserDetailsService { throw new IllegalArgumentException( String.format("User with username %s is already exists", entity.getUsername())); } + entity.setAvatarImg("https://i.pravatar.cc/150?u=" + entity.getUsername()); repository.save(entity); return existsentity; } diff --git a/nekontakte/src/main/resources/public/css/style.css b/nekontakte/src/main/resources/public/css/style.css index 07fa21e..1f25eba 100644 --- a/nekontakte/src/main/resources/public/css/style.css +++ b/nekontakte/src/main/resources/public/css/style.css @@ -1,3 +1,7 @@ +a { + text-decoration: none; +} + html, body { height: 100%; @@ -59,3 +63,69 @@ td form { textarea { min-height: 1.5em; } + +.post-meta { + font-size: small; +} + +.counter-block { + transition: 0.1s; + cursor: pointer; +} + +.counter-block:hover { + background-color: #e8e8e8; +} + +.post-body-img { + width: 100%; +} + +.post-body a { + color: #4a9cb7; + text-decoration: none; + background-image: linear-gradient(currentColor, currentColor); + background-position: 0% 100%; + background-repeat: no-repeat; + background-size: 0% 2px; + transition: background-size 0.3s; +} + +.post-body a:hover { + background-size: 100% 2px; +} + +.post-body-text { + white-space: pre-wrap; +} + +.avatar-small { + width: 35px; + height: 35px; + object-fit: cover; +} + +.username-link { + transition: 0.3s; + display: flex; +} + +.username-link::before { + content: "@"; + display: flex; + flex-direction: row; + padding: 0; + margin: 0; +} + +.username-link::hover { + text-decoration: underline; +} + +.b1 { + border: none; + background: none; + cursor: pointer; + margin: 0; + padding: 0; +} diff --git a/nekontakte/src/main/resources/templates/feed.html b/nekontakte/src/main/resources/templates/feed.html index 9fb1934..52440ea 100644 --- a/nekontakte/src/main/resources/templates/feed.html +++ b/nekontakte/src/main/resources/templates/feed.html @@ -12,17 +12,21 @@
-
+
+
@@ -39,9 +43,9 @@
diff --git a/nekontakte/src/main/resources/templates/index.html b/nekontakte/src/main/resources/templates/index.html index 9b2b6d5..2ac69a4 100644 --- a/nekontakte/src/main/resources/templates/index.html +++ b/nekontakte/src/main/resources/templates/index.html @@ -80,8 +80,7 @@ Профиль diff --git a/nekontakte/src/main/resources/templates/posts.html b/nekontakte/src/main/resources/templates/posts.html index 7ad870e..a4adec2 100644 --- a/nekontakte/src/main/resources/templates/posts.html +++ b/nekontakte/src/main/resources/templates/posts.html @@ -1,48 +1,105 @@ - -
-
- - - - -
- - -
-
-
-
- [[${post.html}]] -
- - - -
- -
- - \ No newline at end of file + +
+
+
+ + +
+
+ +
+
+ +
+
+
+
+ + +
+ +
+ + +
+ + +
+
+ +