Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented mod actions for posts #40

Merged
merged 1 commit into from
Nov 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@
import com.sublinks.sublinksapi.api.lemmy.v3.comment.models.EditComment;
import com.sublinks.sublinksapi.api.lemmy.v3.comment.models.GetComments;
import com.sublinks.sublinksapi.api.lemmy.v3.comment.models.GetCommentsResponse;
import com.sublinks.sublinksapi.api.lemmy.v3.comment.models.ListCommentReports;
import com.sublinks.sublinksapi.api.lemmy.v3.comment.models.ListCommentReportsResponse;
import com.sublinks.sublinksapi.api.lemmy.v3.comment.models.MarkCommentReplyAsRead;
import com.sublinks.sublinksapi.api.lemmy.v3.comment.services.LemmyCommentReportService;
import com.sublinks.sublinksapi.api.lemmy.v3.comment.services.LemmyCommentService;
Expand All @@ -23,7 +21,6 @@
import com.sublinks.sublinksapi.comment.dto.CommentReply;
import com.sublinks.sublinksapi.comment.dto.CommentReport;
import com.sublinks.sublinksapi.comment.enums.CommentSortType;
import com.sublinks.sublinksapi.comment.models.CommentReportSearchCriteria;
import com.sublinks.sublinksapi.comment.models.CommentSearchCriteria;
import com.sublinks.sublinksapi.comment.repositories.CommentReplyRepository;
import com.sublinks.sublinksapi.comment.repositories.CommentReportRepository;
Expand All @@ -33,11 +30,9 @@
import com.sublinks.sublinksapi.comment.services.CommentReplyService;
import com.sublinks.sublinksapi.comment.services.CommentReportService;
import com.sublinks.sublinksapi.comment.services.CommentService;
import com.sublinks.sublinksapi.community.dto.Community;
import com.sublinks.sublinksapi.language.dto.Language;
import com.sublinks.sublinksapi.language.repositories.LanguageRepository;
import com.sublinks.sublinksapi.person.dto.Person;
import com.sublinks.sublinksapi.person.enums.LinkPersonCommunityType;
import com.sublinks.sublinksapi.person.enums.ListingType;
import com.sublinks.sublinksapi.person.services.LinkPersonCommunityService;
import com.sublinks.sublinksapi.person.services.PersonService;
Expand Down Expand Up @@ -101,16 +96,27 @@ public CommentResponse create(@Valid @RequestBody final CreateComment createComm
final Person person = getPersonOrThrowUnauthorized(principal);
final Post post = postRepository.findById((long) createCommentForm.post_id())
.orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST));

if (post.isLocked()) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "post_locked");
}

if (post.isDeleted() || post.isRemoved()) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "post_not_found");
}

// Language
Optional<Language> language;
if (createCommentForm.language_id() != null) {
language = languageRepository.findById((long) createCommentForm.language_id());
} else {
language = personService.getPersonDefaultPostLanguage(person, post.getCommunity());
}

if (language.isEmpty()) {
throw new RuntimeException("No language selected");
}

final Comment comment = Comment.builder().person(person).isLocal(true)
.commentBody(createCommentForm.content()).activityPubId("").post(post)
.community(post.getCommunity()).language(language.get()).build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,39 @@
import com.sublinks.sublinksapi.api.lemmy.v3.authentication.JwtPerson;
import com.sublinks.sublinksapi.api.lemmy.v3.common.controllers.AbstractLemmyApiController;
import com.sublinks.sublinksapi.api.lemmy.v3.errorhandler.ApiError;
import com.sublinks.sublinksapi.api.lemmy.v3.modlog.models.ModLockPost;
import com.sublinks.sublinksapi.api.lemmy.v3.modlog.models.ModRemovePost;
import com.sublinks.sublinksapi.api.lemmy.v3.post.models.FeaturePost;
import com.sublinks.sublinksapi.api.lemmy.v3.post.models.ListPostReports;
import com.sublinks.sublinksapi.api.lemmy.v3.post.models.ListPostReportsResponse;
import com.sublinks.sublinksapi.api.lemmy.v3.post.models.PostReportResponse;
import com.sublinks.sublinksapi.api.lemmy.v3.post.models.PostReportView;
import com.sublinks.sublinksapi.api.lemmy.v3.post.models.PostResponse;
import com.sublinks.sublinksapi.api.lemmy.v3.post.models.ResolvePostReport;
import com.sublinks.sublinksapi.api.lemmy.v3.post.services.LemmyPostReportService;
import com.sublinks.sublinksapi.api.lemmy.v3.post.services.LemmyPostService;
import com.sublinks.sublinksapi.authorization.services.AuthorizationService;
import com.sublinks.sublinksapi.community.dto.Community;
import com.sublinks.sublinksapi.community.repositories.CommunityRepository;
import com.sublinks.sublinksapi.person.dto.Person;
import com.sublinks.sublinksapi.person.enums.LinkPersonCommunityType;
import com.sublinks.sublinksapi.person.services.LinkPersonCommunityService;
import com.sublinks.sublinksapi.post.dto.Post;
import com.sublinks.sublinksapi.post.dto.PostReport;
import com.sublinks.sublinksapi.post.models.PostReportSearchCriteria;
import com.sublinks.sublinksapi.post.repositories.PostReportRepository;
import com.sublinks.sublinksapi.post.repositories.PostRepository;
import com.sublinks.sublinksapi.post.services.PostReportService;
import com.sublinks.sublinksapi.post.services.PostService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;

