diff --git a/src/main/java/np/something/DTO/AlbumDto.java b/src/main/java/np/something/DTO/AlbumDto.java new file mode 100644 index 0000000..e0525d1 --- /dev/null +++ b/src/main/java/np/something/DTO/AlbumDto.java @@ -0,0 +1,58 @@ +package np.something.DTO; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonProperty; +import np.something.model.Album; +import np.something.model.Photo; + +import javax.validation.constraints.Size; + +public class AlbumDto { + private Long id; + @Size(min=3, max=32, message="Album's name's size must be from 3 to 32 letters") + private String name; + private Long ownerId; + private String ownerName; + private List photos; + + + public AlbumDto() { + } + + public AlbumDto(Album album) { + this.id = album.getId(); + this.name = album.getName(); + this.ownerId = album.getOwner().getId(); + this.ownerName = album.getOwner().getUsername(); + this.photos = album.getPhotos().stream().map(PhotoDto::new).toList(); + } + + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + public Long getOwnerId() { + return ownerId; + } + + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + public String getOwnerName() { + return ownerName; + } + + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + public List getPhotos() { + return photos; + } +} diff --git a/src/main/java/np/something/DTO/CommentDto.java b/src/main/java/np/something/DTO/CommentDto.java deleted file mode 100644 index 82016da..0000000 --- a/src/main/java/np/something/DTO/CommentDto.java +++ /dev/null @@ -1,101 +0,0 @@ -package np.something.DTO; - -import np.something.model.Comment; - -import com.fasterxml.jackson.annotation.JsonProperty; -import java.time.format.DateTimeFormatter; - -public class CommentDto { - public long id; - public String content; - public long customerId; - public String customerName; - public long postId; - public String postTitle; - public String postAuthor; - public long postAuthorId; - public String createDate; - - public CommentDto() { - - } - - public CommentDto(Comment comment) { - this.id = comment.getId(); - this.content = comment.getContent(); - this.customerId = comment.getCustomer().getId(); - this.customerName = comment.getCustomer().getUsername(); - this.postId = comment.getPost().getId(); - this.postTitle = comment.getPost().getTitle(); - this.postAuthor = comment.getPost().getCustomer().getUsername(); - this.postAuthorId = comment.getPost().getCustomer().getId(); - this.createDate = comment.getCreateDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); - } - - @JsonProperty(access = JsonProperty.Access.READ_ONLY) - public long getId() { - return id; - } - - public String getContent() { - return content; - } - - public void setContent(String content) { - this.content = content; - } - - public long getCustomerId() { - return customerId; - } - - public void setCustomerId(long customerId) { - this.customerId = customerId; - } - - @JsonProperty(access = JsonProperty.Access.READ_ONLY) - public String getCustomerName() { - return customerName; - } - - public long getPostId() { - return postId; - } - - public void setPostId(long postId) { - this.postId = postId; - } - - @JsonProperty(access = JsonProperty.Access.READ_ONLY) - public String getPostTitle() {return postTitle;} - - @JsonProperty(access = JsonProperty.Access.READ_ONLY) - public String getPostAuthor() { - return postAuthor; - } - - @JsonProperty(access = JsonProperty.Access.READ_ONLY) - public long getPostAuthorId() { - return postAuthorId; - } - - @JsonProperty(access = JsonProperty.Access.READ_ONLY) - public String getCreateDate() { - return createDate; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - CommentDto that = (CommentDto) o; - - return id == that.id; - } - - @Override - public int hashCode() { - return (int) (id ^ (id >>> 32)); - } -} diff --git a/src/main/java/np/something/DTO/CustomerDto.java b/src/main/java/np/something/DTO/CustomerDto.java index 0ad8ebf..1616726 100644 --- a/src/main/java/np/something/DTO/CustomerDto.java +++ b/src/main/java/np/something/DTO/CustomerDto.java @@ -1,35 +1,35 @@ package np.something.DTO; -import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; import np.something.model.Customer; -import java.io.Serializable; -import java.util.List; +import javax.validation.constraints.Size; public class CustomerDto { - public long id; - public String username; - public String password; - public List comments; - public List posts; - - public CustomerDto() { - - } + private Long id; + @Size(min=3, max=32, message="Username string length must be from 3 to 32 letters") + private String username; + private List ownedAlbums; + private List albums; public CustomerDto(Customer customer) { this.id = customer.getId(); this.username = customer.getUsername(); - this.password = customer.getPassword(); - this.comments = customer.getComments().stream().map(CommentDto::new).toList(); - this.posts = customer.getPosts().stream().map(PostDto::new).toList(); + this.ownedAlbums = customer.getOwnedAlbums().stream().map(AlbumDto::new).toList(); + this.albums = customer.getAlbums().stream().map(AlbumDto::new).toList(); } - @JsonProperty(access = JsonProperty.Access.READ_ONLY) - public long getId() { + public CustomerDto() { + } + + public Long getId() { return id; } + public void setId(Long id) { + this.id = id; + } + public String getUsername() { return username; } @@ -38,21 +38,19 @@ public class CustomerDto { this.username = username; } - public String getPassword() { - return password; + public List getOwnedAlbums() { + return ownedAlbums; } - public void setPassword(String password) { - this.password = password; + public void setOwnedAlbums(List ownedAlbums) { + this.ownedAlbums = ownedAlbums; } - @JsonProperty(access = JsonProperty.Access.READ_ONLY) - public List getComments() { - return comments; + public List getAlbums() { + return albums; } - @JsonProperty(access = JsonProperty.Access.READ_ONLY) - public List getPosts() { - return posts; + public void setAlbums(List albums) { + this.albums = albums; } } diff --git a/src/main/java/np/something/DTO/PhotoDto.java b/src/main/java/np/something/DTO/PhotoDto.java new file mode 100644 index 0000000..f8642e4 --- /dev/null +++ b/src/main/java/np/something/DTO/PhotoDto.java @@ -0,0 +1,37 @@ +package np.something.DTO; + +import np.something.model.Photo; + +import java.util.List; + +public class PhotoDto { + private Long id; + private List tags; + private Long albumId; + + public PhotoDto() { + + } + + public PhotoDto(Photo photo) { + this.id = photo.getId(); + this.tags = photo.getTags().stream().map(TagDto::new).toList(); + this.albumId = photo.getAlbum().getId(); + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public List getTags() { + return tags; + } + + public void setTags(List tags) { + this.tags = tags; + } +} diff --git a/src/main/java/np/something/DTO/PostDto.java b/src/main/java/np/something/DTO/PostDto.java deleted file mode 100644 index 9c6d146..0000000 --- a/src/main/java/np/something/DTO/PostDto.java +++ /dev/null @@ -1,77 +0,0 @@ -package np.something.DTO; - -import com.fasterxml.jackson.annotation.JsonProperty; -import np.something.model.Post; - -import java.time.format.DateTimeFormatter; -import java.util.ArrayList; -import java.util.List; - -public class PostDto { - public long id; - public String title; - public String content; - public String customerName; - public long customerId; - public ArrayList comments; - - public String createDate; - - public PostDto() { - - } - - public PostDto(Post post) { - this.id = post.getId(); - this.title = post.getTitle(); - this.content = post.getContent(); - this.customerName = post.getCustomer().getUsername(); - this.customerId = post.getCustomer().getId(); - this.comments = new ArrayList<>(post.getComments().stream().map(CommentDto::new).toList()); - this.createDate = post.getCreateDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); - } - - @JsonProperty(access = JsonProperty.Access.READ_ONLY) - public long getId() { - return id; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public String getContent() { - return content; - } - - public void setContent(String content) { - this.content = content; - } - - @JsonProperty(access = JsonProperty.Access.READ_ONLY) - public String getCustomerName() { - return customerName; - } - - @JsonProperty(access = JsonProperty.Access.READ_ONLY) - public List getComments() { - return comments; - } - - public long getCustomerId() { - return customerId; - } - - public void setCustomerId(long customerId) { - this.customerId = customerId; - } - - @JsonProperty(access = JsonProperty.Access.READ_ONLY) - public String getCreateDate() { - return createDate; - } -} diff --git a/src/main/java/np/something/DTO/TagDto.java b/src/main/java/np/something/DTO/TagDto.java new file mode 100644 index 0000000..b7f701b --- /dev/null +++ b/src/main/java/np/something/DTO/TagDto.java @@ -0,0 +1,35 @@ +package np.something.DTO; + +import com.fasterxml.jackson.annotation.JsonProperty; +import np.something.model.Tag; + +import javax.validation.constraints.Size; +import java.util.List; + +public class TagDto { + private Long id; + @Size(min=3, max=32, message="Tag's name must be from 3 to 32 letters") + private String name; + + public TagDto() { + + } + + public TagDto(Tag tag) { + this.id = tag.getId(); + this.name = tag.getName(); + } + + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/src/main/java/np/something/Exceptions/AlbumNotFoundException.java b/src/main/java/np/something/Exceptions/AlbumNotFoundException.java new file mode 100644 index 0000000..c972cff --- /dev/null +++ b/src/main/java/np/something/Exceptions/AlbumNotFoundException.java @@ -0,0 +1,7 @@ +package np.something.Exceptions; + +public class AlbumNotFoundException extends RuntimeException { + public AlbumNotFoundException(Long id) { + super(String.format("Album with id [%s] is not found", id)); + } +} \ No newline at end of file diff --git a/src/main/java/np/something/Exceptions/CommentNotFoundException.java b/src/main/java/np/something/Exceptions/CommentNotFoundException.java deleted file mode 100644 index 1dd2e80..0000000 --- a/src/main/java/np/something/Exceptions/CommentNotFoundException.java +++ /dev/null @@ -1,7 +0,0 @@ -package np.something.Exceptions; - -public class CommentNotFoundException extends RuntimeException { - public CommentNotFoundException(Long id) { - super(String.format("Comment with id [%s] is not found", id)); - } -} diff --git a/src/main/java/np/something/Exceptions/CustomerNotFoundException.java b/src/main/java/np/something/Exceptions/CustomerNotFoundException.java index 8d37c34..ff8ef31 100644 --- a/src/main/java/np/something/Exceptions/CustomerNotFoundException.java +++ b/src/main/java/np/something/Exceptions/CustomerNotFoundException.java @@ -4,4 +4,4 @@ public class CustomerNotFoundException extends RuntimeException { public CustomerNotFoundException(Long id) { super(String.format("Customer with id [%s] is not found", id)); } -} +} \ No newline at end of file diff --git a/src/main/java/np/something/Exceptions/JwtException.java b/src/main/java/np/something/Exceptions/JwtException.java deleted file mode 100644 index 5d55c1e..0000000 --- a/src/main/java/np/something/Exceptions/JwtException.java +++ /dev/null @@ -1,11 +0,0 @@ -package np.something.Exceptions; - -public class JwtException extends RuntimeException { - public JwtException(Throwable throwable) { - super(throwable); - } - - public JwtException(String message) { - super(message); - } -} diff --git a/src/main/java/np/something/Exceptions/PostNotFoundException.java b/src/main/java/np/something/Exceptions/PostNotFoundException.java deleted file mode 100644 index 5c08388..0000000 --- a/src/main/java/np/something/Exceptions/PostNotFoundException.java +++ /dev/null @@ -1,7 +0,0 @@ -package np.something.Exceptions; - -public class PostNotFoundException extends RuntimeException { - public PostNotFoundException(Long id) { - super(String.format("Post with id [%s] is not found", id)); - } -} diff --git a/src/main/java/np/something/OpenAPI30Configuration.java b/src/main/java/np/something/OpenAPI30Configuration.java deleted file mode 100644 index 26bb817..0000000 --- a/src/main/java/np/something/OpenAPI30Configuration.java +++ /dev/null @@ -1,28 +0,0 @@ -package np.something; - -import io.swagger.v3.oas.models.Components; -import io.swagger.v3.oas.models.OpenAPI; -import io.swagger.v3.oas.models.security.SecurityRequirement; -import io.swagger.v3.oas.models.security.SecurityScheme; -import np.something.security.JwtFilter; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration -public class OpenAPI30Configuration { - public static final String API_PREFIX = "/api/1.0"; - - @Bean - public OpenAPI customizeOpenAPI() { - final String securitySchemeName = JwtFilter.TOKEN_BEGIN_STR; - return new OpenAPI() - .addSecurityItem(new SecurityRequirement() - .addList(securitySchemeName)) - .components(new Components() - .addSecuritySchemes(securitySchemeName, new SecurityScheme() - .name(securitySchemeName) - .type(SecurityScheme.Type.HTTP) - .scheme("bearer") - .bearerFormat("JWT"))); - } -} diff --git a/src/main/java/np/something/WebConfiguration.java b/src/main/java/np/something/WebConfiguration.java index 8f62a14..c764c88 100644 --- a/src/main/java/np/something/WebConfiguration.java +++ b/src/main/java/np/something/WebConfiguration.java @@ -13,13 +13,11 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebConfiguration implements WebMvcConfigurer { - public static final String REST_API = OpenAPI30Configuration.API_PREFIX; @Override public void addViewControllers(ViewControllerRegistry registry) { WebMvcConfigurer.super.addViewControllers(registry); registry.addViewController("login"); - registry.addViewController(SecurityConfiguration.SPA_URL_MASK).setViewName("forward:/"); registry.addViewController("/notFound").setViewName("forward:/"); } diff --git a/src/main/java/np/something/controllers/CommentController.java b/src/main/java/np/something/controllers/CommentController.java deleted file mode 100644 index 4064fae..0000000 --- a/src/main/java/np/something/controllers/CommentController.java +++ /dev/null @@ -1,61 +0,0 @@ -package np.something.controllers; - -import javax.validation.Valid; -import np.something.DTO.CommentDto; -import np.something.WebConfiguration; -import np.something.model.Comment; -import np.something.services.*; -import org.springframework.web.bind.annotation.*; - -import java.util.List; - -@RestController -@RequestMapping(WebConfiguration.REST_API + "/comment") -public class CommentController { - private final CommentService commentService; - private final CustomerService customerService; - private final PostService postService; - - public CommentController(CommentService commentService, CustomerService customerService, PostService postService) { - this.commentService = commentService; - this.customerService = customerService; - this.postService = postService; - } - - @GetMapping("/{id}") - public CommentDto getComment(@PathVariable Long id) { - return new CommentDto(commentService.findComment(id)); - } - - @GetMapping - public List getComments() { - return commentService.findAllComments().stream() - .map(CommentDto::new) - .toList(); - } - - @PostMapping - public CommentDto createComment(@RequestBody @Valid CommentDto commentDto){ - final Comment comment = commentService.addComment( - customerService.findCustomer(commentDto.getCustomerId()), - postService.findPost(commentDto.getPostId()), - commentDto.getContent() - ); - return new CommentDto(comment); - } - - @PutMapping("/{id}") - public CommentDto updateComment(@RequestBody @Valid CommentDto commentDto, @PathVariable Long id) { - return new CommentDto(commentService.updateComment(id, commentDto.getContent())); - } - - @DeleteMapping("/{id}") - public CommentDto deleteComment(@PathVariable Long id) { - return new CommentDto(commentService.deleteComment(id)); - } - - @DeleteMapping - public void deleteAllComments(){ - commentService.deleteAllComments(); - } -} diff --git a/src/main/java/np/something/controllers/CustomerController.java b/src/main/java/np/something/controllers/CustomerController.java deleted file mode 100644 index fc34436..0000000 --- a/src/main/java/np/something/controllers/CustomerController.java +++ /dev/null @@ -1,82 +0,0 @@ -package np.something.controllers; - -import javax.validation.Valid; -import np.something.DTO.CustomerDto; -import np.something.WebConfiguration; -import np.something.model.Customer; -import np.something.services.*; -import org.springframework.http.HttpHeaders; -import org.springframework.web.bind.annotation.*; - -import java.util.List; - -@RestController -@RequestMapping(WebConfiguration.REST_API + "/customer") -public class CustomerController { - public static final String URL_LOGIN = "/jwt/login"; - private final CustomerService customerService; - - public CustomerController(CustomerService customerService) { - this.customerService = customerService; - } - - @GetMapping("/{id}") - public CustomerDto getCustomer(@PathVariable Long id) { - return new CustomerDto(customerService.findCustomer(id)); - } - - @GetMapping - public List getCustomers() { - return customerService.findAllCustomers().stream() - .map(CustomerDto::new) - .toList(); - } - - @PostMapping - public CustomerDto createCustomer(@RequestBody @Valid CustomerDto customerDto){ - final Customer customer = customerService.addCustomer(customerDto.getUsername(), customerDto.getPassword()); - return new CustomerDto(customer); - } - - @PutMapping("/{id}") - public CustomerDto updateCustomer(@RequestBody @Valid CustomerDto customerDto, @PathVariable Long id) { - return new CustomerDto(customerService.updateCustomer(id, customerDto.getUsername(), customerDto.getPassword())); - } - - @DeleteMapping("/{id}") - public CustomerDto deleteCustomer(@PathVariable Long id) { - return new CustomerDto(customerService.deleteCustomer(id)); - } - - @DeleteMapping - public void deleteAllCustomers(){ - customerService.deleteAllCustomers(); - } - - @GetMapping("/find/{username}") - public CustomerDto getCustomerByUsername(@PathVariable String username) { - return new CustomerDto(customerService.findByUsername(username)); - } - - @PostMapping(URL_LOGIN) - public String login(@RequestBody @Valid CustomerDto customerDto) { - return customerService.loginAndGetToken(customerDto); - } - - @GetMapping ("/me") - CustomerDto getCurrentCustomer(@RequestHeader(HttpHeaders.AUTHORIZATION) String token) { - return new CustomerDto(customerService.findByUsername(customerService.loadUserByToken(token.substring(7)).getUsername())); - } - - @GetMapping("role/{token}") - public String getRoleByToken(@PathVariable String token) { - var userDetails = customerService.loadUserByToken(token); - Customer customer = customerService.findByUsername(userDetails.getUsername()); - - if (customer != null) { - return customer.getRole().toString(); - } - - return null; - } -} diff --git a/src/main/java/np/something/controllers/PostController.java b/src/main/java/np/something/controllers/PostController.java deleted file mode 100644 index 3158edc..0000000 --- a/src/main/java/np/something/controllers/PostController.java +++ /dev/null @@ -1,66 +0,0 @@ -package np.something.controllers; - -import javax.validation.Valid; -import np.something.DTO.PostDto; -import np.something.WebConfiguration; -import np.something.services.CustomerService; -import np.something.services.PostService; -import org.springframework.web.bind.annotation.*; -import java.util.List; - -@RestController -@RequestMapping(WebConfiguration.REST_API + "/post") -public class PostController { - private final PostService postService; - private final CustomerService customerService; - - public PostController(PostService postService, CustomerService customerService) { - this.postService = postService; - this.customerService = customerService; - } - - @GetMapping("/{id}") - public PostDto getPost(@PathVariable Long id) { - return new PostDto(postService.findPost(id)); - } - - @GetMapping - public List getPosts() { - return postService.findAllPosts().stream() - .map(PostDto::new) - .toList(); - } - - @PostMapping - public PostDto createPost(@RequestBody @Valid PostDto postDto) - { - return new PostDto(postService.addPost(customerService.findCustomer(postDto.getCustomerId()), postDto.getTitle(), postDto.getContent())); - } - - @PutMapping("/{id}") - public PostDto updatePost(@RequestBody @Valid PostDto postDto, @PathVariable Long id) - { - return new PostDto(postService.updatePost(id, postDto.title, postDto.content)); - } - - @DeleteMapping("/{id}") - public PostDto deletePost (@PathVariable Long id) { - return new PostDto(postService.deletePost(id)); - } - - @DeleteMapping - public void deleteAllPosts() { - postService.deleteAllPosts(); - } - - @GetMapping("/search") - public List searchPosts(@RequestParam(required = false) String query) { - if (query == null || query.isBlank()) { - return postService.findAllPosts().stream() - .map(PostDto::new) - .toList(); - } else { - return postService.searchPosts(query); - } - } -} \ No newline at end of file diff --git a/src/main/java/np/something/model/Album.java b/src/main/java/np/something/model/Album.java new file mode 100644 index 0000000..bcccb43 --- /dev/null +++ b/src/main/java/np/something/model/Album.java @@ -0,0 +1,94 @@ +package np.something.model; + +import javax.persistence.*; +import javax.validation.constraints.Size; +import java.util.*; + +@Entity +public class Album { + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + + @Column + @Size(min=3, max=32, message="Album's name's size must be from 3 to 32 letters") + private String name; + + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "owner_fk") + private Customer owner; + + @ManyToMany(fetch = FetchType.EAGER) + @JoinTable(name = "albums_customers", + joinColumns = { + @JoinColumn(name = "album_id", referencedColumnName = "id", + nullable = false, updatable = false)}, + inverseJoinColumns = { + @JoinColumn(name = "customer_id", referencedColumnName = "id", + nullable = false, updatable = false)}) + private Set customers; + + @OneToMany(mappedBy = "album", fetch = FetchType.EAGER) + private List photos = new ArrayList<>(); + + public Album(String name, Customer owner) { + this.name = name; + this.owner = owner; + } + + public Album() { + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Customer getOwner() { + return owner; + } + + public void setOwner(Customer owner) { + this.owner = owner; + } + + public Set getCustomers() { + return customers; + } + + public void setCustomers(Set customers) { + this.customers = customers; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Album album = (Album) o; + return id.equals(album.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public List getPhotos() { + return photos; + } + + public void setPhotos(List photos) { + this.photos = photos; + } +} diff --git a/src/main/java/np/something/model/Comment.java b/src/main/java/np/something/model/Comment.java deleted file mode 100644 index 54059cf..0000000 --- a/src/main/java/np/something/model/Comment.java +++ /dev/null @@ -1,82 +0,0 @@ -package np.something.model; - -import javax.persistence.*; -import javax.validation.constraints.NotBlank; - -import java.time.LocalDateTime; -import java.util.Objects; - -@Entity -public class Comment { - @Id - @GeneratedValue(strategy = GenerationType.AUTO) - private Long id; - - @Column - @NotBlank(message = "Content cannot be empty") - private String content; - - @ManyToOne(fetch = FetchType.EAGER) - @JoinColumn(name="customer_fk") - private Customer customer; - - @ManyToOne(fetch = FetchType.EAGER) - @JoinColumn(name="post_fk") - private Post post; - - @Column(columnDefinition = "timestamp default NOW()") - private LocalDateTime createDate; - - public Comment() { - - } - - public Comment(Customer customer, Post post, String content) { - this.customer = customer; - this.post = post; - this.content = content; - } - - public Long getId() { - return id; - } - - public Post getPost() { - return post; - } - - public Customer getCustomer() { - return customer; - } - - public String getContent() { - return content; - } - - public void setContent(String content) { - this.content = content; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - Comment comment = (Comment) o; - - return Objects.equals(id, comment.id); - } - - @Override - public int hashCode() { - return Objects.hash(id); - } - - public LocalDateTime getCreateDate() { - return createDate; - } - - public void setCreateDate(LocalDateTime createDate) { - this.createDate = createDate; - } -} diff --git a/src/main/java/np/something/model/Customer.java b/src/main/java/np/something/model/Customer.java index cbfc795..c1dcbd5 100644 --- a/src/main/java/np/something/model/Customer.java +++ b/src/main/java/np/something/model/Customer.java @@ -4,6 +4,7 @@ import org.h2.engine.User; import javax.persistence.*; import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Size; import java.util.*; @@ -13,15 +14,17 @@ public class Customer { @GeneratedValue(strategy = GenerationType.AUTO) private Long id; @Column - @NotBlank(message = "Username cannot be empty") + @Size(min=3, max=32, message="Username string length must be from 3 to 32 letters") private String username; @Column - @NotBlank(message = "Password cannot be empty") + @Size(min=8, max=1024, message="Password string length must be from 8 to 1024 letters") private String password; - @OneToMany(fetch = FetchType.EAGER, mappedBy = "customer", cascade = CascadeType.ALL) - private List comments; - @OneToMany(fetch = FetchType.EAGER, mappedBy = "customer", cascade = CascadeType.ALL) - private List posts; + + @ManyToMany(mappedBy = "customers", fetch = FetchType.EAGER) + private Set albums = new HashSet<>(); + + @OneToMany(mappedBy = "owner", fetch = FetchType.EAGER) + private List ownedAlbums = new ArrayList<>(); private UserRole role; @@ -33,16 +36,12 @@ public class Customer { this.username = username; this.password = password; this.role = UserRole.USER; - this.comments = new ArrayList<>(); - this.posts = new ArrayList<>(); } public Customer(String username, String password, UserRole role) { this.username = username; this.password = password; this.role = role; - this.comments = new ArrayList<>(); - this.posts = new ArrayList<>(); } public Long getId() { @@ -57,14 +56,6 @@ public class Customer { return password; } - public List getComments() { - return comments; - } - - public List getPosts() { - return posts; - } - public void setUsername(String username) { this.username = username; } @@ -89,4 +80,20 @@ public class Customer { public int hashCode() { return Objects.hash(id); } + + public Set getAlbums() { + return albums; + } + + public void setAlbums(Set albums) { + this.albums = albums; + } + + public List getOwnedAlbums() { + return ownedAlbums; + } + + public void setOwnedAlbums(List ownedAlbums) { + this.ownedAlbums = ownedAlbums; + } } diff --git a/src/main/java/np/something/model/Photo.java b/src/main/java/np/something/model/Photo.java new file mode 100644 index 0000000..4bd4f26 --- /dev/null +++ b/src/main/java/np/something/model/Photo.java @@ -0,0 +1,70 @@ +package np.something.model; + +import javax.persistence.*; +import java.util.Objects; +import java.util.Set; + +@Entity +public class Photo { + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "album_fk") + private Album album; + + @ManyToMany(fetch = FetchType.EAGER) + @JoinTable(name = "photos_tags", + joinColumns = { + @JoinColumn(name = "photo_id", referencedColumnName = "id", + nullable = false, updatable = false)}, + inverseJoinColumns = { + @JoinColumn(name = "tag_id", referencedColumnName = "id", + nullable = false, updatable = false)}) + private Set tags; + + public Photo(Album album) { + this.album = album; + } + + public Photo() { + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Photo photo = (Photo) o; + return id.equals(photo.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } + + public Album getAlbum() { + return album; + } + + public void setAlbum(Album album) { + this.album = album; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Set getTags() { + return tags; + } + + public void setTags(Set tags) { + this.tags = tags; + } +} diff --git a/src/main/java/np/something/model/Post.java b/src/main/java/np/something/model/Post.java deleted file mode 100644 index 26ceafa..0000000 --- a/src/main/java/np/something/model/Post.java +++ /dev/null @@ -1,95 +0,0 @@ -package np.something.model; - -import javax.persistence.*; -import javax.validation.constraints.NotBlank; - -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.List; - -@Entity -public class Post { - @Id - @GeneratedValue(strategy = GenerationType.AUTO) - private Long id; - - @Column - @NotBlank(message = "Title cannot be empty") - private String title; - - @Column - @NotBlank(message = "Content cannot be empty") - private String content; - - @ManyToOne(fetch = FetchType.EAGER) - @JoinColumn(name = "customer_fk") - private Customer customer; - - @OneToMany(fetch = FetchType.EAGER, mappedBy = "post", cascade = CascadeType.ALL) - private List comments; - - @Column(columnDefinition = "timestamp default NOW()") - private LocalDateTime createDate; - - public Post() { - - } - - public Post(Customer customer, String title, String content) { - this.customer = customer; - this.title = title; - this.content = content; - this.comments = new ArrayList<>(); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - Post post = (Post) o; - - return id.equals(post.id); - } - - @Override - public int hashCode() { - return id.hashCode(); - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public String getContent() { - return content; - } - - public void setContent(String content) { - this.content = content; - } - - public List getComments() { - return comments; - } - - public Customer getCustomer() { - return customer; - } - - public Long getId() { - return id; - } - - public LocalDateTime getCreateDate() { - return createDate; - } - - public void setCreateDate(LocalDateTime createDate) { - this.createDate = createDate; - } -} diff --git a/src/main/java/np/something/model/Tag.java b/src/main/java/np/something/model/Tag.java new file mode 100644 index 0000000..5e15f52 --- /dev/null +++ b/src/main/java/np/something/model/Tag.java @@ -0,0 +1,64 @@ +package np.something.model; + +import javax.persistence.*; +import javax.validation.constraints.Size; +import java.util.List; +import java.util.Objects; + +@Entity +public class Tag { + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + + @Column + @Size(min=3, max=32, message="Tag's name must be from 3 to 32 letters") + private String name; + + @ManyToMany(mappedBy = "tags") + List photos; + + public Tag() { + } + + public Tag(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List getPhotos() { + return photos; + } + + public void setPhotos(List photos) { + this.photos = photos; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Tag tag = (Tag) o; + return id.equals(tag.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } +} diff --git a/src/main/java/np/something/mvc/Admin.java b/src/main/java/np/something/mvc/Admin.java deleted file mode 100644 index e28ecf7..0000000 --- a/src/main/java/np/something/mvc/Admin.java +++ /dev/null @@ -1,70 +0,0 @@ -package np.something.mvc; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpSession; -import javax.validation.Valid; -import np.something.DTO.CustomerDto; -import np.something.model.UserRole; -import np.something.services.CustomerService; -import org.springframework.security.access.annotation.Secured; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.validation.BindingResult; -import org.springframework.web.bind.annotation.*; - -@Controller -@RequestMapping("/admin") -@Secured({UserRole.AsString.ADMIN}) -public class Admin { - private final CustomerService customerService; - - public Admin(CustomerService customerService) { - this.customerService = customerService; - } - - @GetMapping(value = { "/", "/{id}" }) - @Secured({UserRole.AsString.ADMIN}) - public String getCustomers(@PathVariable(required = false) Long id, HttpServletRequest request, Model model) { - model.addAttribute("request", request); - model.addAttribute("currentCustomerId", customerService.findByUsername( - ((UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername() - ).getId()); - if (id == null || id <= 0) { - model.addAttribute("customers", customerService.findAllCustomers().stream().map(CustomerDto::new).toList()); - return "admin"; - } else { - return "redirect:/customers/" + id; - } - } - - @PostMapping("/delete/{id}") - public String deleteCustomer(@PathVariable Long id) { - customerService.deleteCustomer(id); - return "redirect:/admin/"; - } - - @PostMapping(value = { "/", "/{id}"}) - public String manipulateCustomer(@PathVariable(required = false) Long id, @ModelAttribute @Valid CustomerDto customerDto, - HttpServletRequest request, - BindingResult bindingResult, - Model model) { - model.addAttribute("request", request); - model.addAttribute("currentCustomerId", customerService.findByUsername( - ((UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername() - ).getId()); - if (bindingResult.hasErrors()) { - model.addAttribute("errors", bindingResult.getAllErrors()); - return "/admin"; - } - - if (id == null || id <= 0) { - customerService.addCustomer(customerDto.username, customerDto.password); - } else { - customerService.updateCustomer(id, customerDto.username, customerDto.password); - } - - return "redirect:/admin/"; - } -} diff --git a/src/main/java/np/something/mvc/AlbumMVC.java b/src/main/java/np/something/mvc/AlbumMVC.java new file mode 100644 index 0000000..b53b60b --- /dev/null +++ b/src/main/java/np/something/mvc/AlbumMVC.java @@ -0,0 +1,132 @@ +package np.something.mvc; + +import np.something.DTO.AlbumDto; +import np.something.model.Album; +import np.something.model.Customer; +import np.something.services.AlbumService; +import np.something.services.CustomerService; +import np.something.services.PhotoService; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.Objects; + +@Controller +@RequestMapping(value = {"/albums"}) +public class AlbumMVC { + private final AlbumService albumService; + private final CustomerService customerService; + private final PhotoService photoService; + + public AlbumMVC(AlbumService albumService, CustomerService customerService, PhotoService photoService) { + this.albumService = albumService; + this.customerService = customerService; + this.photoService = photoService; + } + + @GetMapping + public String albums(Model model) { + Customer customer = customerService.findByUsername( + ((UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername() + ); + model.addAttribute("currentCustomer", customer); + model.addAttribute("albums", customer.getAlbums()); + model.addAttribute("ownerAlbums", customer.getOwnedAlbums()); + + return "/albums"; + } + + @GetMapping("/{id}") + public String album(Model model, @PathVariable Long id) { + Customer customer = customerService.findByUsername( + ((UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername() + ); + Album album = albumService.find(id); + model.addAttribute("currentCustomer", customer); + model.addAttribute("customers", customerService.findAllCustomers().stream().filter(x -> !Objects.equals(x.getId(), album.getOwner().getId()) && !album.getCustomers().contains(x)).toList()); + model.addAttribute("album", album); + model.addAttribute("photos", album.getPhotos()); + + return "/album"; + } + + @PostMapping + public String createAlbum(@ModelAttribute @Valid AlbumDto albumDto) { + Customer customer = customerService.findByUsername( + ((UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername() + ); + + albumService.add(albumDto.getName(), customer); + + return "redirect:/albums"; + } + + @PostMapping("/edit/{id}") + public String editAlbum(@PathVariable Long id, @ModelAttribute @Valid AlbumDto albumDto) { + Customer customer = customerService.findByUsername( + ((UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername() + ); + + if (Objects.equals(albumService.find(id).getOwner().getId(), customer.getId())) { + albumService.update(id, albumDto.getName()); + } + + return "redirect:/albums/" + id; + } + + @PostMapping("/delete/{id}") + public String deleteAlbum(@PathVariable Long id) { + Customer customer = customerService.findByUsername( + ((UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername() + ); + + if (Objects.equals(albumService.find(id).getOwner().getId(), customer.getId())) { + albumService.delete(id); + } + + return "redirect:/albums"; + } + + @PostMapping("/{id}/add/photo") + public String addPhoto(@PathVariable Long id) { + Customer customer = customerService.findByUsername( + ((UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername() + ); + + if (Objects.equals(albumService.find(id).getOwner().getId(), customer.getId())) { + albumService.addPhoto(id); + } + + return "redirect:/albums/" + id; + } + + @PostMapping("/{id}/add/customer/{cid}") + public String addCustomer(@PathVariable Long id, @PathVariable Long cid) { + Customer customer = customerService.findByUsername( + ((UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername() + ); + + if (Objects.equals(albumService.find(id).getOwner().getId(), customer.getId())) { + albumService.addCustomer(id, cid); + } + + return "redirect:/albums/" + id; + } + + @PostMapping("/{id}/remove/customer/{cid}") + public String removeCustomer(@PathVariable Long id, @PathVariable Long cid) { + Customer customer = customerService.findByUsername( + ((UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername() + ); + + if (Objects.equals(albumService.find(id).getOwner().getId(), customer.getId())) { + albumService.removeCustomer(id, cid); + } + + return "redirect:/albums/" + id; + } +} diff --git a/src/main/java/np/something/mvc/Comments.java b/src/main/java/np/something/mvc/Comments.java deleted file mode 100644 index a535be2..0000000 --- a/src/main/java/np/something/mvc/Comments.java +++ /dev/null @@ -1,59 +0,0 @@ -package np.something.mvc; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpSession; -import javax.validation.Valid; -import np.something.DTO.CommentDto; -import np.something.DTO.PostDto; -import np.something.services.CommentService; -import np.something.services.CustomerService; -import np.something.services.PostService; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.validation.BindingResult; -import org.springframework.web.bind.annotation.*; - -@Controller -@RequestMapping("/comments") -public class Comments { - private final CustomerService customerService; - private final CommentService commentService; - private final PostService postService; - - public Comments(CustomerService customerService, CommentService commentService, PostService postService) { - this.customerService = customerService; - this.commentService = commentService; - this.postService = postService; - } - - @PostMapping(value = { "/", "/{id}"}) - public String manipulateComment(@PathVariable(required = false) Long id, @ModelAttribute @Valid CommentDto commentDto, - HttpServletRequest request, BindingResult bindingResult, Model model) { - model.addAttribute("request", request); - model.addAttribute("currentCustomerId", customerService.findByUsername( - ((UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername() - ).getId()); - model.addAttribute("posts", postService.findAllPosts().stream().map(PostDto::new).toList()); - - if (bindingResult.hasErrors()) { - model.addAttribute("errors", bindingResult.getAllErrors()); - return "/feed"; - } - - if (id == null || id <= 0) { - commentService.addComment(customerService.findCustomer(commentDto.customerId), postService.findPost(commentDto.postId), commentDto.content); - } else { - commentService.updateComment(id, commentDto.content); - } - - return "redirect:/feed"; - } - - @PostMapping("/delete/{id}") - public String deleteComment(@PathVariable Long id) { - commentService.deleteComment(id); - return "redirect:/feed"; - } -} diff --git a/src/main/java/np/something/mvc/Customers.java b/src/main/java/np/something/mvc/Customers.java deleted file mode 100644 index ef6af64..0000000 --- a/src/main/java/np/something/mvc/Customers.java +++ /dev/null @@ -1,67 +0,0 @@ -package np.something.mvc; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpSession; -import javax.validation.Valid; -import np.something.DTO.CustomerDto; -import np.something.services.CustomerService; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.validation.BindingResult; -import org.springframework.web.bind.annotation.*; - -@Controller -@RequestMapping("/customers") -public class Customers { - private final CustomerService customerService; - - public Customers(CustomerService customerService) { - this.customerService = customerService; - } - - @GetMapping(value = { "/", "/{id}" }) - public String getCustomers(@PathVariable(required = false) Long id, HttpServletRequest request, HttpSession session, Model model) { - model.addAttribute("request", request); - model.addAttribute("currentCustomerId", customerService.findByUsername( - ((UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername() - ).getId()); - if (id == null || id <= 0) { - model.addAttribute("customers", customerService.findAllCustomers().stream().map(CustomerDto::new).toList()); - } else { - model.addAttribute("customers", new CustomerDto[] { new CustomerDto(customerService.findCustomer(id)) }); - } - - return "customers"; - } - - @PostMapping("/delete/{id}") - public String deleteCustomer(@PathVariable Long id, HttpSession session) { - customerService.deleteCustomer(id); - return "redirect:/customers/"; - } - - @PostMapping(value = { "/", "/{id}"}) - public String manipulateCustomer(@PathVariable(required = false) Long id, @ModelAttribute @Valid CustomerDto customerDto, - HttpServletRequest request, HttpSession session, - BindingResult bindingResult, - Model model) { - model.addAttribute("request", request); - model.addAttribute("currentCustomerId", customerService.findByUsername( - ((UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername() - ).getId()); - if (bindingResult.hasErrors()) { - model.addAttribute("errors", bindingResult.getAllErrors()); - return "/customers"; - } - - if (id == null || id <= 0) { - customerService.addCustomer(customerDto.username, customerDto.password); - } else { - customerService.updateCustomer(id, customerDto.username, customerDto.password); - } - - return "redirect:/customers/"; - } -} diff --git a/src/main/java/np/something/mvc/Feed.java b/src/main/java/np/something/mvc/Feed.java deleted file mode 100644 index ee70548..0000000 --- a/src/main/java/np/something/mvc/Feed.java +++ /dev/null @@ -1,54 +0,0 @@ -package np.something.mvc; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpSession; -import np.something.DTO.CommentDto; -import np.something.DTO.CustomerDto; -import np.something.DTO.PostDto; -import np.something.model.Post; -import np.something.services.CommentService; -import np.something.services.CustomerService; -import np.something.services.PostService; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.userdetails.UserDetails; -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.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -@Controller -@RequestMapping(value = { "", "/feed" }) -public class Feed { - private final PostService postService; - private final CustomerService customerService; - - private final CommentService commentService; - - public Feed(PostService postService, CustomerService customerService, CommentService commentService) { - this.postService = postService; - this.customerService = customerService; - this.commentService = commentService; - } - - @GetMapping - public String getPosts(@RequestParam(required = false) String search, HttpServletRequest request, HttpSession session, Model model) { - model.addAttribute("request", request); - model.addAttribute("currentCustomerId", customerService.findByUsername( - ((UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername() - ).getId()); - if (search == null) { - model.addAttribute("posts", postService.findAllPosts().stream().map(PostDto::new).toList()); - } else { - model.addAttribute("posts", postService.searchPosts(search)); - } - model.addAttribute("customers", customerService.findAllCustomers().stream().map(CustomerDto::new).toList()); - - return "/feed"; - } -} diff --git a/src/main/java/np/something/mvc/PhotoMVC.java b/src/main/java/np/something/mvc/PhotoMVC.java new file mode 100644 index 0000000..586dd70 --- /dev/null +++ b/src/main/java/np/something/mvc/PhotoMVC.java @@ -0,0 +1,94 @@ +package np.something.mvc; + +import np.something.model.Album; +import np.something.model.Customer; +import np.something.model.Photo; +import np.something.services.CustomerService; +import np.something.services.PhotoService; +import np.something.services.TagService; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.Objects; + +@Controller +@RequestMapping("/photos") +public class PhotoMVC { + private final PhotoService photoService; + private final TagService tagService; + + private final CustomerService customerService; + + public PhotoMVC(PhotoService photoService, TagService tagService, CustomerService customerService) { + this.photoService = photoService; + this.tagService = tagService; + this.customerService = customerService; + } + + @GetMapping("/{id}") + public String photo(Model model, @PathVariable Long id) { + Customer customer = customerService.findByUsername( + ((UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername() + ); + + Photo photo = photoService.getPhotoById(id); + + model.addAttribute("currentCustomer", customer); + model.addAttribute("photo", photo); + model.addAttribute("tags", tagService.findAll().stream().filter(x -> !photo.getTags().contains(x)).toList()); + + return "/photo"; + } + + @PostMapping("/delete/{id}") + public String deletePhoto(@PathVariable Long id) { + Customer customer = customerService.findByUsername( + ((UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername() + ); + + Photo photo = photoService.getPhotoById(id); + Album album = photo.getAlbum(); + + if (Objects.equals(album.getOwner().getId(), customer.getId())) { + photoService.delete(id); + } + + return "redirect:/albums/" + album.getId(); + } + + @PostMapping("/{id}/add/tag/{tag_id}") + public String addTag(@PathVariable Long id, @PathVariable Long tag_id) { + Customer customer = customerService.findByUsername( + ((UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername() + ); + + Photo photo = photoService.getPhotoById(id); + Album album = photo.getAlbum(); + + if (Objects.equals(album.getOwner().getId(), customer.getId())) { + photoService.addTag(id, tag_id); + } + + return "redirect:/photos/" + id; + } + + @PostMapping("/{id}/remove/tag/{tag_id}") + public String removeTag(@PathVariable Long id, @PathVariable Long tag_id) { + Customer customer = customerService.findByUsername( + ((UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername() + ); + + Photo photo = photoService.getPhotoById(id); + Album album = photo.getAlbum(); + + if (Objects.equals(album.getOwner().getId(), customer.getId())) { + photoService.removeTag(id, tag_id); + } + + return "redirect:/photos/" + id; + } +} diff --git a/src/main/java/np/something/mvc/Posts.java b/src/main/java/np/something/mvc/Posts.java deleted file mode 100644 index 0cab3ea..0000000 --- a/src/main/java/np/something/mvc/Posts.java +++ /dev/null @@ -1,60 +0,0 @@ -package np.something.mvc; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpSession; -import np.something.services.CommentService; -import np.something.services.CustomerService; -import np.something.services.PostService; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.*; -import org.springframework.validation.BindingResult; -import javax.validation.Valid; -import np.something.DTO.PostDto; - -@Controller -@RequestMapping("/posts") -public class Posts { - private final CustomerService customerService; - private final CommentService commentService; - private final PostService postService; - - public Posts(CustomerService customerService, CommentService commentService, PostService postService) { - this.customerService = customerService; - this.commentService = commentService; - this.postService = postService; - } - - @PostMapping("/delete/{id}") - public String deletePost(@PathVariable Long id) { - postService.deletePost(id); - return "redirect:/feed"; - } - - @PostMapping(value = { "/", "/{id}"}) - public String manipulatePost(@PathVariable(required = false) Long id, @ModelAttribute @Valid PostDto postDto, - HttpServletRequest request, HttpSession session, - BindingResult bindingResult, - Model model) { - model.addAttribute("request", request); - model.addAttribute("currentCustomerId", customerService.findByUsername( - ((UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername() - ).getId()); - model.addAttribute("posts", postService.findAllPosts().stream().map(PostDto::new).toList()); - - if (bindingResult.hasErrors()) { - model.addAttribute("errors", bindingResult.getAllErrors()); - return "/feed"; - } - - if (id == null || id <= 0) { - postService.addPost(customerService.findCustomer(postDto.customerId), postDto.title, postDto.content); - } else { - postService.updatePost(id, postDto.title, postDto.content); - } - - return "redirect:/feed"; - } -} diff --git a/src/main/java/np/something/mvc/TagMVC.java b/src/main/java/np/something/mvc/TagMVC.java new file mode 100644 index 0000000..715d4c3 --- /dev/null +++ b/src/main/java/np/something/mvc/TagMVC.java @@ -0,0 +1,79 @@ +package np.something.mvc; + +import np.something.DTO.TagDto; +import np.something.model.Customer; +import np.something.model.Tag; +import np.something.model.UserRole; +import np.something.services.CustomerService; +import np.something.services.PhotoService; +import np.something.services.TagService; +import org.springframework.security.access.annotation.Secured; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.*; + +@Controller +@RequestMapping("/tags") +public class TagMVC { + private final TagService tagService; + private final CustomerService customerService; + private final PhotoService photoService; + + public TagMVC(TagService tagService, CustomerService customerService, PhotoService photoService) { + this.tagService = tagService; + this.customerService = customerService; + this.photoService = photoService; + } + + @GetMapping + public String tags(Model model, @RequestParam(required = false) String search) { + Customer customer = customerService.findByUsername( + ((UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername() + ); + + model.addAttribute("currentCustomer", customer); + if (search == null || search.isBlank()) { + model.addAttribute("tags", tagService.findAll()); + } else { + model.addAttribute("tags", tagService.tagsByTagPrefix(search)); + } + + return "/tags"; + } + + @GetMapping("/{id}") + public String tag(Model model, @PathVariable Long id) { + Customer customer = customerService.findByUsername( + ((UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername() + ); + + Tag tag = tagService.find(id); + + model.addAttribute("currentCustomer", customer); + model.addAttribute("tag", tag); + model.addAttribute("photos", tagService.customersPhotosByTag(customer, id)); + + return "/tag"; + } + + @PostMapping + @Secured({UserRole.AsString.ADMIN}) + public String createTag(@ModelAttribute @Valid TagDto tagDto) { + tagService.add(tagDto.getName()); + + return "redirect:/tags"; + } + + @PostMapping("/{id}") + @Secured({UserRole.AsString.ADMIN}) + public String editTag(@PathVariable Long id, @ModelAttribute @Valid TagDto tagDto) { + tagService.update(id, tagDto.getName()); + + return "redirect:/tags"; + } +} diff --git a/src/main/java/np/something/repositories/AlbumRepository.java b/src/main/java/np/something/repositories/AlbumRepository.java new file mode 100644 index 0000000..6a83170 --- /dev/null +++ b/src/main/java/np/something/repositories/AlbumRepository.java @@ -0,0 +1,7 @@ +package np.something.repositories; + +import np.something.model.Album; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface AlbumRepository extends JpaRepository { +} diff --git a/src/main/java/np/something/repositories/CommentRepository.java b/src/main/java/np/something/repositories/CommentRepository.java deleted file mode 100644 index cab8d44..0000000 --- a/src/main/java/np/something/repositories/CommentRepository.java +++ /dev/null @@ -1,13 +0,0 @@ -package np.something.repositories; - -import np.something.model.Comment; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; - -import java.util.List; - -public interface CommentRepository extends JpaRepository { - @Query("SELECT DISTINCT c FROM Comment c WHERE c.content LIKE %:tag%") - List searchComments(@Param("tag") String tag); -} diff --git a/src/main/java/np/something/repositories/PhotoRepository.java b/src/main/java/np/something/repositories/PhotoRepository.java new file mode 100644 index 0000000..c4adf16 --- /dev/null +++ b/src/main/java/np/something/repositories/PhotoRepository.java @@ -0,0 +1,12 @@ +package np.something.repositories; + +import np.something.model.Photo; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +import java.util.List; + +public interface PhotoRepository extends JpaRepository { + +} diff --git a/src/main/java/np/something/repositories/PostRepository.java b/src/main/java/np/something/repositories/PostRepository.java deleted file mode 100644 index 998809f..0000000 --- a/src/main/java/np/something/repositories/PostRepository.java +++ /dev/null @@ -1,14 +0,0 @@ -package np.something.repositories; - -import np.something.model.Comment; -import np.something.model.Post; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; - -import java.util.List; - -public interface PostRepository extends JpaRepository { - @Query("SELECT DISTINCT p FROM Post p WHERE p.title LIKE %:tag% OR p.content LIKE %:tag%") - List searchPosts(@Param("tag") String tag); -} diff --git a/src/main/java/np/something/repositories/TagRepository.java b/src/main/java/np/something/repositories/TagRepository.java new file mode 100644 index 0000000..fe696a6 --- /dev/null +++ b/src/main/java/np/something/repositories/TagRepository.java @@ -0,0 +1,17 @@ +package np.something.repositories; + +import np.something.model.Photo; +import np.something.model.Tag; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +import java.util.List; + +public interface TagRepository extends JpaRepository { + @Query("SELECT t FROM Tag t WHERE LOWER(t.name) LIKE LOWER(CONCAT(:tagPrefix, '%'))") + List findTagsByTagPrefix(@Param("tagPrefix") String tagPrefix); + + @Query("SELECT p FROM Photo p JOIN p.tags t WHERE (:tagIds) IN t.id GROUP BY p HAVING COUNT(DISTINCT t) >= :tagCount") + List findPhotosByTags(@Param("tagIds") List tagIds, @Param("tagCount") long tagCount); +} diff --git a/src/main/java/np/something/security/JwtFilter.java b/src/main/java/np/something/security/JwtFilter.java deleted file mode 100644 index bed1ee8..0000000 --- a/src/main/java/np/something/security/JwtFilter.java +++ /dev/null @@ -1,73 +0,0 @@ -package np.something.security; - -import com.fasterxml.jackson.databind.ObjectMapper; -import np.something.Exceptions.JwtException; -import np.something.services.CustomerService; -import org.springframework.http.MediaType; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.util.StringUtils; -import org.springframework.web.filter.GenericFilterBean; - -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; - -public class JwtFilter extends GenericFilterBean { - private static final String AUTHORIZATION = "Authorization"; - public static final String TOKEN_BEGIN_STR = "Bearer "; - - private final CustomerService customerService; - - public JwtFilter(CustomerService customerService) { - this.customerService = customerService; - } - - private String getTokenFromRequest(HttpServletRequest request) { - String bearer = request.getHeader(AUTHORIZATION); - if (StringUtils.hasText(bearer) && bearer.startsWith(TOKEN_BEGIN_STR)) { - return bearer.substring(TOKEN_BEGIN_STR.length()); - } - return null; - } - - private void raiseException(ServletResponse response, int status, String message) throws IOException { - if (response instanceof final HttpServletResponse httpResponse) { - httpResponse.setContentType(MediaType.APPLICATION_JSON_VALUE); - httpResponse.setStatus(status); - final byte[] body = new ObjectMapper().writeValueAsBytes(message); - response.getOutputStream().write(body); - } - } - - @Override - public void doFilter(ServletRequest request, - ServletResponse response, - FilterChain chain) throws IOException, ServletException { - if (request instanceof final HttpServletRequest httpRequest) { - final String token = getTokenFromRequest(httpRequest); - if (StringUtils.hasText(token)) { - try { - final UserDetails user = customerService.loadUserByToken(token); - final UsernamePasswordAuthenticationToken auth = - new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities()); - SecurityContextHolder.getContext().setAuthentication(auth); - } catch (JwtException e) { - raiseException(response, HttpServletResponse.SC_UNAUTHORIZED, e.getMessage()); - return; - } catch (Exception e) { - e.printStackTrace(); - raiseException(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, - String.format("Internal error: %s", e.getMessage())); - return; - } - } - } - chain.doFilter(request, response); - } -} \ No newline at end of file diff --git a/src/main/java/np/something/security/JwtProperties.java b/src/main/java/np/something/security/JwtProperties.java deleted file mode 100644 index cbb2497..0000000 --- a/src/main/java/np/something/security/JwtProperties.java +++ /dev/null @@ -1,27 +0,0 @@ -package np.something.security; - -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Configuration; - -@Configuration -@ConfigurationProperties(prefix = "jwt", ignoreInvalidFields = true) -public class JwtProperties { - private String devToken = ""; - private Boolean isDev = true; - - public String getDevToken() { - return devToken; - } - - public void setDevToken(String devToken) { - this.devToken = devToken; - } - - public Boolean isDev() { - return isDev; - } - - public void setDev(Boolean dev) { - isDev = dev; - } -} diff --git a/src/main/java/np/something/security/JwtProvider.java b/src/main/java/np/something/security/JwtProvider.java deleted file mode 100644 index 82a7443..0000000 --- a/src/main/java/np/something/security/JwtProvider.java +++ /dev/null @@ -1,108 +0,0 @@ -package np.something.security; - -import com.auth0.jwt.JWT; -import com.auth0.jwt.algorithms.Algorithm; -import com.auth0.jwt.exceptions.JWTVerificationException; -import com.auth0.jwt.interfaces.DecodedJWT; -import com.auth0.jwt.interfaces.JWTVerifier; -import np.something.Exceptions.JwtException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Component; -import org.springframework.util.StringUtils; - -import java.nio.charset.StandardCharsets; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.time.LocalDate; -import java.time.ZoneId; -import java.util.Date; -import java.util.Optional; -import java.util.UUID; - -@Component -public class JwtProvider { - private final static Logger LOG = LoggerFactory.getLogger(JwtProvider.class); - - private final static byte[] HEX_ARRAY = "0123456789ABCDEF".getBytes(StandardCharsets.US_ASCII); - private final static String ISSUER = "auth0"; - - private final Algorithm algorithm; - private final JWTVerifier verifier; - - public JwtProvider(JwtProperties jwtProperties) { - if (!jwtProperties.isDev()) { - LOG.info("Generate new JWT key for prod"); - try { - final MessageDigest salt = MessageDigest.getInstance("SHA-256"); - salt.update(UUID.randomUUID().toString().getBytes(StandardCharsets.UTF_8)); - LOG.info("Use generated JWT key for prod \n{}", bytesToHex(salt.digest())); - algorithm = Algorithm.HMAC256(bytesToHex(salt.digest())); - } catch (NoSuchAlgorithmException e) { - throw new JwtException(e); - } - } else { - LOG.info("Use default JWT key for dev \n{}", jwtProperties.getDevToken()); - algorithm = Algorithm.HMAC256(jwtProperties.getDevToken()); - } - verifier = JWT.require(algorithm) - .withIssuer(ISSUER) - .build(); - } - - private static String bytesToHex(byte[] bytes) { - byte[] hexChars = new byte[bytes.length * 2]; - for (int j = 0; j < bytes.length; j++) { - int v = bytes[j] & 0xFF; - hexChars[j * 2] = HEX_ARRAY[v >>> 4]; - hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F]; - } - return new String(hexChars, StandardCharsets.UTF_8); - } - - public String generateToken(String login) { - final Date issueDate = Date.from(LocalDate.now() - .atStartOfDay(ZoneId.systemDefault()) - .toInstant()); - final Date expireDate = Date.from(LocalDate.now() - .plusDays(15) - .atStartOfDay(ZoneId.systemDefault()) - .toInstant()); - return JWT.create() - .withIssuer(ISSUER) - .withIssuedAt(issueDate) - .withExpiresAt(expireDate) - .withSubject(login) - .sign(algorithm); - } - - private DecodedJWT validateToken(String token) { - try { - return verifier.verify(token); - } catch (JWTVerificationException e) { - throw new JwtException(String.format("Token verification error: %s", e.getMessage())); - } - } - - public boolean isTokenValid(String token) { - if (!StringUtils.hasText(token)) { - return false; - } - try { - validateToken(token); - return true; - } catch (JwtException e) { - LOG.error(e.getMessage()); - return false; - } - } - - public Optional getLoginFromToken(String token) { - try { - return Optional.ofNullable(validateToken(token).getSubject()); - } catch (JwtException e) { - LOG.error(e.getMessage()); - return Optional.empty(); - } - } -} diff --git a/src/main/java/np/something/security/SecurityConfiguration.java b/src/main/java/np/something/security/SecurityConfiguration.java index 8ecd2dc..73dd64b 100644 --- a/src/main/java/np/something/security/SecurityConfiguration.java +++ b/src/main/java/np/something/security/SecurityConfiguration.java @@ -1,7 +1,5 @@ package np.something.security; -import np.something.WebConfiguration; -import np.something.controllers.CustomerController; import np.something.model.UserRole; import np.something.mvc.UserSignUp; import np.something.services.CustomerService; @@ -16,12 +14,10 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.WebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.authentication.DelegatingAuthenticationEntryPoint; import org.springframework.security.web.authentication.Http403ForbiddenEntryPoint; import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint; -import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcher; @@ -33,13 +29,10 @@ import java.util.LinkedHashMap; public class SecurityConfiguration extends WebSecurityConfigurerAdapter { private final Logger log = LoggerFactory.getLogger(SecurityConfiguration.class); private static final String LOGIN_URL = "/login"; - public static final String SPA_URL_MASK = "/{path:[^\\.]*}"; private final CustomerService customerService; - private final JwtFilter jwtFilter; public SecurityConfiguration(CustomerService customerService) { this.customerService = customerService; - this.jwtFilter = new JwtFilter(customerService); createAdminOnStartup(); } @@ -47,7 +40,7 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter { final String admin = "admin"; if (customerService.findByUsername(admin) == null) { log.info("Admin user successfully created"); - customerService.addCustomer(admin, admin, UserRole.ADMIN); + customerService.addCustomer(admin, admin + admin, UserRole.ADMIN); } } @@ -62,31 +55,12 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter { .antMatchers(HttpMethod.GET, LOGIN_URL).permitAll() .anyRequest().authenticated() .and() - .formLogin() + .formLogin().defaultSuccessUrl("/albums", true) .loginPage(LOGIN_URL).permitAll() .and() .logout().permitAll(); } -// @Override -// protected void configure(HttpSecurity http) throws Exception { -// log.info("Creating security configuration"); -// http.cors() -// .and() -// .csrf().disable() -// .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) -// .and() -// .authorizeRequests() -// .antMatchers("/", SPA_URL_MASK).permitAll() -// .antMatchers(HttpMethod.POST, WebConfiguration.REST_API + "/customer" + CustomerController.URL_LOGIN).permitAll() -// .antMatchers(HttpMethod.POST, WebConfiguration.REST_API + "/customer").permitAll() -// .anyRequest() -// .authenticated() -// .and() -// .addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class) -// .anonymous(); -// } - @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(customerService); @@ -106,11 +80,11 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter { @Bean public AuthenticationEntryPoint delegatingEntryPoint() { final LinkedHashMap map = new LinkedHashMap(); - map.put(new AntPathRequestMatcher("/"), new LoginUrlAuthenticationEntryPoint("/login")); + map.put(new AntPathRequestMatcher("/"), new LoginUrlAuthenticationEntryPoint(LOGIN_URL)); map.put(new AntPathRequestMatcher("/api/1.0/**"), new Http403ForbiddenEntryPoint()); final DelegatingAuthenticationEntryPoint entryPoint = new DelegatingAuthenticationEntryPoint(map); - entryPoint.setDefaultEntryPoint(new LoginUrlAuthenticationEntryPoint("/login")); + entryPoint.setDefaultEntryPoint(new LoginUrlAuthenticationEntryPoint(LOGIN_URL)); return entryPoint; } diff --git a/src/main/java/np/something/services/AlbumService.java b/src/main/java/np/something/services/AlbumService.java new file mode 100644 index 0000000..01b0ef8 --- /dev/null +++ b/src/main/java/np/something/services/AlbumService.java @@ -0,0 +1,85 @@ +package np.something.services; + +import np.something.model.Album; +import np.something.model.Customer; +import np.something.model.Photo; +import np.something.repositories.AlbumRepository; +import np.something.repositories.CustomerRepository; +import np.something.repositories.PhotoRepository; +import np.something.util.validation.ValidatorUtil; +import org.springframework.stereotype.Service; + +import javax.transaction.Transactional; +import java.util.List; + +@Service +public class AlbumService { + private final AlbumRepository albumRepository; + private final CustomerRepository customerRepository; + private final PhotoRepository photoRepository; + private final ValidatorUtil validatorUtil; + + public AlbumService(AlbumRepository albumRepository, CustomerRepository customerRepository, PhotoRepository photoRepository, ValidatorUtil validatorUtil) { + this.albumRepository = albumRepository; + this.customerRepository = customerRepository; + this.photoRepository = photoRepository; + this.validatorUtil = validatorUtil; + } + + public Album find(Long id) { + return albumRepository.findById(id).get(); + } + + public List findAll() { + return albumRepository.findAll(); + } + + @Transactional + public Album add(String name, Customer owner) { + Album album = new Album(name, owner); + validatorUtil.validate(album); + return albumRepository.save(album); + } + + @Transactional + public Album update(Long id, String name) { + Album album = albumRepository.findById(id).get(); + album.setName(name); + validatorUtil.validate(album); + albumRepository.save(album); + return album; + } + + @Transactional + public void delete(Long id) { + albumRepository.deleteById(id); + } + + @Transactional + public void addPhoto(Long id) { + Album album = albumRepository.findById(id).get(); + album.getPhotos().add(photoRepository.save(new Photo(album))); + albumRepository.save(album); + } + + @Transactional + public void removePhoto(Long photo_id) { + photoRepository.deleteById(photo_id); + } + + @Transactional + public void addCustomer(Long album_id, Long customer_id) { + Album album = albumRepository.findById(album_id).get(); + Customer customer = customerRepository.findById(customer_id).get(); + album.getCustomers().add(customer); + albumRepository.save(album); + } + + @Transactional + public void removeCustomer(Long album_id, Long customer_id) { + Album album = albumRepository.findById(album_id).get(); + Customer customer = customerRepository.findById(customer_id).get(); + album.getCustomers().remove(customer); + albumRepository.save(album); + } +} diff --git a/src/main/java/np/something/services/CommentService.java b/src/main/java/np/something/services/CommentService.java deleted file mode 100644 index d363090..0000000 --- a/src/main/java/np/something/services/CommentService.java +++ /dev/null @@ -1,74 +0,0 @@ -package np.something.services; - -import np.something.Exceptions.CommentNotFoundException; -import org.springframework.transaction.annotation.Transactional; -import np.something.model.Comment; -import np.something.model.Customer; -import np.something.model.Post; -import np.something.repositories.CommentRepository; -import np.something.util.validation.ValidatorUtil; -import org.springframework.stereotype.Service; - -import java.time.LocalDateTime; -import java.util.List; -import java.util.Optional; - -@Service -public class CommentService { - private final CommentRepository commentRepository; - private final ValidatorUtil validatorUtil; - - public CommentService(CommentRepository commentRepository, - ValidatorUtil validatorUtil) { - this.commentRepository = commentRepository; - this.validatorUtil = validatorUtil; - } - - @Transactional(readOnly = true) - public Comment findComment(Long id) { - final Optional comment = commentRepository.findById(id); - return comment.orElseThrow(() -> new CommentNotFoundException(id)); - } - - @Transactional(readOnly = true) - public List findAllComments() { - return commentRepository.findAll(); - } - - @Transactional - public Comment addComment(Customer customer, Post post, String content) { - final Comment comment = new Comment(customer, post, content); - comment.setCreateDate(LocalDateTime.now()); - validatorUtil.validate(comment); - customer.getComments().add(comment); - post.getComments().add(comment); - return commentRepository.save(comment); - } - - @Transactional - public Comment updateComment(Long id, String content) { - final Comment currentComment = findComment(id); - currentComment.setContent(content); - validatorUtil.validate(currentComment); - return commentRepository.save(currentComment); - } - - @Transactional - public Comment deleteComment(Long id) { - final Comment currentComment = findComment(id); - commentRepository.delete(currentComment); - currentComment.getPost().getComments().remove(currentComment); - currentComment.getCustomer().getComments().remove(currentComment); - return currentComment; - } - - @Transactional - public void deleteAllComments() { - commentRepository.deleteAll(); - } - - @Transactional - public List searchComments(String tag) { - return commentRepository.searchComments(tag); - } -} diff --git a/src/main/java/np/something/services/CustomerService.java b/src/main/java/np/something/services/CustomerService.java index 52f71b2..00fccae 100644 --- a/src/main/java/np/something/services/CustomerService.java +++ b/src/main/java/np/something/services/CustomerService.java @@ -4,11 +4,10 @@ import javax.transaction.Transactional; import np.something.DTO.CustomerDto; import np.something.Exceptions.CustomerNotFoundException; -import np.something.Exceptions.JwtException; +import np.something.model.Album; import np.something.model.Customer; import np.something.model.UserRole; import np.something.repositories.CustomerRepository; -import np.something.security.JwtProvider; import np.something.util.validation.ValidatorUtil; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; @@ -24,14 +23,12 @@ public class CustomerService implements UserDetailsService { private final CustomerRepository customerRepository; private final ValidatorUtil validatorUtil; private final PasswordEncoder passwordEncoder; - private final JwtProvider jwtProvider; public CustomerService(CustomerRepository customerRepository, - ValidatorUtil validatorUtil, PasswordEncoder passwordEncoder, JwtProvider jwtProvider) { + ValidatorUtil validatorUtil, PasswordEncoder passwordEncoder) { this.customerRepository = customerRepository; this.validatorUtil = validatorUtil; this.passwordEncoder = passwordEncoder; - this.jwtProvider = jwtProvider; } @Transactional @@ -48,6 +45,7 @@ public class CustomerService implements UserDetailsService { public Customer addCustomer(String username, String password) { Customer customer = new Customer(username, passwordEncoder.encode(password)); validatorUtil.validate(customer); + customer.getAlbums().add(new Album("Стандартный", customer)); return customerRepository.save(customer); } @@ -92,29 +90,4 @@ public class CustomerService implements UserDetailsService { return new org.springframework.security.core.userdetails.User( customerEntity.getUsername(), customerEntity.getPassword(), Collections.singleton(customerEntity.getRole())); } - - public String loginAndGetToken(CustomerDto customerDto) { - try { - final Customer customer = findByUsername(customerDto.getUsername()); - if (customer == null) { - throw new Exception("Login not found" + customerDto.getUsername()); - } - if (!passwordEncoder.matches(customerDto.getPassword(), customer.getPassword())) { - throw new Exception("User not found" + customer.getUsername()); - } - return jwtProvider.generateToken(customer.getUsername()); - } - catch (Exception e) { - return null; - } - } - - public UserDetails loadUserByToken(String token) throws UsernameNotFoundException { - if (!jwtProvider.isTokenValid(token)) { - throw new JwtException("Bad token"); - } - final String userLogin = jwtProvider.getLoginFromToken(token) - .orElseThrow(() -> new JwtException("Token is not contain Login")); - return loadUserByUsername(userLogin); - } } diff --git a/src/main/java/np/something/services/PhotoService.java b/src/main/java/np/something/services/PhotoService.java new file mode 100644 index 0000000..ca4ed0a --- /dev/null +++ b/src/main/java/np/something/services/PhotoService.java @@ -0,0 +1,52 @@ +package np.something.services; + +import np.something.model.Photo; +import np.something.model.Tag; +import np.something.repositories.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class PhotoService { + + private final PhotoRepository photoRepository; + private final TagRepository tagRepository; + + @Autowired + public PhotoService(PhotoRepository photoRepository, TagRepository tagRepository) { + this.photoRepository = photoRepository; + this.tagRepository = tagRepository; + } + + public List getAllPhotos() { + return photoRepository.findAll(); + } + + public Photo getPhotoById(Long id) { + return photoRepository.findById(id).get(); + } + + public Photo add() { + return photoRepository.save(new Photo()); + } + + public void delete(Long id) { + photoRepository.deleteById(id); + } + + public void addTag(Long photo_id, Long tag_id) { + Photo photo = photoRepository.findById(photo_id).get(); + Tag tag = tagRepository.findById(tag_id).get(); + photo.getTags().add(tag); + photoRepository.save(photo); + } + + public void removeTag(Long photo_id, Long tag_id) { + Photo photo = photoRepository.findById(photo_id).get(); + Tag tag = tagRepository.findById(tag_id).get(); + photo.getTags().remove(tag); + photoRepository.save(photo); + } +} \ No newline at end of file diff --git a/src/main/java/np/something/services/PostService.java b/src/main/java/np/something/services/PostService.java deleted file mode 100644 index ae824c7..0000000 --- a/src/main/java/np/something/services/PostService.java +++ /dev/null @@ -1,98 +0,0 @@ -package np.something.services; - -import javax.transaction.Transactional; - -import np.something.DTO.PostDto; -import np.something.Exceptions.PostNotFoundException; -import np.something.model.Customer; -import np.something.model.Post; -import np.something.repositories.CommentRepository; -import np.something.repositories.PostRepository; -import np.something.util.validation.ValidatorUtil; -import org.springframework.stereotype.Service; - -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -@Service -public class PostService { - private final PostRepository postRepository; - private final CommentRepository commentRepository; - private final ValidatorUtil validatorUtil; - - public PostService(PostRepository postRepository, - CommentRepository commentRepository, ValidatorUtil validatorUtil) { - this.postRepository = postRepository; - this.commentRepository = commentRepository; - this.validatorUtil = validatorUtil; - } - - @Transactional - public Post findPost(Long id) { - return postRepository.findById(id).orElseThrow(() -> new PostNotFoundException(id)); - } - - @Transactional - public List findAllPosts() { - return postRepository.findAll(); - } - - @Transactional - public Post addPost(Customer customer, String title, String content) { - Post post = new Post(customer, title, content); - post.setCreateDate(LocalDateTime.now()); - validatorUtil.validate(post); - customer.getPosts().add(post); - return postRepository.save(post); - } - - @Transactional - public Post updatePost(Long id, String title, String content) { - Post post = findPost(id); - post.setTitle(title); - post.setContent(content); - validatorUtil.validate(post); - return postRepository.save(post); - } - - @Transactional - public Post deletePost(Long id) { - Post post = findPost(id); - post.getCustomer().getPosts().remove(post); - postRepository.delete(post); - return post; - } - - @Transactional - public void deleteAllPosts() { - postRepository.deleteAll(); - } - - @Transactional - public List searchPosts(String search) { - var posts = new ArrayList<>(postRepository.searchPosts(search)); - var comments = commentRepository.searchComments(search); - for (var post: posts) { - post.getComments().clear(); - } - for (var comment: comments) { - boolean found = false; - for (var post: posts) { - if (Objects.equals(comment.getPost().getId(), post.getId())) { - post.getComments().add(comment); - found = true; - break; - } - } - if (!found) { - var newPost = comment.getPost(); - newPost.getComments().clear(); - newPost.getComments().add(comment); - posts.add(newPost); - } - } - return posts.stream().map(PostDto::new).toList(); - } -} diff --git a/src/main/java/np/something/services/TagService.java b/src/main/java/np/something/services/TagService.java new file mode 100644 index 0000000..ab543e0 --- /dev/null +++ b/src/main/java/np/something/services/TagService.java @@ -0,0 +1,71 @@ +package np.something.services; + +import np.something.model.Album; +import np.something.model.Customer; +import np.something.model.Photo; +import np.something.model.Tag; +import np.something.repositories.AlbumRepository; +import np.something.repositories.CustomerRepository; +import np.something.repositories.PhotoRepository; +import np.something.repositories.TagRepository; +import np.something.util.validation.ValidatorUtil; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.stream.Stream; + +@Service +public class TagService { + private final AlbumRepository albumRepository; + private final CustomerRepository customerRepository; + private final PhotoRepository photoRepository; + private final TagRepository tagRepository; + private final ValidatorUtil validatorUtil; + + public TagService(AlbumRepository albumRepository, CustomerRepository customerRepository, PhotoRepository photoRepository, TagRepository tagRepository, ValidatorUtil validatorUtil) { + this.albumRepository = albumRepository; + this.customerRepository = customerRepository; + this.photoRepository = photoRepository; + this.tagRepository = tagRepository; + this.validatorUtil = validatorUtil; + } + + public Tag find(Long id) { + return tagRepository.findById(id).get(); + } + + public List findAll() { + return tagRepository.findAll(); + } + + public Tag add(String name) { + Tag tag = new Tag(name); + validatorUtil.validate(tag); + return tagRepository.save(tag); + } + + public Tag update(Long id, String name) { + Tag tag = tagRepository.findById(id).get(); + tag.setName(name); + validatorUtil.validate(tag); + return tagRepository.save(tag); + } + + public void delete(Long id) { + tagRepository.deleteById(id); + } + + public List tagsByTagPrefix(String prefix) { + return tagRepository.findTagsByTagPrefix(prefix); + } + + public List photosByTags(List ids) { + return tagRepository.findPhotosByTags(ids, ids.size()); + } + + public List customersPhotosByTag(Customer customer, Long tag_id) { + var albums = Stream.concat(customer.getAlbums().stream(), customer.getOwnedAlbums().stream()); + List photos = albums.flatMap(x -> x.getPhotos().stream()).toList(); + return photosByTags(List.of(tag_id)).stream().filter(photos::contains).toList(); + } +} diff --git a/src/main/java/np/something/util/error/AdviceController.java b/src/main/java/np/something/util/error/AdviceController.java index 2c58f64..16a8549 100644 --- a/src/main/java/np/something/util/error/AdviceController.java +++ b/src/main/java/np/something/util/error/AdviceController.java @@ -1,8 +1,6 @@ package np.something.util.error; -import np.something.Exceptions.CommentNotFoundException; import np.something.Exceptions.CustomerNotFoundException; -import np.something.Exceptions.PostNotFoundException; import np.something.util.validation.ValidationException; import org.springframework.context.support.DefaultMessageSourceResolvable; import org.springframework.http.HttpStatus; @@ -17,9 +15,7 @@ import java.util.stream.Collectors; @ControllerAdvice(annotations = RestController.class) public class AdviceController { @ExceptionHandler({ - CommentNotFoundException.class, CustomerNotFoundException.class, - PostNotFoundException.class, ValidationException.class }) public ResponseEntity handleException(Throwable e) { diff --git a/src/main/resources/templates/admin.html b/src/main/resources/templates/admin.html deleted file mode 100644 index 433b574..0000000 --- a/src/main/resources/templates/admin.html +++ /dev/null @@ -1,103 +0,0 @@ - - - - - -
-
-
-
-

Профили

-
-
-
-
- -
-
-
- -

Список профилей

-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
- - - -
- -
-
-
-
-
-
-
- - - - - -
- - - - - \ No newline at end of file diff --git a/src/main/resources/templates/album.html b/src/main/resources/templates/album.html new file mode 100644 index 0000000..a99fdb1 --- /dev/null +++ b/src/main/resources/templates/album.html @@ -0,0 +1,58 @@ + + + + + +
+
+
+
+
+
+
+ +
+
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+ +
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+ + + + \ No newline at end of file diff --git a/src/main/resources/templates/albums.html b/src/main/resources/templates/albums.html new file mode 100644 index 0000000..b0a94f3 --- /dev/null +++ b/src/main/resources/templates/albums.html @@ -0,0 +1,44 @@ + + + + + +
+
+
+
+
+
+
+ +
+
+ +
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/src/main/resources/templates/customers.html b/src/main/resources/templates/customers.html deleted file mode 100644 index 58c4666..0000000 --- a/src/main/resources/templates/customers.html +++ /dev/null @@ -1,83 +0,0 @@ - - - - - -
-
-
-
-

Профили

-
- -

Список профилей

-
-
-
-
-
-
-
-

Комментарии:

-
-
-
-
-
-
-
-

Нет комментариев

-

Посты:

-
-
-
-
-
-
-
-
-

Нет постов

-
-
- -
- -
-
-
-
-
-
- - - -
- - - - - \ No newline at end of file diff --git a/src/main/resources/templates/default.html b/src/main/resources/templates/default.html index cab96f9..129c16f 100644 --- a/src/main/resources/templates/default.html +++ b/src/main/resources/templates/default.html @@ -7,16 +7,15 @@ - Социальная сеть + Фотографии