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 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ 清空
+
+
+
+ md格式优化
+
+
+ 取消
+
+
更新
+
更新中...
+
+
+
+
+
+
+
+
+
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)