mirror of https://github.com/halo-dev/halo
Refactor related comment services
parent
388a37adfe
commit
ef2c2b2759
|
@ -4,10 +4,14 @@ import io.swagger.annotations.ApiOperation;
|
|||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import run.halo.app.model.dto.BaseCommentDTO;
|
||||
import run.halo.app.model.dto.JournalDTO;
|
||||
import run.halo.app.model.dto.JournalWithCmtCountDTO;
|
||||
import run.halo.app.model.entity.Journal;
|
||||
import run.halo.app.model.entity.JournalComment;
|
||||
import run.halo.app.model.params.JournalCommentParam;
|
||||
import run.halo.app.model.params.JournalParam;
|
||||
import run.halo.app.service.JournalCommentService;
|
||||
import run.halo.app.service.JournalService;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
@ -25,8 +29,12 @@ public class JournalController {
|
|||
|
||||
private final JournalService journalService;
|
||||
|
||||
public JournalController(JournalService journalService) {
|
||||
private final JournalCommentService journalCommentService;
|
||||
|
||||
public JournalController(JournalService journalService,
|
||||
JournalCommentService journalCommentService) {
|
||||
this.journalService = journalService;
|
||||
this.journalCommentService = journalCommentService;
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
|
@ -50,4 +58,10 @@ public class JournalController {
|
|||
return journalService.convertTo(createdJournal);
|
||||
}
|
||||
|
||||
@PostMapping("comments")
|
||||
@ApiOperation("Create a journal comment")
|
||||
public BaseCommentDTO createCommentBy(@RequestBody JournalCommentParam journalCommentParam) {
|
||||
JournalComment journalComment = journalCommentService.createBy(journalCommentParam);
|
||||
return journalCommentService.convertTo(journalComment);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import org.springframework.web.bind.annotation.PostMapping;
|
|||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import run.halo.app.model.dto.CommentDTO;
|
||||
import run.halo.app.model.dto.BaseCommentDTO;
|
||||
import run.halo.app.model.params.CommentParam;
|
||||
import run.halo.app.service.CommentService;
|
||||
|
||||
|
@ -27,7 +27,7 @@ public class CommentController {
|
|||
|
||||
@PostMapping
|
||||
@ApiOperation("Comments a post")
|
||||
public CommentDTO comment(@RequestBody CommentParam commentParam) {
|
||||
return new CommentDTO().convertFrom(commentService.createBy(commentParam));
|
||||
public BaseCommentDTO comment(@RequestBody CommentParam commentParam) {
|
||||
return commentService.convertTo(commentService.createBy(commentParam));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import lombok.ToString;
|
|||
@Data
|
||||
@ToString(callSuper = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Deprecated
|
||||
public class CommentDTO extends BaseCommentDTO {
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
package run.halo.app.model.entity;
|
||||
|
||||
import javax.persistence.DiscriminatorValue;
|
||||
import javax.persistence.Entity;
|
||||
|
||||
/**
|
||||
* Journal comment.
|
||||
*
|
||||
* @author johnniang
|
||||
* @date 19-4-25
|
||||
*/
|
||||
@Entity(name = "JournalComment")
|
||||
@DiscriminatorValue("2")
|
||||
public class JournalComment extends BaseComment {
|
||||
|
||||
}
|
|
@ -1,14 +1,10 @@
|
|||
package run.halo.app.model.params;
|
||||
|
||||
import lombok.Data;
|
||||
import run.halo.app.model.dto.base.InputConverter;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import run.halo.app.model.entity.Comment;
|
||||
|
||||
import javax.validation.constraints.Email;
|
||||
import javax.validation.constraints.Min;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
/**
|
||||
* Comment param.
|
||||
*
|
||||
|
@ -16,28 +12,8 @@ import javax.validation.constraints.Size;
|
|||
* @date 3/22/19
|
||||
*/
|
||||
@Data
|
||||
public class CommentParam implements InputConverter<Comment> {
|
||||
|
||||
@NotBlank(message = "Comment author name must not be blank")
|
||||
@Size(max = 50, message = "Length of comment author name must not be more than {max}")
|
||||
private String author;
|
||||
|
||||
@NotBlank(message = "Comment email must not be blank")
|
||||
@Email(message = "Comment email's format is incorrect")
|
||||
@Size(max = 255, message = "Length of comment email must not be more than {max}")
|
||||
private String email;
|
||||
|
||||
@Size(max = 127, message = "Length of comment author url must not be more than {max}")
|
||||
private String authorUrl;
|
||||
|
||||
@NotBlank(message = "Comment content must not be blank")
|
||||
@Size(max = 1023, message = "Length of comment content must not be more than {max}")
|
||||
private String content;
|
||||
|
||||
@Min(value = 1, message = "Post id must not be less than {value}")
|
||||
private Integer postId;
|
||||
|
||||
@Min(value = 0, message = "Comment parent id must not be less than {value}")
|
||||
private Long parentId = 0L;
|
||||
@ToString(callSuper = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class CommentParam extends BaseCommentParam<Comment> {
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
package run.halo.app.model.params;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import run.halo.app.model.entity.JournalComment;
|
||||
|
||||
/**
|
||||
* Journal comment param.
|
||||
*
|
||||
* @author johnniang
|
||||
* @date 3/22/19
|
||||
*/
|
||||
@Data
|
||||
@ToString(callSuper = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class JournalCommentParam extends BaseCommentParam<JournalComment> {
|
||||
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
package run.halo.app.model.vo;
|
||||
|
||||
import run.halo.app.model.dto.CommentDTO;
|
||||
import run.halo.app.model.dto.post.PostMinimalDTO;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import run.halo.app.model.dto.BaseCommentDTO;
|
||||
import run.halo.app.model.dto.post.PostMinimalDTO;
|
||||
|
||||
/**
|
||||
* Comment list with post vo.
|
||||
|
@ -14,7 +14,7 @@ import lombok.ToString;
|
|||
@Data
|
||||
@ToString
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class CommentWithPostVO extends CommentDTO {
|
||||
public class CommentWithPostVO extends BaseCommentDTO {
|
||||
|
||||
private PostMinimalDTO post;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
package run.halo.app.repository;
|
||||
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.lang.NonNull;
|
||||
import run.halo.app.model.entity.JournalComment;
|
||||
import run.halo.app.model.projection.CommentCountProjection;
|
||||
import run.halo.app.repository.base.BaseCommentRepository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Journal comment repository.
|
||||
*
|
||||
* @author johnniang
|
||||
* @date 19-4-24
|
||||
*/
|
||||
public interface JournalCommentRepository extends BaseCommentRepository<JournalComment> {
|
||||
|
||||
@Query("select new run.halo.app.model.projection.CommentCountProjection(count(comment.id), comment.postId) from JournalComment comment where comment.postId in ?1 group by comment.postId")
|
||||
@NonNull
|
||||
@Override
|
||||
List<CommentCountProjection> countByPostIds(@NonNull Iterable<Integer> postIds);
|
||||
}
|
|
@ -17,15 +17,6 @@ import java.util.List;
|
|||
*/
|
||||
public interface CommentService extends BaseCommentService<Comment> {
|
||||
|
||||
/**
|
||||
* Creates a comment by comment param.
|
||||
*
|
||||
* @param commentParam comment param must not be null
|
||||
* @return created comment
|
||||
*/
|
||||
@NonNull
|
||||
Comment createBy(@NonNull CommentParam commentParam);
|
||||
|
||||
/**
|
||||
* Converts to with post vo.
|
||||
*
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
package run.halo.app.service;
|
||||
|
||||
import run.halo.app.model.entity.JournalComment;
|
||||
import run.halo.app.service.base.BaseCommentService;
|
||||
|
||||
/**
|
||||
* Journal comment service interface.
|
||||
*
|
||||
* @author johnniang
|
||||
* @date 19-4-25
|
||||
*/
|
||||
public interface JournalCommentService extends BaseCommentService<JournalComment> {
|
||||
|
||||
}
|
|
@ -7,6 +7,7 @@ import org.springframework.lang.Nullable;
|
|||
import run.halo.app.model.dto.BaseCommentDTO;
|
||||
import run.halo.app.model.entity.BaseComment;
|
||||
import run.halo.app.model.enums.CommentStatus;
|
||||
import run.halo.app.model.params.BaseCommentParam;
|
||||
import run.halo.app.model.params.CommentQuery;
|
||||
import run.halo.app.model.vo.BaseCommentVO;
|
||||
import run.halo.app.model.vo.BaseCommentWithParentVO;
|
||||
|
@ -98,13 +99,23 @@ public interface BaseCommentService<COMMENT extends BaseComment> extends CrudSer
|
|||
Map<Integer, Long> countByPostIds(@Nullable Collection<Integer> postIds);
|
||||
|
||||
/**
|
||||
* Creates a comment by comment param.
|
||||
* Creates a comment by comment.
|
||||
*
|
||||
* @param COMMENT comment must not be null
|
||||
* @return created comment
|
||||
*/
|
||||
@NonNull
|
||||
COMMENT createBy(@NonNull COMMENT COMMENT);
|
||||
@Override
|
||||
COMMENT create(@NonNull COMMENT COMMENT);
|
||||
|
||||
/**
|
||||
* Creates a comment by comment param.
|
||||
*
|
||||
* @param commentParam commet param must not be null
|
||||
* @return created comment
|
||||
*/
|
||||
@NonNull
|
||||
COMMENT createBy(@NonNull BaseCommentParam<COMMENT> commentParam);
|
||||
|
||||
/**
|
||||
* Updates comment status.
|
||||
|
@ -142,4 +153,11 @@ public interface BaseCommentService<COMMENT extends BaseComment> extends CrudSer
|
|||
*/
|
||||
@NonNull
|
||||
Page<BaseCommentDTO> convertTo(@NonNull Page<COMMENT> commentPage);
|
||||
|
||||
/**
|
||||
* Target must exist.
|
||||
*
|
||||
* @param targetId target id must not be null
|
||||
*/
|
||||
void targetMustExist(@NonNull Integer targetId);
|
||||
}
|
||||
|
|
|
@ -19,9 +19,12 @@ import run.halo.app.event.comment.CommentReplyEvent;
|
|||
import run.halo.app.exception.NotFoundException;
|
||||
import run.halo.app.model.dto.BaseCommentDTO;
|
||||
import run.halo.app.model.entity.BaseComment;
|
||||
import run.halo.app.model.entity.User;
|
||||
import run.halo.app.model.enums.CommentStatus;
|
||||
import run.halo.app.model.params.BaseCommentParam;
|
||||
import run.halo.app.model.params.CommentQuery;
|
||||
import run.halo.app.model.projection.CommentCountProjection;
|
||||
import run.halo.app.model.properties.BlogProperties;
|
||||
import run.halo.app.model.properties.CommentProperties;
|
||||
import run.halo.app.model.support.CommentPage;
|
||||
import run.halo.app.model.vo.BaseCommentVO;
|
||||
|
@ -35,6 +38,7 @@ import run.halo.app.service.base.AbstractCrudService;
|
|||
import run.halo.app.service.base.BaseCommentService;
|
||||
import run.halo.app.utils.ServiceUtils;
|
||||
import run.halo.app.utils.ServletUtils;
|
||||
import run.halo.app.utils.ValidationUtils;
|
||||
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import java.util.*;
|
||||
|
@ -51,19 +55,15 @@ public abstract class BaseCommentServiceImpl<COMMENT extends BaseComment> extend
|
|||
|
||||
private final BaseCommentRepository<COMMENT> baseCommentRepository;
|
||||
|
||||
protected final PostRepository postRepository;
|
||||
|
||||
protected final OptionService optionService;
|
||||
|
||||
protected final ApplicationEventPublisher eventPublisher;
|
||||
|
||||
public BaseCommentServiceImpl(BaseCommentRepository<COMMENT> baseCommentRepository,
|
||||
PostRepository postRepository,
|
||||
OptionService optionService,
|
||||
ApplicationEventPublisher eventPublisher) {
|
||||
super(baseCommentRepository);
|
||||
this.baseCommentRepository = baseCommentRepository;
|
||||
this.postRepository = postRepository;
|
||||
this.optionService = optionService;
|
||||
this.eventPublisher = eventPublisher;
|
||||
}
|
||||
|
@ -206,12 +206,12 @@ public abstract class BaseCommentServiceImpl<COMMENT extends BaseComment> extend
|
|||
}
|
||||
|
||||
@Override
|
||||
public COMMENT createBy(COMMENT comment) {
|
||||
public COMMENT create(COMMENT comment) {
|
||||
Assert.notNull(comment, "Domain must not be null");
|
||||
|
||||
// Check post id
|
||||
if (!ServiceUtils.isEmptyId(comment.getPostId())) {
|
||||
postMustExist(comment.getPostId());
|
||||
targetMustExist(comment.getPostId());
|
||||
}
|
||||
|
||||
// Check parent id
|
||||
|
@ -239,7 +239,7 @@ public abstract class BaseCommentServiceImpl<COMMENT extends BaseComment> extend
|
|||
}
|
||||
|
||||
// Create comment
|
||||
COMMENT createdComment = create(comment);
|
||||
COMMENT createdComment = super.create(comment);
|
||||
|
||||
if (ServiceUtils.isEmptyId(createdComment.getParentId())) {
|
||||
if (authentication == null) {
|
||||
|
@ -254,6 +254,27 @@ public abstract class BaseCommentServiceImpl<COMMENT extends BaseComment> extend
|
|||
return createdComment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public COMMENT createBy(BaseCommentParam<COMMENT> commentParam) {
|
||||
Assert.notNull(commentParam, "Comment param must not be null");
|
||||
|
||||
// Check user login status and set this field
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
|
||||
if (authentication != null) {
|
||||
User user = authentication.getDetail().getUser();
|
||||
commentParam.setAuthor(StringUtils.isBlank(user.getNickname()) ? user.getUsername() : user.getNickname());
|
||||
commentParam.setEmail(user.getEmail());
|
||||
commentParam.setAuthorUrl(optionService.getByPropertyOfNullable(BlogProperties.BLOG_URL));
|
||||
}
|
||||
|
||||
// Validate the comment param manually
|
||||
ValidationUtils.validate(commentParam);
|
||||
|
||||
// Convert to comment
|
||||
return create(commentParam.convertTo());
|
||||
}
|
||||
|
||||
@Override
|
||||
public COMMENT updateStatus(Long commentId, CommentStatus status) {
|
||||
Assert.notNull(commentId, "Comment id must not be null");
|
||||
|
@ -300,18 +321,6 @@ public abstract class BaseCommentServiceImpl<COMMENT extends BaseComment> extend
|
|||
return new BaseCommentDTO().convertFrom(comment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Post must exist.
|
||||
*
|
||||
* @param postId post id must not be null
|
||||
*/
|
||||
protected void postMustExist(@NonNull Integer postId) {
|
||||
boolean isPostExist = postRepository.existsById(postId);
|
||||
if (!isPostExist) {
|
||||
throw new NotFoundException("The post with id " + postId + " was not found");
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
protected Specification<COMMENT> buildSpecByQuery(@NonNull CommentQuery commentQuery) {
|
||||
Assert.notNull(commentQuery, "Comment query must not be null");
|
||||
|
|
|
@ -1,28 +1,22 @@
|
|||
package run.halo.app.service.impl;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import run.halo.app.exception.NotFoundException;
|
||||
import run.halo.app.model.dto.post.PostMinimalDTO;
|
||||
import run.halo.app.model.entity.Comment;
|
||||
import run.halo.app.model.entity.Post;
|
||||
import run.halo.app.model.entity.User;
|
||||
import run.halo.app.model.params.CommentParam;
|
||||
import run.halo.app.model.properties.BlogProperties;
|
||||
import run.halo.app.model.vo.CommentWithPostVO;
|
||||
import run.halo.app.repository.CommentRepository;
|
||||
import run.halo.app.repository.PostRepository;
|
||||
import run.halo.app.security.authentication.Authentication;
|
||||
import run.halo.app.security.context.SecurityContextHolder;
|
||||
import run.halo.app.service.CommentService;
|
||||
import run.halo.app.service.OptionService;
|
||||
import run.halo.app.utils.ServiceUtils;
|
||||
import run.halo.app.utils.ValidationUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
@ -42,33 +36,15 @@ public class CommentServiceImpl extends BaseCommentServiceImpl<Comment> implemen
|
|||
|
||||
private final CommentRepository commentRepository;
|
||||
|
||||
private final PostRepository postRepository;
|
||||
|
||||
public CommentServiceImpl(CommentRepository commentRepository,
|
||||
PostRepository postRepository,
|
||||
OptionService optionService,
|
||||
ApplicationEventPublisher eventPublisher) {
|
||||
super(commentRepository, postRepository, optionService, eventPublisher);
|
||||
super(commentRepository, optionService, eventPublisher);
|
||||
this.commentRepository = commentRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Comment createBy(CommentParam commentParam) {
|
||||
Assert.notNull(commentParam, "Comment param must not be null");
|
||||
|
||||
// Check user login status and set this field
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
|
||||
if (authentication != null) {
|
||||
User user = authentication.getDetail().getUser();
|
||||
commentParam.setAuthor(StringUtils.isBlank(user.getNickname()) ? user.getUsername() : user.getNickname());
|
||||
commentParam.setEmail(user.getEmail());
|
||||
commentParam.setAuthorUrl(optionService.getByPropertyOfNullable(BlogProperties.BLOG_URL));
|
||||
}
|
||||
|
||||
// Validate the comment param manually
|
||||
ValidationUtils.validate(commentParam);
|
||||
|
||||
// Convert to comment
|
||||
return createBy(commentParam.convertTo());
|
||||
this.postRepository = postRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -102,4 +78,10 @@ public class CommentServiceImpl extends BaseCommentServiceImpl<Comment> implemen
|
|||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void targetMustExist(Integer postId) {
|
||||
if (!postRepository.existsById(postId)) {
|
||||
throw new NotFoundException("The post with id " + postId + " was not found");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
package run.halo.app.service.impl;
|
||||
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.stereotype.Service;
|
||||
import run.halo.app.exception.NotFoundException;
|
||||
import run.halo.app.model.entity.JournalComment;
|
||||
import run.halo.app.repository.JournalCommentRepository;
|
||||
import run.halo.app.repository.JournalRepository;
|
||||
import run.halo.app.service.JournalCommentService;
|
||||
import run.halo.app.service.OptionService;
|
||||
|
||||
/**
|
||||
* Journal comment service implementation.
|
||||
*
|
||||
* @author johnniang
|
||||
* @date 19-4-25
|
||||
*/
|
||||
@Service
|
||||
public class JournalCommentServiceImpl extends BaseCommentServiceImpl<JournalComment> implements JournalCommentService {
|
||||
|
||||
private final JournalCommentRepository journalCommentRepository;
|
||||
|
||||
private final JournalRepository journalRepository;
|
||||
|
||||
public JournalCommentServiceImpl(JournalCommentRepository journalCommentRepository,
|
||||
OptionService optionService,
|
||||
ApplicationEventPublisher eventPublisher, JournalRepository journalRepository) {
|
||||
super(journalCommentRepository, optionService, eventPublisher);
|
||||
this.journalCommentRepository = journalCommentRepository;
|
||||
this.journalRepository = journalRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void targetMustExist(Integer journalId) {
|
||||
if (!journalRepository.existsById(journalId)) {
|
||||
throw new NotFoundException("The journal with id " + journalId + " was not found");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,9 +2,10 @@ package run.halo.app.service.impl;
|
|||
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.stereotype.Service;
|
||||
import run.halo.app.exception.NotFoundException;
|
||||
import run.halo.app.model.entity.SheetComment;
|
||||
import run.halo.app.repository.PostRepository;
|
||||
import run.halo.app.repository.SheetCommentRepository;
|
||||
import run.halo.app.repository.SheetRepository;
|
||||
import run.halo.app.service.OptionService;
|
||||
import run.halo.app.service.SheetCommentService;
|
||||
|
||||
|
@ -19,11 +20,21 @@ public class SheetCommentServiceImpl extends BaseCommentServiceImpl<SheetComment
|
|||
|
||||
private final SheetCommentRepository sheetCommentRepository;
|
||||
|
||||
private final SheetRepository sheetRepository;
|
||||
|
||||
public SheetCommentServiceImpl(SheetCommentRepository sheetCommentRepository,
|
||||
PostRepository postRepository,
|
||||
OptionService optionService,
|
||||
ApplicationEventPublisher eventPublisher) {
|
||||
super(sheetCommentRepository, postRepository, optionService, eventPublisher);
|
||||
ApplicationEventPublisher eventPublisher,
|
||||
SheetRepository sheetRepository) {
|
||||
super(sheetCommentRepository, optionService, eventPublisher);
|
||||
this.sheetCommentRepository = sheetCommentRepository;
|
||||
this.sheetRepository = sheetRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void targetMustExist(Integer sheetId) {
|
||||
if (sheetRepository.existsById(sheetId)) {
|
||||
throw new NotFoundException("The sheet with id " + sheetId + " was not found");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue