109 lines
3 KiB
TypeScript
109 lines
3 KiB
TypeScript
import { Article } from "../../models/Article";
|
|
import { requireAuth } from "../../utils/auth";
|
|
import { Types } from "mongoose";
|
|
|
|
export default defineEventHandler(async (event) => {
|
|
const slug = getRouterParam(event, "slug");
|
|
const user = await requireAuth(event);
|
|
const body = await readBody(event);
|
|
|
|
if (!slug) {
|
|
throw createError({
|
|
statusCode: 400,
|
|
statusMessage: "Slug is required",
|
|
});
|
|
}
|
|
|
|
// Find article
|
|
const article = await Article.findOne({ slug });
|
|
|
|
if (!article) {
|
|
throw createError({
|
|
statusCode: 404,
|
|
statusMessage: "Article not found",
|
|
});
|
|
}
|
|
|
|
// Check permissions
|
|
const isAuthor = article.author.toString() === user.userId;
|
|
const isAdmin = user.permissions.canAdmin;
|
|
const isModerator = user.permissions.canModerate;
|
|
const canEdit = user.permissions.canEdit;
|
|
|
|
if (!isAuthor && !isAdmin && !isModerator) {
|
|
throw createError({
|
|
statusCode: 403,
|
|
statusMessage: "You do not have permission to edit this article",
|
|
});
|
|
}
|
|
|
|
// Check if article is locked by another user
|
|
if (article.lockedBy && article.lockedBy.toString() !== user.userId) {
|
|
const lockExpired =
|
|
article.lockedAt &&
|
|
new Date().getTime() - article.lockedAt.getTime() > 30 * 60 * 1000; // 30 minutes
|
|
|
|
if (!lockExpired) {
|
|
throw createError({
|
|
statusCode: 423,
|
|
statusMessage: "Article is currently being edited by another user",
|
|
});
|
|
}
|
|
}
|
|
|
|
// Update fields
|
|
if (body.title) article.title = body.title;
|
|
if (body.description) article.description = body.description;
|
|
if (body.content) {
|
|
// Add to revision history
|
|
article.revisions.push({
|
|
content: body.content,
|
|
author: new Types.ObjectId(user.userId),
|
|
message: body.revisionMessage || "Content updated",
|
|
createdAt: new Date(),
|
|
});
|
|
article.content = body.content;
|
|
}
|
|
if (body.category) article.category = body.category;
|
|
if (body.tags) article.tags = body.tags;
|
|
if (body.accessLevel && (isAdmin || isModerator)) {
|
|
article.accessLevel = body.accessLevel;
|
|
}
|
|
if (body.cohorts && (isAdmin || isModerator)) {
|
|
article.cohorts = body.cohorts;
|
|
}
|
|
if (body.status) {
|
|
article.status = body.status;
|
|
if (body.status === "published" && !article.publishedAt) {
|
|
article.publishedAt = new Date();
|
|
}
|
|
}
|
|
|
|
// Add contributor if not already listed
|
|
const userObjectId = new Types.ObjectId(user.userId);
|
|
if (!article.contributors.some((c: any) => c.toString() === user.userId)) {
|
|
article.contributors.push(userObjectId);
|
|
}
|
|
|
|
// Clear lock
|
|
article.lockedBy = undefined;
|
|
article.lockedAt = undefined;
|
|
|
|
// Save changes
|
|
try {
|
|
await article.save();
|
|
|
|
return {
|
|
success: true,
|
|
slug: article.slug,
|
|
message: "Article updated successfully",
|
|
revision: article.revisions.length,
|
|
};
|
|
} catch (error) {
|
|
console.error("Error updating article:", error);
|
|
throw createError({
|
|
statusCode: 500,
|
|
statusMessage: "Failed to update article",
|
|
});
|
|
}
|
|
});
|