From 1c00c86bc7c232da193a843345a32cc83893ae68 Mon Sep 17 00:00:00 2001 From: Tim <135014430+nagisa77@users.noreply.github.com> Date: Sun, 6 Jul 2025 01:56:35 +0800 Subject: [PATCH] feat: add draft post support --- open-isle-cli/src/views/NewPostPageView.vue | 53 ++++++++++++++- .../openisle/controller/DraftController.java | 67 +++++++++++++++++++ .../openisle/controller/PostController.java | 3 + src/main/java/com/openisle/model/Draft.java | 41 ++++++++++++ .../openisle/repository/DraftRepository.java | 12 ++++ .../com/openisle/service/DraftService.java | 58 ++++++++++++++++ 6 files changed, 232 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/openisle/controller/DraftController.java create mode 100644 src/main/java/com/openisle/model/Draft.java create mode 100644 src/main/java/com/openisle/repository/DraftRepository.java create mode 100644 src/main/java/com/openisle/service/DraftService.java diff --git a/open-isle-cli/src/views/NewPostPageView.vue b/open-isle-cli/src/views/NewPostPageView.vue index b78268ef4..27984844f 100644 --- a/open-isle-cli/src/views/NewPostPageView.vue +++ b/open-isle-cli/src/views/NewPostPageView.vue @@ -20,7 +20,7 @@ diff --git a/src/main/java/com/openisle/controller/DraftController.java b/src/main/java/com/openisle/controller/DraftController.java new file mode 100644 index 000000000..b47fa6ff2 --- /dev/null +++ b/src/main/java/com/openisle/controller/DraftController.java @@ -0,0 +1,67 @@ +package com.openisle.controller; + +import com.openisle.model.Draft; +import com.openisle.service.DraftService; +import lombok.Data; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.Authentication; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.stream.Collectors; + +@RestController +@RequestMapping("/api/drafts") +@RequiredArgsConstructor +public class DraftController { + private final DraftService draftService; + + @PostMapping + public ResponseEntity saveDraft(@RequestBody DraftRequest req, Authentication auth) { + Draft draft = draftService.saveDraft(auth.getName(), req.getCategoryId(), req.getTitle(), req.getContent(), req.getTagIds()); + return ResponseEntity.ok(toDto(draft)); + } + + @GetMapping("/me") + public ResponseEntity getMyDraft(Authentication auth) { + return draftService.getDraft(auth.getName()) + .map(d -> ResponseEntity.ok(toDto(d))) + .orElseGet(() -> ResponseEntity.noContent().build()); + } + + @DeleteMapping("/me") + public ResponseEntity deleteMyDraft(Authentication auth) { + draftService.deleteDraft(auth.getName()); + return ResponseEntity.ok().build(); + } + + private DraftDto toDto(Draft draft) { + DraftDto dto = new DraftDto(); + dto.setId(draft.getId()); + dto.setTitle(draft.getTitle()); + dto.setContent(draft.getContent()); + if (draft.getCategory() != null) { + dto.setCategoryId(draft.getCategory().getId()); + } + dto.setTagIds(draft.getTags().stream().map(com.openisle.model.Tag::getId).collect(Collectors.toList())); + return dto; + } + + @Data + private static class DraftRequest { + private String title; + private String content; + private Long categoryId; + private List tagIds; + } + + @Data + private static class DraftDto { + private Long id; + private String title; + private String content; + private Long categoryId; + private List tagIds; + } +} diff --git a/src/main/java/com/openisle/controller/PostController.java b/src/main/java/com/openisle/controller/PostController.java index 2450b7139..a140ae357 100644 --- a/src/main/java/com/openisle/controller/PostController.java +++ b/src/main/java/com/openisle/controller/PostController.java @@ -7,6 +7,7 @@ import com.openisle.service.CommentService; import com.openisle.service.PostService; import com.openisle.service.ReactionService; import com.openisle.service.CaptchaService; +import com.openisle.service.DraftService; import lombok.Data; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; @@ -26,6 +27,7 @@ public class PostController { private final CommentService commentService; private final ReactionService reactionService; private final CaptchaService captchaService; + private final DraftService draftService; @Value("${app.captcha.enabled:false}") private boolean captchaEnabled; @@ -40,6 +42,7 @@ public class PostController { } Post post = postService.createPost(auth.getName(), req.getCategoryId(), req.getTitle(), req.getContent(), req.getTagIds()); + draftService.deleteDraft(auth.getName()); return ResponseEntity.ok(toDto(post)); } diff --git a/src/main/java/com/openisle/model/Draft.java b/src/main/java/com/openisle/model/Draft.java new file mode 100644 index 000000000..32d46fd11 --- /dev/null +++ b/src/main/java/com/openisle/model/Draft.java @@ -0,0 +1,41 @@ +package com.openisle.model; + +import jakarta.persistence.*; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.HashSet; +import java.util.Set; + +@Entity +@Getter +@Setter +@NoArgsConstructor +@Table(name = "drafts", uniqueConstraints = { + @UniqueConstraint(columnNames = {"author_id"}) +}) +public class Draft { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String title; + + @Column(columnDefinition = "TEXT") + private String content; + + @ManyToOne(fetch = FetchType.LAZY, optional = false) + @JoinColumn(name = "author_id") + private User author; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "category_id") + private Category category; + + @ManyToMany(fetch = FetchType.LAZY) + @JoinTable(name = "draft_tags", + joinColumns = @JoinColumn(name = "draft_id"), + inverseJoinColumns = @JoinColumn(name = "tag_id")) + private Set tags = new HashSet<>(); +} diff --git a/src/main/java/com/openisle/repository/DraftRepository.java b/src/main/java/com/openisle/repository/DraftRepository.java new file mode 100644 index 000000000..536201796 --- /dev/null +++ b/src/main/java/com/openisle/repository/DraftRepository.java @@ -0,0 +1,12 @@ +package com.openisle.repository; + +import com.openisle.model.Draft; +import com.openisle.model.User; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface DraftRepository extends JpaRepository { + Optional findByAuthor(User author); + void deleteByAuthor(User author); +} diff --git a/src/main/java/com/openisle/service/DraftService.java b/src/main/java/com/openisle/service/DraftService.java new file mode 100644 index 000000000..804660724 --- /dev/null +++ b/src/main/java/com/openisle/service/DraftService.java @@ -0,0 +1,58 @@ +package com.openisle.service; + +import com.openisle.model.Category; +import com.openisle.model.Draft; +import com.openisle.model.Tag; +import com.openisle.model.User; +import com.openisle.repository.CategoryRepository; +import com.openisle.repository.DraftRepository; +import com.openisle.repository.TagRepository; +import com.openisle.repository.UserRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +@Service +@RequiredArgsConstructor +public class DraftService { + private final DraftRepository draftRepository; + private final UserRepository userRepository; + private final CategoryRepository categoryRepository; + private final TagRepository tagRepository; + + public Draft saveDraft(String username, Long categoryId, String title, String content, List tagIds) { + User user = userRepository.findByUsername(username) + .orElseThrow(() -> new IllegalArgumentException("User not found")); + Draft draft = draftRepository.findByAuthor(user).orElse(new Draft()); + draft.setAuthor(user); + draft.setTitle(title); + draft.setContent(content); + if (categoryId != null) { + Category category = categoryRepository.findById(categoryId) + .orElseThrow(() -> new IllegalArgumentException("Category not found")); + draft.setCategory(category); + } else { + draft.setCategory(null); + } + Set tags = new HashSet<>(); + if (tagIds != null && !tagIds.isEmpty()) { + tags.addAll(tagRepository.findAllById(tagIds)); + } + draft.setTags(tags); + return draftRepository.save(draft); + } + + public Optional getDraft(String username) { + return userRepository.findByUsername(username) + .flatMap(draftRepository::findByAuthor); + } + + public void deleteDraft(String username) { + userRepository.findByUsername(username) + .ifPresent(draftRepository::deleteByAuthor); + } +}