feat: Add blog category, blog, and tag controllers with CRUD operations

This commit is contained in:
Wini_Fy
2026-02-02 17:01:42 +07:00
parent d1b931d547
commit f531cc4a92
3 changed files with 1024 additions and 0 deletions

View File

@@ -0,0 +1,231 @@
const BlogCategory = require('../models/blogCategory');
// -------------------- Admin Controllers --------------------
// Display category management page
exports.index = async (req, res) => {
try {
const categories = await BlogCategory.find()
.sort({ name: 1 })
.lean();
res.render('admin/blog/categories/index', {
layout: 'layouts/main',
title: 'Blog Categories',
categories,
currentPath: req.path,
user: req.session.user
});
} catch (err) {
console.error('Category index error:', err);
req.flash('error_msg', 'Error loading categories');
res.redirect('/admin/dashboard');
}
};
// Show create category form
exports.create = async (req, res) => {
try {
res.render('admin/blog/categories/create', {
layout: 'layouts/main',
title: 'Create New Category',
currentPath: req.path,
user: req.session.user
});
} catch (err) {
console.error('Category create form error:', err);
req.flash('error_msg', 'Error loading create form');
res.redirect('/admin/blog/categories');
}
};
// Store new category
exports.store = async (req, res) => {
try {
const {
name,
description,
isActive
} = req.body;
// Generate slug
const slug = name
.toLowerCase()
.replace(/[^a-z0-9\s-]/g, '')
.replace(/\s+/g, '-')
.replace(/-+/g, '-')
.trim('-');
// Check if slug exists
const existingCategory = await BlogCategory.findOne({ slug });
if (existingCategory) {
req.flash('error_msg', 'A category with this name already exists');
return res.redirect('/admin/blog/categories/create');
}
// Create category data
const categoryData = {
name,
slug,
description,
isActive: isActive === 'on'
};
// Create category
const category = new BlogCategory(categoryData);
await category.save();
req.flash('success_msg', 'Category created successfully');
res.redirect('/admin/blog/categories');
} catch (err) {
console.error('Category store error:', err);
req.flash('error_msg', 'Error creating category');
res.redirect('/admin/blog/categories/create');
}
};
// Show edit category form
exports.edit = async (req, res) => {
try {
const category = await BlogCategory.findById(req.params.id);
if (!category) {
req.flash('error_msg', 'Category not found');
return res.redirect('/admin/blog/categories');
}
res.render('admin/blog/categories/edit', {
layout: 'layouts/main',
title: 'Edit Category',
category,
currentPath: req.path,
user: req.session.user
});
} catch (err) {
console.error('Category edit form error:', err);
req.flash('error_msg', 'Error loading category');
res.redirect('/admin/blog/categories');
}
};
// Update category
exports.update = async (req, res) => {
try {
const category = await BlogCategory.findById(req.params.id);
if (!category) {
req.flash('error_msg', 'Category not found');
return res.redirect('/admin/blog/categories');
}
const {
name,
description,
isActive
} = req.body;
// Update category data
category.name = name;
category.description = description;
category.isActive = isActive === 'on';
// Generate new slug if name changed
const newSlug = name
.toLowerCase()
.replace(/[^a-z0-9\s-]/g, '')
.replace(/\s+/g, '-')
.replace(/-+/g, '-')
.trim('-');
if (newSlug !== category.slug) {
const existingCategory = await BlogCategory.findOne({
slug: newSlug,
_id: { $ne: category._id }
});
if (existingCategory) {
req.flash('error_msg', 'A category with this name already exists');
return res.redirect(`/admin/blog/categories/${category._id}/edit`);
}
category.slug = newSlug;
}
await category.save();
req.flash('success_msg', 'Category updated successfully');
res.redirect('/admin/blog/categories');
} catch (err) {
console.error('Category update error:', err);
req.flash('error_msg', 'Error updating category');
res.redirect(`/admin/blog/categories/${req.params.id}/edit`);
}
};
// Delete category
exports.destroy = async (req, res) => {
try {
const category = await BlogCategory.findById(req.params.id);
if (!category) {
req.flash('error_msg', 'Category not found');
return res.redirect('/admin/blog/categories');
}
// Check if category has posts
const Blog = require('../models/blog');
const postCount = await Blog.countDocuments({ category: { $in: [category.name] } });
if (postCount > 0) {
req.flash('error_msg', 'Cannot delete category that has blog posts');
return res.redirect('/admin/blog/categories');
}
await BlogCategory.findByIdAndDelete(req.params.id);
req.flash('success_msg', 'Category deleted successfully');
res.redirect('/admin/blog/categories');
} catch (err) {
console.error('Category delete error:', err);
req.flash('error_msg', 'Error deleting category');
res.redirect('/admin/blog/categories');
}
};
// -------------------- Public API Controllers --------------------
// Get all active categories
exports.api = async (req, res) => {
try {
const categories = await BlogCategory.getActive();
// Update post counts
for (const category of categories) {
await category.updatePostCount();
}
res.json(categories);
} catch (err) {
console.error('Categories API error:', err);
res.status(500).json({ error: 'Error loading categories' });
}
};
// Get category by slug
exports.apiShow = async (req, res) => {
try {
const category = await BlogCategory.findOne({
slug: req.params.slug,
isActive: true
}).lean();
if (!category) {
return res.status(404).json({ error: 'Category not found' });
}
res.json(category);
} catch (err) {
console.error('Category show API error:', err);
res.status(500).json({ error: 'Error loading category' });
}
};
module.exports = exports;