diff --git a/Laba5.1/.vscode/launch.json b/Laba5.1/.vscode/launch.json index c6b156c..7622aae 100644 --- a/Laba5.1/.vscode/launch.json +++ b/Laba5.1/.vscode/launch.json @@ -6,7 +6,7 @@ "request": "launch", "cwd": "${workspaceFolder}", "mainClass": "com.example.demo.DemoApplication", - "projectName": "lec7", + "projectName": "Laba5.1", "args": "--populate", "envFile": "${workspaceFolder}/.env" } diff --git a/Laba5.1/src/main/java/com/example/demo/DemoApplication.java b/Laba5.1/src/main/java/com/example/demo/DemoApplication.java index 5566a90..db7fb26 100644 --- a/Laba5.1/src/main/java/com/example/demo/DemoApplication.java +++ b/Laba5.1/src/main/java/com/example/demo/DemoApplication.java @@ -11,12 +11,18 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import com.example.demo.core.configuration.Constants; +import com.example.demo.films.model.FilmEntity; +import com.example.demo.films.service.FilmService; +import com.example.demo.genres.model.GenreEntity; +import com.example.demo.genres.service.GenreService; import com.example.demo.orders.model.OrderEntity; import com.example.demo.orders.service.OrderService; import com.example.demo.subscriptions.model.SubscriptionEntity; import com.example.demo.subscriptions.service.SubscriptionService; import com.example.demo.types.model.TypeEntity; import com.example.demo.types.service.TypeService; +import com.example.demo.userfilms.model.UserfilmEntity; +import com.example.demo.userfilms.service.UserfilmService; import com.example.demo.users.model.UserEntity; import com.example.demo.users.model.UserRole; import com.example.demo.users.service.UserService; @@ -29,16 +35,25 @@ public class DemoApplication implements CommandLineRunner { private final SubscriptionService subscriptionService; private final UserService userService; private final OrderService orderService; + private final GenreService genreService; + private final FilmService filmService; + private final UserfilmService userfilmService; public DemoApplication( TypeService typeService, SubscriptionService subscriptionService, UserService userService, - OrderService orderService) { + OrderService orderService, + GenreService genreService, + FilmService filmService, + UserfilmService userfilmService) { this.typeService = typeService; this.subscriptionService = subscriptionService; this.userService = userService; this.orderService = orderService; + this.genreService = genreService; + this.filmService = filmService; + this.userfilmService = userfilmService; } public static void main(String[] args) { @@ -79,6 +94,21 @@ public class DemoApplication implements CommandLineRunner { new OrderEntity(type3, 75000.00, 6), new OrderEntity(type3, 67800.00, 3)); orders.forEach(order -> orderService.create(user1.getId(), order)); + + log.info("Create default genre values"); + final var genre1 = genreService.create(new GenreEntity("Comedy")); + final var genre2 = genreService.create(new GenreEntity("Triller")); + final var genre3 = genreService.create(new GenreEntity("Drama")); + + log.info("Create default film values"); + final var film1 = filmService.create(new FilmEntity(genre1, "Ivan Vasilevich menyaet proffessiu")); + final var film2 = filmService.create(new FilmEntity(genre2, "Ironia sudby")); + final var film3 = filmService.create(new FilmEntity(genre3, "S legkim parom")); + + log.info("Create default userfilm values"); + userfilmService.create(user1.getId(), new UserfilmEntity(film1)); + userfilmService.create(user1.getId(), new UserfilmEntity(film2)); + userfilmService.create(user1.getId(), new UserfilmEntity(film3)); } } } diff --git a/Laba5.1/src/main/java/com/example/demo/core/configuration/Constants.java b/Laba5.1/src/main/java/com/example/demo/core/configuration/Constants.java index 0bf6e30..1276c52 100644 --- a/Laba5.1/src/main/java/com/example/demo/core/configuration/Constants.java +++ b/Laba5.1/src/main/java/com/example/demo/core/configuration/Constants.java @@ -9,6 +9,8 @@ public class Constants { public static final String ADMIN_PREFIX = "/admin"; + public static final String USER_COOKIE = "userIdCookie"; + public static final String LOGIN_URL = "/login"; public static final String LOGOUT_URL = "/logout"; diff --git a/Laba5.1/src/main/java/com/example/demo/films/api/FilmController.java b/Laba5.1/src/main/java/com/example/demo/films/api/FilmController.java new file mode 100644 index 0000000..cdf5861 --- /dev/null +++ b/Laba5.1/src/main/java/com/example/demo/films/api/FilmController.java @@ -0,0 +1,104 @@ +package com.example.demo.films.api; + +import org.modelmapper.ModelMapper; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.GetMapping; +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.RequestMapping; + +import com.example.demo.core.configuration.Constants; +import com.example.demo.films.model.FilmEntity; +import com.example.demo.films.service.FilmService; + +import jakarta.validation.Valid; + +@Controller +@RequestMapping(FilmController.URL) +public class FilmController { + public static final String URL = Constants.ADMIN_PREFIX + "/film"; + private static final String FILM_VIEW = "film"; + private static final String FILM_EDIT_VIEW = "film-edit"; + private static final String FILM_ATTRIBUTE = "film"; + + private final FilmService filmService; + private final ModelMapper modelMapper; + + public FilmController(FilmService filmService, ModelMapper modelMapper) { + this.filmService = filmService; + this.modelMapper = modelMapper; + } + + private FilmDto toDto(FilmEntity entity) { + return modelMapper.map(entity, FilmDto.class); + } + + private FilmEntity toEntity(FilmDto dto) { + return modelMapper.map(dto, FilmEntity.class); + } + + @GetMapping + public String getAll(Model model) { + model.addAttribute( + "items", + filmService.getAll().stream() + .map(this::toDto) + .toList()); + return FILM_VIEW; + } + + @GetMapping("/edit/") + public String create(Model model) { + model.addAttribute(FILM_ATTRIBUTE, new FilmDto()); + return FILM_EDIT_VIEW; + } + + @PostMapping("/edit/") + public String create( + @ModelAttribute(name = FILM_ATTRIBUTE) @Valid FilmDto film, + BindingResult bindingResult, + Model model) { + if (bindingResult.hasErrors()) { + return FILM_EDIT_VIEW; + } + filmService.create(toEntity(film)); + return Constants.REDIRECT_VIEW + URL; + } + + @GetMapping("/edit/{id}") + public String update( + @PathVariable(name = "id") Long id, + Model model) { + if (id <= 0) { + throw new IllegalArgumentException(); + } + model.addAttribute(FILM_ATTRIBUTE, toDto(filmService.get(id))); + return FILM_EDIT_VIEW; + } + + @PostMapping("/edit/{id}") + public String update( + @PathVariable(name = "id") Long id, + @ModelAttribute(name = FILM_ATTRIBUTE) @Valid FilmDto film, + BindingResult bindingResult, + Model model) { + if (bindingResult.hasErrors()) { + return FILM_EDIT_VIEW; + } + if (id <= 0) { + throw new IllegalArgumentException(); + } + filmService.update(id, toEntity(film)); + return Constants.REDIRECT_VIEW + URL; + } + + @PostMapping("/delete/{id}") + public String delete( + @PathVariable(name = "id") Long id) { + filmService.delete(id); + return Constants.REDIRECT_VIEW + URL; + } +} diff --git a/Laba5.1/src/main/java/com/example/demo/films/api/FilmDto.java b/Laba5.1/src/main/java/com/example/demo/films/api/FilmDto.java new file mode 100644 index 0000000..4c1ae3f --- /dev/null +++ b/Laba5.1/src/main/java/com/example/demo/films/api/FilmDto.java @@ -0,0 +1,42 @@ +package com.example.demo.films.api; + +import groovyjarjarantlr4.v4.runtime.misc.NotNull; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; + +public class FilmDto { + private Long id; + @NotNull + @Min(1) + private String genreName; + @NotBlank + @Size(min = 5, max = 50) + private String name; + private String imageExtension; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getGenreName() { + return genreName; + } + + public void setGenreName(String genreName) { + this.genreName = genreName; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + +} diff --git a/Laba5.1/src/main/java/com/example/demo/films/model/FilmEntity.java b/Laba5.1/src/main/java/com/example/demo/films/model/FilmEntity.java new file mode 100644 index 0000000..2367ba7 --- /dev/null +++ b/Laba5.1/src/main/java/com/example/demo/films/model/FilmEntity.java @@ -0,0 +1,84 @@ +package com.example.demo.films.model; + +import java.util.Objects; + +import com.example.demo.core.model.BaseEntity; +import com.example.demo.genres.model.GenreEntity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.Lob; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; + +@Entity +@Table(name = "films") +public class FilmEntity extends BaseEntity { + @ManyToOne + @JoinColumn(name = "genreId", nullable = false) + private GenreEntity genre; + @Column(nullable = false, unique = true, length = 50) + private String name; + private String imageExtension; + @Lob + private byte[] image; + + public FilmEntity() { + } + + public FilmEntity(GenreEntity genre, String name) { + this.name = name; + this.genre = genre; + } + + public GenreEntity getGenre() { + return genre; + } + + public void setGenre(GenreEntity genre) { + this.genre = genre; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getImageExtension() { + return imageExtension; + } + + public void setImageExtension(String imageExtension) { + this.imageExtension = imageExtension; + } + + public byte[] getImage() { + return image; + } + + public void setImage(byte[] image) { + this.image = image; + } + + @Override + public int hashCode() { + return Objects.hash(id, genre, name); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null || getClass() != obj.getClass()) + return false; + final FilmEntity other = (FilmEntity) obj; + return Objects.equals(other.getId(), id) + && Objects.equals(other.getGenre(), genre) + && Objects.equals(other.getName(), name); + } + +} diff --git a/Laba5.1/src/main/java/com/example/demo/films/repository/FilmRepository.java b/Laba5.1/src/main/java/com/example/demo/films/repository/FilmRepository.java new file mode 100644 index 0000000..0c1d5e4 --- /dev/null +++ b/Laba5.1/src/main/java/com/example/demo/films/repository/FilmRepository.java @@ -0,0 +1,13 @@ +package com.example.demo.films.repository; + +import java.util.Optional; + +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.PagingAndSortingRepository; + +import com.example.demo.films.model.FilmEntity; + +public interface FilmRepository + extends CrudRepository, PagingAndSortingRepository { + Optional findByNameIgnoreCase(String name); +} diff --git a/Laba5.1/src/main/java/com/example/demo/films/service/FilmService.java b/Laba5.1/src/main/java/com/example/demo/films/service/FilmService.java new file mode 100644 index 0000000..036ae18 --- /dev/null +++ b/Laba5.1/src/main/java/com/example/demo/films/service/FilmService.java @@ -0,0 +1,78 @@ +package com.example.demo.films.service; + +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.stream.StreamSupport; + +import org.springframework.data.domain.Sort; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.example.demo.core.error.NotFoundException; +import com.example.demo.films.model.FilmEntity; +import com.example.demo.films.repository.FilmRepository; + +@Service +public class FilmService { + private final FilmRepository repository; + + public FilmService(FilmRepository repository) { + this.repository = repository; + } + + private void checkName(Long id, String name) { + final Optional existsFilm = repository.findByNameIgnoreCase(name); + if (existsFilm.isPresent() && !existsFilm.get().getId().equals(id)) { + throw new IllegalArgumentException( + String.format("Film with name %s is already exists", name)); + } + } + + @Transactional(readOnly = true) + public List getAll() { + return StreamSupport.stream(repository.findAll(Sort.by("id")).spliterator(), false).toList(); + } + + @Transactional(readOnly = true) + public List getByIds(Collection ids) { + final List films = StreamSupport.stream(repository.findAllById(ids).spliterator(), false).toList(); + if (films.size() < ids.size()) { + throw new IllegalArgumentException("Invalid film"); + } + return films; + } + + @Transactional(readOnly = true) + public FilmEntity get(long id) { + return repository.findById(id) + .orElseThrow(() -> new NotFoundException(FilmEntity.class, id)); + } + + @Transactional + public FilmEntity create(FilmEntity entity) { + if (entity == null) { + throw new IllegalArgumentException("Entity is null"); + } + checkName(null, entity.getName()); + return repository.save(entity); + } + + @Transactional + public FilmEntity update(Long id, FilmEntity entity) { + final FilmEntity existsEntity = get(id); + checkName(id, entity.getName()); + existsEntity.setName(entity.getName()); + existsEntity.setGenre(entity.getGenre()); + existsEntity.setImageExtension(entity.getImageExtension()); + existsEntity.setImage(entity.getImage()); + return repository.save(existsEntity); + } + + @Transactional + public FilmEntity delete(Long id) { + final FilmEntity existsEntity = get(id); + repository.delete(existsEntity); + return existsEntity; + } +} diff --git a/Laba5.1/src/main/java/com/example/demo/genres/api/GenreController.java b/Laba5.1/src/main/java/com/example/demo/genres/api/GenreController.java new file mode 100644 index 0000000..9b079a2 --- /dev/null +++ b/Laba5.1/src/main/java/com/example/demo/genres/api/GenreController.java @@ -0,0 +1,104 @@ +package com.example.demo.genres.api; + +import org.modelmapper.ModelMapper; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.GetMapping; +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.RequestMapping; + +import com.example.demo.core.configuration.Constants; +import com.example.demo.genres.model.GenreEntity; +import com.example.demo.genres.service.GenreService; + +import jakarta.validation.Valid; + +@Controller +@RequestMapping(GenreController.URL) +public class GenreController { + public static final String URL = Constants.ADMIN_PREFIX + "/genre"; + private static final String GENRE_VIEW = "genre"; + private static final String GENRE_EDIT_VIEW = "genre-edit"; + private static final String GENRE_ATTRIBUTE = "genre"; + + private final GenreService genreService; + private final ModelMapper modelMapper; + + public GenreController(GenreService genreService, ModelMapper modelMapper) { + this.genreService = genreService; + this.modelMapper = modelMapper; + } + + private GenreDto toDto(GenreEntity entity) { + return modelMapper.map(entity, GenreDto.class); + } + + private GenreEntity toEntity(GenreDto dto) { + return modelMapper.map(dto, GenreEntity.class); + } + + @GetMapping + public String getAll(Model model) { + model.addAttribute( + "items", + genreService.getAll().stream() + .map(this::toDto) + .toList()); + return GENRE_VIEW; + } + + @GetMapping("/edit/") + public String create(Model model) { + model.addAttribute(GENRE_ATTRIBUTE, new GenreDto()); + return GENRE_EDIT_VIEW; + } + + @PostMapping("/edit/") + public String create( + @ModelAttribute(name = GENRE_ATTRIBUTE) @Valid GenreDto genre, + BindingResult bindingResult, + Model model) { + if (bindingResult.hasErrors()) { + return GENRE_EDIT_VIEW; + } + genreService.create(toEntity(genre)); + return Constants.REDIRECT_VIEW + URL; + } + + @GetMapping("/edit/{id}") + public String update( + @PathVariable(name = "id") Long id, + Model model) { + if (id <= 0) { + throw new IllegalArgumentException(); + } + model.addAttribute(GENRE_ATTRIBUTE, toDto(genreService.get(id))); + return GENRE_EDIT_VIEW; + } + + @PostMapping("/edit/{id}") + public String update( + @PathVariable(name = "id") Long id, + @ModelAttribute(name = GENRE_ATTRIBUTE) @Valid GenreDto genre, + BindingResult bindingResult, + Model model) { + if (bindingResult.hasErrors()) { + return GENRE_EDIT_VIEW; + } + if (id <= 0) { + throw new IllegalArgumentException(); + } + genreService.update(id, toEntity(genre)); + return Constants.REDIRECT_VIEW + URL; + } + + @PostMapping("/delete/{id}") + public String delete( + @PathVariable(name = "id") Long id) { + genreService.delete(id); + return Constants.REDIRECT_VIEW + URL; + } +} diff --git a/Laba5.1/src/main/java/com/example/demo/genres/api/GenreDto.java b/Laba5.1/src/main/java/com/example/demo/genres/api/GenreDto.java new file mode 100644 index 0000000..5fc3218 --- /dev/null +++ b/Laba5.1/src/main/java/com/example/demo/genres/api/GenreDto.java @@ -0,0 +1,27 @@ +package com.example.demo.genres.api; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; + +public class GenreDto { + private Long id; + @NotBlank + @Size(min = 5, max = 50) + private String name; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/Laba5.1/src/main/java/com/example/demo/genres/model/GenreEntity.java b/Laba5.1/src/main/java/com/example/demo/genres/model/GenreEntity.java new file mode 100644 index 0000000..b36a926 --- /dev/null +++ b/Laba5.1/src/main/java/com/example/demo/genres/model/GenreEntity.java @@ -0,0 +1,48 @@ +package com.example.demo.genres.model; + +import java.util.Objects; + +import com.example.demo.core.model.BaseEntity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Table; + +@Entity +@Table(name = "genres") +public class GenreEntity extends BaseEntity { + @Column(nullable = false, unique = true, length = 50) + private String name; + + public GenreEntity() { + } + + public GenreEntity(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public int hashCode() { + return Objects.hash(id, name); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null || getClass() != obj.getClass()) + return false; + final GenreEntity other = (GenreEntity) obj; + return Objects.equals(other.getId(), id) + && Objects.equals(other.getName(), name); + } + +} diff --git a/Laba5.1/src/main/java/com/example/demo/genres/repository/GenreRepository.java b/Laba5.1/src/main/java/com/example/demo/genres/repository/GenreRepository.java new file mode 100644 index 0000000..292b1c4 --- /dev/null +++ b/Laba5.1/src/main/java/com/example/demo/genres/repository/GenreRepository.java @@ -0,0 +1,13 @@ +package com.example.demo.genres.repository; + +import java.util.Optional; + +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.PagingAndSortingRepository; + +import com.example.demo.genres.model.GenreEntity; + +public interface GenreRepository + extends CrudRepository, PagingAndSortingRepository { + Optional findByNameIgnoreCase(String name); +} diff --git a/Laba5.1/src/main/java/com/example/demo/genres/service/GenreService.java b/Laba5.1/src/main/java/com/example/demo/genres/service/GenreService.java new file mode 100644 index 0000000..9cc84ab --- /dev/null +++ b/Laba5.1/src/main/java/com/example/demo/genres/service/GenreService.java @@ -0,0 +1,76 @@ +package com.example.demo.genres.service; + +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.stream.StreamSupport; + +import org.springframework.data.domain.Sort; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.example.demo.core.error.NotFoundException; +import com.example.demo.genres.model.GenreEntity; +import com.example.demo.genres.repository.GenreRepository; + +@Service +public class GenreService { + private final GenreRepository repository; + + public GenreService(GenreRepository repository) { + this.repository = repository; + } + + private void checkName(Long id, String name) { + final Optional existsGenre = repository.findByNameIgnoreCase(name); + if (existsGenre.isPresent() && !existsGenre.get().getId().equals(id)) { + throw new IllegalArgumentException( + String.format("Genre with name %s is already exists", name)); + } + } + + @Transactional(readOnly = true) + public List getAll() { + return StreamSupport.stream(repository.findAll(Sort.by("id")).spliterator(), false).toList(); + } + + @Transactional(readOnly = true) + public List getByIds(Collection ids) { + final List genres = StreamSupport.stream(repository.findAllById(ids).spliterator(), false) + .toList(); + if (genres.size() < ids.size()) { + throw new IllegalArgumentException("Invalid genre"); + } + return genres; + } + + @Transactional(readOnly = true) + public GenreEntity get(long id) { + return repository.findById(id) + .orElseThrow(() -> new NotFoundException(GenreEntity.class, id)); + } + + @Transactional + public GenreEntity create(GenreEntity entity) { + if (entity == null) { + throw new IllegalArgumentException("Entity is null"); + } + checkName(null, entity.getName()); + return repository.save(entity); + } + + @Transactional + public GenreEntity update(Long id, GenreEntity entity) { + final GenreEntity existsEntity = get(id); + checkName(id, entity.getName()); + existsEntity.setName(entity.getName()); + return repository.save(existsEntity); + } + + @Transactional + public GenreEntity delete(Long id) { + final GenreEntity existsEntity = get(id); + repository.delete(existsEntity); + return existsEntity; + } +} diff --git a/Laba5.1/src/main/java/com/example/demo/userfilms/api/UserfilmDto.java b/Laba5.1/src/main/java/com/example/demo/userfilms/api/UserfilmDto.java new file mode 100644 index 0000000..12e3a54 --- /dev/null +++ b/Laba5.1/src/main/java/com/example/demo/userfilms/api/UserfilmDto.java @@ -0,0 +1,38 @@ +package com.example.demo.userfilms.api; + +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; + +public class UserfilmDto { + private Long id; + @NotNull + @Min(1) + private String filmName; + @NotNull + @Min(1) + private String genreName; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getFilmName() { + return filmName; + } + + public void setFilmName(String filmName) { + this.filmName = filmName; + } + + public String getGenreName() { + return genreName; + } + + public void setGenreName(String genreName) { + this.genreName = genreName; + } +} diff --git a/Laba5.1/src/main/java/com/example/demo/userfilms/api/UserfilmGroupedDto.java b/Laba5.1/src/main/java/com/example/demo/userfilms/api/UserfilmGroupedDto.java new file mode 100644 index 0000000..12f7701 --- /dev/null +++ b/Laba5.1/src/main/java/com/example/demo/userfilms/api/UserfilmGroupedDto.java @@ -0,0 +1,22 @@ +package com.example.demo.userfilms.api; + +public class UserfilmGroupedDto { + private Long filmCount; + private String genreName; + + public Long getfilmCount() { + return filmCount; + } + + public void setfilmCount(Long filmCount) { + this.filmCount = filmCount; + } + + public String getGenreName() { + return genreName; + } + + public void setGenreName(String genreName) { + this.genreName = genreName; + } +} diff --git a/Laba5.1/src/main/java/com/example/demo/userfilms/model/UserfilmEntity.java b/Laba5.1/src/main/java/com/example/demo/userfilms/model/UserfilmEntity.java new file mode 100644 index 0000000..68426a9 --- /dev/null +++ b/Laba5.1/src/main/java/com/example/demo/userfilms/model/UserfilmEntity.java @@ -0,0 +1,72 @@ +package com.example.demo.userfilms.model; + +import java.util.Objects; + +import com.example.demo.core.model.BaseEntity; +import com.example.demo.films.model.FilmEntity; +import com.example.demo.genres.model.GenreEntity; +import com.example.demo.users.model.UserEntity; + +import jakarta.persistence.Entity; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; + +@Entity +@Table(name = "userfilms") +public class UserfilmEntity extends BaseEntity { + @ManyToOne + @JoinColumn(name = "filmId", nullable = false) + private FilmEntity film; + @ManyToOne + @JoinColumn(name = "userId", nullable = false) + private UserEntity user; + @ManyToOne + @JoinColumn(name = "genreId", nullable = false) + private GenreEntity genre; + + public UserfilmEntity() { + } + + public UserfilmEntity(FilmEntity film) { + this.film = film; + this.genre = film.getGenre(); + } + + public GenreEntity getGenre() { + return film.getGenre(); + } + + public FilmEntity getFilm() { + return film; + } + + public void setFilm(FilmEntity film) { + this.film = film; + } + + public UserEntity getUser() { + return user; + } + + public void setUser(UserEntity user) { + this.user = user; + } + + @Override + public int hashCode() { + return Objects.hash(id, film, user.getId()); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null || getClass() != obj.getClass()) + return false; + final UserfilmEntity other = (UserfilmEntity) obj; + return Objects.equals(other.getId(), id) + && Objects.equals(other.getFilm(), film) + && Objects.equals(other.getUser().getId(), user.getId()); + } +} diff --git a/Laba5.1/src/main/java/com/example/demo/userfilms/model/UserfilmGrouped.java b/Laba5.1/src/main/java/com/example/demo/userfilms/model/UserfilmGrouped.java new file mode 100644 index 0000000..771c61d --- /dev/null +++ b/Laba5.1/src/main/java/com/example/demo/userfilms/model/UserfilmGrouped.java @@ -0,0 +1,9 @@ +package com.example.demo.userfilms.model; + +import com.example.demo.genres.model.GenreEntity; + +public interface UserfilmGrouped { + Long getCount(); + + GenreEntity getGenre(); +} diff --git a/Laba5.1/src/main/java/com/example/demo/userfilms/repository/UserfilmRepository.java b/Laba5.1/src/main/java/com/example/demo/userfilms/repository/UserfilmRepository.java new file mode 100644 index 0000000..e2e3129 --- /dev/null +++ b/Laba5.1/src/main/java/com/example/demo/userfilms/repository/UserfilmRepository.java @@ -0,0 +1,38 @@ +package com.example.demo.userfilms.repository; + +import java.util.List; +import java.util.Optional; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.PagingAndSortingRepository; + +import com.example.demo.userfilms.model.UserfilmEntity; +import com.example.demo.userfilms.model.UserfilmGrouped; + +public interface UserfilmRepository + extends CrudRepository, PagingAndSortingRepository { + + Optional findOneByUserIdAndId(long userId, long id); + + List findByUserId(long userId); + + Page findByUserId(long userId, Pageable pageable); + + List findByUserIdAndGenreId(long userId, long genreId); + + Page findByUserIdAndGenreId(long userId, long genreId, Pageable pageable); + + @Query("select " + + "count(*) as count, " + + "g as genre " + + "from FilmEntity f " + + "left join GenreEntity g " + + "on f.genre = g " + + "right join UserfilmEntity uf " + + "on uf.film = f and uf.user.id = ?1 " + + "group by g order by g.name") + List getFilmsTotalByGenre(long userId); +} diff --git a/Laba5.1/src/main/java/com/example/demo/userfilms/service/UserfilmService.java b/Laba5.1/src/main/java/com/example/demo/userfilms/service/UserfilmService.java new file mode 100644 index 0000000..c9024cf --- /dev/null +++ b/Laba5.1/src/main/java/com/example/demo/userfilms/service/UserfilmService.java @@ -0,0 +1,105 @@ +package com.example.demo.userfilms.service; + +import java.util.List; +import java.util.stream.StreamSupport; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.example.demo.core.error.NotFoundException; +import com.example.demo.userfilms.model.UserfilmEntity; +import com.example.demo.userfilms.model.UserfilmGrouped; +import com.example.demo.userfilms.repository.UserfilmRepository; +import com.example.demo.users.model.UserEntity; +import com.example.demo.users.service.UserService; + +@Service +public class UserfilmService { + private final UserfilmRepository repository; + private final UserService userService; + + public UserfilmService(UserfilmRepository repository, UserService userService) { + this.repository = repository; + this.userService = userService; + } + + @Transactional(readOnly = true) + public List getAll(long userId, long genreId) { + userService.get(userId); + if (genreId <= 0L) { + return repository.findByUserId(userId); + } else { + return repository.findByUserIdAndGenreId(userId, genreId); + } + } + + @Transactional(readOnly = true) + public List getAll(long userId) { + userService.get(userId); + return repository.findByUserId(userId); + } + + @Transactional(readOnly = true) + public Page getAll(long userId, long genreId, int page, int size) { + final Pageable pageable = PageRequest.of(page, size, Sort.by("id")); + userService.get(userId); + if (genreId <= 0L) { + return repository.findByUserId(userId, pageable); + } else { + return repository.findByUserIdAndGenreId(userId, genreId, pageable); + } + } + + @Transactional(readOnly = true) + public UserfilmEntity get(long userId, long id) { + userService.get(userId); + return repository.findOneByUserIdAndId(userId, id) + .orElseThrow(() -> new NotFoundException(UserfilmEntity.class, id)); + } + + @Transactional + public UserfilmEntity create(long userId, UserfilmEntity entity) { + if (entity == null) { + throw new IllegalArgumentException("Entity is null"); + } + final UserEntity existsUser = userService.get(userId); + entity.setUser(existsUser); + return repository.save(entity); + } + + @Transactional + public List createAll(long userId, List entities) { + if (entities == null || entities.isEmpty()) { + throw new IllegalArgumentException("Userfilms list is null or empty"); + } + final UserEntity existsUser = userService.get(userId); + entities.forEach(entity -> entity.setUser(existsUser)); + return StreamSupport.stream(repository.saveAll(entities).spliterator(), false).toList(); + } + + @Transactional + public UserfilmEntity update(long userId, long id, UserfilmEntity entity) { + userService.get(userId); + final UserfilmEntity existsEntity = get(userId, id); + existsEntity.setFilm(entity.getFilm()); + return repository.save(existsEntity); + } + + @Transactional + public UserfilmEntity delete(long userId, long id) { + userService.get(userId); + final UserfilmEntity existsEntity = get(userId, id); + repository.delete(existsEntity); + return existsEntity; + } + + @Transactional(readOnly = true) + public List getTotal(long userId) { + userService.get(userId); + return repository.getFilmsTotalByGenre(userId); + } +} diff --git a/Laba5.1/src/main/java/com/example/demo/users/api/UserCabinetController.java b/Laba5.1/src/main/java/com/example/demo/users/api/UserCabinetController.java new file mode 100644 index 0000000..8fd239d --- /dev/null +++ b/Laba5.1/src/main/java/com/example/demo/users/api/UserCabinetController.java @@ -0,0 +1,108 @@ +package com.example.demo.users.api; + +import java.util.stream.Collectors; + +import org.modelmapper.ModelMapper; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.CookieValue; +import org.springframework.web.bind.annotation.GetMapping; +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.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.servlet.mvc.support.RedirectAttributes; + +import com.example.demo.core.api.PageAttributesMapper; +import com.example.demo.core.configuration.Constants; +import com.example.demo.core.security.UserPrincipal; +import com.example.demo.films.service.FilmService; +import com.example.demo.genres.api.GenreDto; +import com.example.demo.genres.model.GenreEntity; +import com.example.demo.genres.service.GenreService; +import com.example.demo.userfilms.api.UserfilmDto; +import com.example.demo.userfilms.api.UserfilmGroupedDto; +import com.example.demo.userfilms.model.UserfilmEntity; +import com.example.demo.userfilms.model.UserfilmGrouped; +import com.example.demo.userfilms.service.UserfilmService; +import com.example.demo.users.model.UserSubscriptionWithStatus; +import com.example.demo.users.service.UserService; + +import jakarta.validation.Valid; + +@Controller +@RequestMapping("/cabinet") +public class UserCabinetController { + + private static final String PROFILE_VIEW = "cabinet"; + + private static final String PAGE_ATTRIBUTE = "page"; + private static final String GENREID_ATTRIBUTE = "genreId"; + private static final String PROFILE_ATTRIBUTE = "profile"; + + private final UserfilmService userfilmService; + private final GenreService genreService; + private final FilmService filmService; + private final UserService userService; + private final ModelMapper modelMapper; + + public UserCabinetController( + UserfilmService userfilmService, + GenreService genreService, + FilmService filmService, + UserService userService, + ModelMapper modelMapper) { + this.userfilmService = userfilmService; + this.genreService = genreService; + this.filmService = filmService; + this.userService = userService; + this.modelMapper = modelMapper; + } + + private GenreDto toGenreDto(GenreEntity entity) { + return modelMapper.map(entity, GenreDto.class); + } + + private UserfilmDto toUserfilmDto(UserfilmEntity entity) { + return modelMapper.map(entity, UserfilmDto.class); + } + + private UserfilmGroupedDto toUserfilmGroupedDto(UserfilmGrouped entity) { + return modelMapper.map(entity, UserfilmGroupedDto.class); + } + + @GetMapping() + public String getProfile( + @RequestParam(name = PAGE_ATTRIBUTE, defaultValue = "0") int page, + @RequestParam(name = GENREID_ATTRIBUTE, defaultValue = "0") int genreId, + Model model, + @AuthenticationPrincipal UserPrincipal principal) { + final long userId = principal.getId(); + model.addAttribute(PAGE_ATTRIBUTE, page); + model.addAttribute(GENREID_ATTRIBUTE, genreId); + model.addAllAttributes(PageAttributesMapper.toAttributes( + userfilmService.getAll(userId, genreId, page, Constants.DEFUALT_PAGE_SIZE), + this::toUserfilmDto)); + model.addAttribute("genres", + genreService.getAll().stream() + .map(this::toGenreDto) + .toList()); + return PROFILE_VIEW; + } + + @PostMapping("/delete/{id}") + public String deleteUserfilm( + @PathVariable(name = "id") Long id, + @RequestParam(name = PAGE_ATTRIBUTE, defaultValue = "0") int page, + @RequestParam(name = GENREID_ATTRIBUTE, defaultValue = "0") int genreId, + RedirectAttributes redirectAttributes, + @AuthenticationPrincipal UserPrincipal principal) { + redirectAttributes.addAttribute(PAGE_ATTRIBUTE, page); + redirectAttributes.addAttribute(GENREID_ATTRIBUTE, genreId); + userfilmService.delete(principal.getId(), id); + return Constants.REDIRECT_VIEW + "/cabinet"; + } +} diff --git a/Laba5.1/src/main/resources/templates/cabinet.html b/Laba5.1/src/main/resources/templates/cabinet.html new file mode 100644 index 0000000..f448ed6 --- /dev/null +++ b/Laba5.1/src/main/resources/templates/cabinet.html @@ -0,0 +1,46 @@ + + + + + Личный кабинет + + + +
+ + +
+
+ +
+
+
    +
  • + [[${userfilm.filmName}]] : [[${userfilm.genreName}]] + +
  • +
+
+
+ +
+ + + \ No newline at end of file diff --git a/Laba5.1/src/main/resources/templates/default.html b/Laba5.1/src/main/resources/templates/default.html index 103729e..43a3894 100644 --- a/Laba5.1/src/main/resources/templates/default.html +++ b/Laba5.1/src/main/resources/templates/default.html @@ -38,6 +38,14 @@ th:classappend="${activeLink.startsWith('/admin/type') ? 'active' : ''}"> Типы заказов + + Жанры фильмов + + + Фильмы + Списки рассылки @@ -73,7 +81,7 @@
- +
diff --git a/Laba5.1/src/main/resources/templates/film-edit.html b/Laba5.1/src/main/resources/templates/film-edit.html new file mode 100644 index 0000000..65d4fdc --- /dev/null +++ b/Laba5.1/src/main/resources/templates/film-edit.html @@ -0,0 +1,36 @@ + + + + + Редакторовать фильм + + + +
+
+
+ + +
+
+ + +
+
+
+ + +
+
+
+
+
+ + + \ No newline at end of file diff --git a/Laba5.1/src/main/resources/templates/film.html b/Laba5.1/src/main/resources/templates/film.html new file mode 100644 index 0000000..e1acd02 --- /dev/null +++ b/Laba5.1/src/main/resources/templates/film.html @@ -0,0 +1,50 @@ + + + + + Фильмы + + + +
+ +

Данные отсутствуют

+ +

Фильмы

+ + + + + + + + + + + + + + + + + + + +
IDФильм
+
+ +
+
+
+ +
+
+
+
+
+ + + \ No newline at end of file diff --git a/Laba5.1/src/main/resources/templates/genre-edit.html b/Laba5.1/src/main/resources/templates/genre-edit.html new file mode 100644 index 0000000..9081d00 --- /dev/null +++ b/Laba5.1/src/main/resources/templates/genre-edit.html @@ -0,0 +1,28 @@ + + + + + Редакторовать тип заказа + + + +
+
+
+ + +
+
+ + +
+
+
+ + Отмена +
+
+
+ + + \ No newline at end of file diff --git a/Laba5.1/src/main/resources/templates/genre.html b/Laba5.1/src/main/resources/templates/genre.html new file mode 100644 index 0000000..fd25c7f --- /dev/null +++ b/Laba5.1/src/main/resources/templates/genre.html @@ -0,0 +1,50 @@ + + + + + Жанры фильмов + + + +
+ +

Данные отсутствуют

+ +

Жанры фильмов

+ + + + + + + + + + + + + + + + + + + +
IDЖанр фильма
+
+ +
+
+
+ +
+
+
+
+
+ + + \ No newline at end of file diff --git a/Laba5.1/src/main/resources/templates/userfilms.html b/Laba5.1/src/main/resources/templates/userfilms.html new file mode 100644 index 0000000..fc88c22 --- /dev/null +++ b/Laba5.1/src/main/resources/templates/userfilms.html @@ -0,0 +1,70 @@ + + + + + + +

Данные отсутствуют

+ +
+
+ + +
+ +
+ + + + + + + + + +
+
    +
  • + [[${userfilm.filmName}]] : [[${userfilm.genreName}]] +
    + + + + +
  • +
+
+ + + + + + + + +
IDТип заказа
+
+ + + +
+
+
+ + +
+ + + + \ No newline at end of file