import java.util.ArrayList;
import java.util.List;

import lombok.AllArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
Expand All @@ -58,27 +62,76 @@ public class PostModActionsController extends AbstractLemmyApiController {
private final LinkPersonCommunityService linkPersonCommunityService;
private final CommunityRepository communityRepository;
private final PostRepository postRepository;
private final LemmyPostService lemmyPostService;
private final PostService postService;

@Operation(summary = "A moderator remove for a post.")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK", content = {
@Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = PostResponse.class))}),
@ApiResponse(responseCode = "400", description = "Post Not Found", content = {
@Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = ApiError.class))})})
@PostMapping("remove")
PostResponse remove() {
PostResponse remove(@Valid @RequestBody final ModRemovePost modRemovePostForm,
final JwtPerson principal) {

final Person person = getPersonOrThrowUnauthorized(principal);

final Post post = postRepository.findById(modRemovePostForm.post_id())
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));

final boolean isAdmin = authorizationService.isAdmin(person);

if (!isAdmin) {
final boolean moderatesCommunity =
linkPersonCommunityService.hasLink(person, post.getCommunity(),
LinkPersonCommunityType.moderator) || linkPersonCommunityService.hasLink(person,
post.getCommunity(), LinkPersonCommunityType.owner);

throw new ResponseStatusException(HttpStatus.NOT_IMPLEMENTED);
if (!moderatesCommunity) {
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "not_a_moderator");
}
}

//@todo: Add it to the modlog
post.setRemoved(modRemovePostForm.removed());

return PostResponse.builder().post_view(lemmyPostService.postViewFromPost(post)).build();
}

@Operation(summary = "A moderator lock for a post.")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK", content = {
@Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = PostResponse.class))}),
@ApiResponse(responseCode = "400", description = "Post Not Found", content = {
@Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = ApiError.class))})})
@Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = ResponseStatusException.class))}),
@ApiResponse(responseCode = "403", description = "Forbidden", content = {
@Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = ResponseStatusException.class))})})
@PostMapping("lock")
PostResponse lock() {
PostResponse lock(@Valid @RequestBody final ModLockPost modLockPostForm, JwtPerson principal) {

final Person person = getPersonOrThrowUnauthorized(principal);

final Post post = postRepository.findById(modLockPostForm.post_id())
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "post_not_found"));

final boolean isAdmin = authorizationService.isAdmin(person);

throw new ResponseStatusException(HttpStatus.NOT_IMPLEMENTED);
if (!isAdmin) {
final boolean moderatesCommunity =
linkPersonCommunityService.hasLink(person, post.getCommunity(),
LinkPersonCommunityType.moderator) || linkPersonCommunityService.hasLink(person,
post.getCommunity(), LinkPersonCommunityType.owner);

if (!moderatesCommunity) {
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "not_a_moderator");
}
}

//@todo: Add it to the modlog
post.setLocked(modLockPostForm.locked());
System.out.println("post: " + post.isLocked());
postService.updatePost(post);

return PostResponse.builder().post_view(lemmyPostService.postViewFromPost(post)).build();
}

