From 7d29b7d6e81ba16a9f44e8f879db88e6fe7a6d9a Mon Sep 17 00:00:00 2001 From: Tim <135014430+nagisa77@users.noreply.github.com> Date: Tue, 22 Jul 2025 18:09:59 +0800 Subject: [PATCH] feat: implement post editing --- open-isle-cli/src/router/index.js | 6 + open-isle-cli/src/views/EditPostPageView.vue | 339 ++++++++++++++++++ open-isle-cli/src/views/PostPageView.vue | 6 + .../openisle/controller/PostController.java | 8 + .../com/openisle/service/PostService.java | 33 ++ 5 files changed, 392 insertions(+) create mode 100644 open-isle-cli/src/views/EditPostPageView.vue diff --git a/open-isle-cli/src/router/index.js b/open-isle-cli/src/router/index.js index 877f6da9d..2239d8a1a 100644 --- a/open-isle-cli/src/router/index.js +++ b/open-isle-cli/src/router/index.js @@ -8,6 +8,7 @@ import LoginPageView from '../views/LoginPageView.vue' import SignupPageView from '../views/SignupPageView.vue' import SignupReasonPageView from '../views/SignupReasonPageView.vue' import NewPostPageView from '../views/NewPostPageView.vue' +import EditPostPageView from '../views/EditPostPageView.vue' import SettingsPageView from '../views/SettingsPageView.vue' import ProfileView from '../views/ProfileView.vue' import NotFoundPageView from '../views/NotFoundPageView.vue' @@ -41,6 +42,11 @@ const routes = [ name: 'new-post', component: NewPostPageView }, + { + path: '/posts/:id/edit', + name: 'edit-post', + component: EditPostPageView + }, { path: '/posts/:id', name: 'post', diff --git a/open-isle-cli/src/views/EditPostPageView.vue b/open-isle-cli/src/views/EditPostPageView.vue new file mode 100644 index 000000000..58358983c --- /dev/null +++ b/open-isle-cli/src/views/EditPostPageView.vue @@ -0,0 +1,339 @@ + + + + + diff --git a/open-isle-cli/src/views/PostPageView.vue b/open-isle-cli/src/views/PostPageView.vue index fca654538..dbadd3165 100644 --- a/open-isle-cli/src/views/PostPageView.vue +++ b/open-isle-cli/src/views/PostPageView.vue @@ -155,6 +155,7 @@ export default { const articleMenuItems = computed(() => { const items = [] if (isAuthor.value || isAdmin.value) { + items.push({ text: '编辑文章', onClick: () => editPost() }) items.push({ text: '删除文章', color: 'red', onClick: () => deletePost() }) } if (isAdmin.value && status.value === 'PENDING') { @@ -394,6 +395,10 @@ export default { } } + const editPost = () => { + router.push(`/posts/${postId}/edit`) + } + const deletePost = async () => { const token = getToken() if (!token) { @@ -506,6 +511,7 @@ export default { status, isAdmin, approvePost, + editPost, onCommentDeleted, deletePost, rejectPost, diff --git a/src/main/java/com/openisle/controller/PostController.java b/src/main/java/com/openisle/controller/PostController.java index 61802835b..e77a3d974 100644 --- a/src/main/java/com/openisle/controller/PostController.java +++ b/src/main/java/com/openisle/controller/PostController.java @@ -50,6 +50,14 @@ public class PostController { return ResponseEntity.ok(toDto(post)); } + @PutMapping("/{id}") + public ResponseEntity updatePost(@PathVariable Long id, @RequestBody PostRequest req, + Authentication auth) { + Post post = postService.updatePost(id, auth.getName(), req.getCategoryId(), + req.getTitle(), req.getContent(), req.getTagIds()); + return ResponseEntity.ok(toDto(post)); + } + @DeleteMapping("/{id}") public void deletePost(@PathVariable Long id, Authentication auth) { postService.deletePost(id, auth.getName()); diff --git a/src/main/java/com/openisle/service/PostService.java b/src/main/java/com/openisle/service/PostService.java index 5eacdb3e8..b203305f1 100644 --- a/src/main/java/com/openisle/service/PostService.java +++ b/src/main/java/com/openisle/service/PostService.java @@ -347,6 +347,39 @@ public class PostService { return post; } + @org.springframework.transaction.annotation.Transactional + public Post updatePost(Long id, + String username, + Long categoryId, + String title, + String content, + java.util.List tagIds) { + if (tagIds == null || tagIds.isEmpty()) { + throw new IllegalArgumentException("At least one tag required"); + } + if (tagIds.size() > 2) { + throw new IllegalArgumentException("At most two tags allowed"); + } + Post post = postRepository.findById(id) + .orElseThrow(() -> new com.openisle.exception.NotFoundException("Post not found")); + User user = userRepository.findByUsername(username) + .orElseThrow(() -> new com.openisle.exception.NotFoundException("User not found")); + if (!user.getId().equals(post.getAuthor().getId()) && user.getRole() != Role.ADMIN) { + throw new IllegalArgumentException("Unauthorized"); + } + Category category = categoryRepository.findById(categoryId) + .orElseThrow(() -> new IllegalArgumentException("Category not found")); + java.util.List tags = tagRepository.findAllById(tagIds); + if (tags.isEmpty()) { + throw new IllegalArgumentException("Tag not found"); + } + post.setTitle(title); + post.setContent(content); + post.setCategory(category); + post.setTags(new java.util.HashSet<>(tags)); + return postRepository.save(post); + } + @org.springframework.transaction.annotation.Transactional public void deletePost(Long id, String username) { Post post = postRepository.findById(id)