@Operation(summary = "A moderator feature for a post (Sticky).")
Expand All @@ -87,9 +140,42 @@ PostResponse lock() {
@ApiResponse(responseCode = "400", description = "Post Not Found", content = {
@Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = ApiError.class))})})
@PostMapping("feature")
PostResponse feature() {
PostResponse feature(@Valid @RequestBody FeaturePost featurePostForm, JwtPerson principal) {

final Person person = getPersonOrThrowUnauthorized(principal);

final Post post = postRepository.findById((long) featurePostForm.post_id())
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));

final boolean isAdmin = authorizationService.isAdmin(person);

if (!isAdmin) {
final boolean moderatesCommunity =
linkPersonCommunityService.hasLink(person, post.getCommunity(),
LinkPersonCommunityType.moderator) || linkPersonCommunityService.hasLink(person,
post.getCommunity(), LinkPersonCommunityType.owner);

if (!moderatesCommunity) {
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "not_a_moderator");
}
}
switch (featurePostForm.feature_type()) {
case Community:
post.setFeaturedInCommunity(featurePostForm.featured());
break;
case Local:
if (!isAdmin) {
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "not_a_admin");
}
post.setFeatured(featurePostForm.featured());
break;
default:
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "invalid_feature_type");
}

//@todo: Add it to the modlog

throw new ResponseStatusException(HttpStatus.NOT_IMPLEMENTED);
return PostResponse.builder().post_view(lemmyPostService.postViewFromPost(post)).build();
}

@Operation(summary = "Resolve a post report. Only a mod can do this.")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,9 @@ public interface PostMapper extends Converter<com.sublinks.sublinksapi.post.dto.
@Mapping(target = "creator_id", ignore = true)
@Mapping(target = "url", source = "post.linkUrl")
@Mapping(target = "thumbnail_url", source = "post.linkThumbnailUrl")
@Mapping(target = "published", source = "post.createdAt",
dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSX")
@Mapping(target = "published", source = "post.createdAt", dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSX")
@Mapping(target = "name", source = "post.title")
@Mapping(target = "locked", constant = "false")
@Mapping(target = "locked", source = "post.locked")
@Mapping(target = "local", constant = "true")
@Mapping(target = "language_id", source = "post.language.id")
@Mapping(target = "featured_local", source = "post.featured")
Expand All @@ -27,8 +26,7 @@ public interface PostMapper extends Converter<com.sublinks.sublinksapi.post.dto.
@Mapping(target = "embed_description", source = "post.linkDescription")
@Mapping(target = "community_id", source = "post.community.id")
@Mapping(target = "body", source = "post.postBody")
@Mapping(target = "updated", source = "post.updatedAt",
dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSX")
@Mapping(target = "updated", source = "post.updatedAt", dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSX")
@Mapping(target = "ap_id", source = "post.activityPubId")
Post convert(@Nullable com.sublinks.sublinksapi.post.dto.Post post);
}
9 changes: 4 additions & 5 deletions src/main/java/com/sublinks/sublinksapi/post/dto/Post.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,7 @@ public class Post implements AuthorizationEntityInterface {
private List<PostLike> postLikes;

@ManyToOne
@JoinTable(
name = "post_post_cross_post",
joinColumns = @JoinColumn(name = "post_id"),
inverseJoinColumns = @JoinColumn(name = "cross_post_id")
)
@JoinTable(name = "post_post_cross_post", joinColumns = @JoinColumn(name = "post_id"), inverseJoinColumns = @JoinColumn(name = "cross_post_id"))
CrossPost crossPost;

/**
Expand All @@ -95,6 +91,9 @@ public class Post implements AuthorizationEntityInterface {
@Column(nullable = false, name = "is_local")
private boolean isLocal;

@Column(nullable = false, name = "is_locked")
private boolean isLocked;

@Column(nullable = false, name = "is_featured")
private boolean isFeatured;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ CREATE TABLE `posts`
`is_deleted` TINYINT NOT NULL DEFAULT 0,
`is_removed` TINYINT NOT NULL DEFAULT 0,
`is_local` TINYINT NOT NULL DEFAULT 0,
`is_locked` TINYINT NOT NULL DEFAULT 0,
`community_id` BIGINT NOT NULL,
`is_featured` TINYINT NOT NULL DEFAULT 0,
`is_featured_in_community` TINYINT NOT NULL DEFAULT 0,
Expand Down