forked from UKSOURCE/cms.hailearning.edu.vn
feat:Add blog management page and enhance admin layout
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
const BlogTag = require('../models/blogTag');
|
||||
const slugify = require('slugify');
|
||||
|
||||
// -------------------- Admin Controllers --------------------
|
||||
|
||||
@@ -48,12 +49,11 @@ exports.store = async (req, res) => {
|
||||
} = req.body;
|
||||
|
||||
// Generate slug
|
||||
const slug = name
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9\s-]/g, '')
|
||||
.replace(/\s+/g, '-')
|
||||
.replace(/-+/g, '-')
|
||||
.trim('-');
|
||||
const slug = slugify(name, {
|
||||
lower: true,
|
||||
strict: true,
|
||||
locale: 'vi'
|
||||
});
|
||||
|
||||
// Check if slug exists
|
||||
const existingTag = await BlogTag.findOne({ slug });
|
||||
@@ -126,12 +126,11 @@ exports.update = async (req, res) => {
|
||||
tag.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('-');
|
||||
const newSlug = slugify(name, {
|
||||
lower: true,
|
||||
strict: true,
|
||||
locale: 'vi'
|
||||
});
|
||||
|
||||
if (newSlug !== tag.slug) {
|
||||
const existingTag = await BlogTag.findOne({
|
||||
@@ -162,6 +161,14 @@ exports.destroy = async (req, res) => {
|
||||
const tag = await BlogTag.findById(req.params.id);
|
||||
|
||||
if (!tag) {
|
||||
// Check if it's an AJAX request
|
||||
const isAjax = req.xhr || req.headers['accept']?.includes('application/json') || req.headers['content-type']?.includes('application/json');
|
||||
if (isAjax) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: 'Tag not found'
|
||||
});
|
||||
}
|
||||
req.flash('error_msg', 'Tag not found');
|
||||
return res.redirect('/admin/blog/tags');
|
||||
}
|
||||
@@ -171,16 +178,44 @@ exports.destroy = async (req, res) => {
|
||||
const postCount = await Blog.countDocuments({ tags: { $in: [tag.name] } });
|
||||
|
||||
if (postCount > 0) {
|
||||
// Check if it's an AJAX request
|
||||
const isAjax = req.xhr || req.headers['accept']?.includes('application/json') || req.headers['content-type']?.includes('application/json');
|
||||
if (isAjax) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: 'Cannot delete tag that is used in blog posts'
|
||||
});
|
||||
}
|
||||
req.flash('error_msg', 'Cannot delete tag that is used in blog posts');
|
||||
return res.redirect('/admin/blog/tags');
|
||||
}
|
||||
|
||||
await BlogTag.findByIdAndDelete(req.params.id);
|
||||
|
||||
// Check if it's an AJAX request
|
||||
const isAjax = req.xhr || req.headers['accept']?.includes('application/json') || req.headers['content-type']?.includes('application/json');
|
||||
if (isAjax) {
|
||||
return res.json({
|
||||
success: true,
|
||||
message: 'Tag deleted successfully'
|
||||
});
|
||||
}
|
||||
|
||||
req.flash('success_msg', 'Tag deleted successfully');
|
||||
res.redirect('/admin/blog/tags');
|
||||
} catch (err) {
|
||||
console.error('Tag delete error:', err);
|
||||
|
||||
// Check if it's an AJAX request
|
||||
const isAjax = req.xhr || req.headers['accept']?.includes('application/json') || req.headers['content-type']?.includes('application/json');
|
||||
if (isAjax) {
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: 'Error deleting tag',
|
||||
error: err.message || 'Error deleting tag'
|
||||
});
|
||||
}
|
||||
|
||||
req.flash('error_msg', 'Error deleting tag');
|
||||
res.redirect('/admin/blog/tags');
|
||||
}
|
||||
@@ -198,10 +233,18 @@ exports.api = async (req, res) => {
|
||||
await tag.updatePostCount();
|
||||
}
|
||||
|
||||
res.json(tags);
|
||||
res.json({
|
||||
success: true,
|
||||
message: 'Tags fetched successfully',
|
||||
data: tags
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('Tags API error:', err);
|
||||
res.status(500).json({ error: 'Error loading tags' });
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: 'Error loading tags',
|
||||
error: err.message || 'Error loading tags'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -210,10 +253,19 @@ exports.apiPopular = async (req, res) => {
|
||||
try {
|
||||
const limit = parseInt(req.query.limit) || 10;
|
||||
const tags = await BlogTag.getPopular(limit);
|
||||
res.json(tags);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: 'Popular tags fetched successfully',
|
||||
data: tags
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('Popular tags API error:', err);
|
||||
res.status(500).json({ error: 'Error loading popular tags' });
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: 'Error loading popular tags',
|
||||
error: err.message || 'Error loading popular tags'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -226,13 +278,80 @@ exports.apiShow = async (req, res) => {
|
||||
}).lean();
|
||||
|
||||
if (!tag) {
|
||||
return res.status(404).json({ error: 'Tag not found' });
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: 'Tag not found'
|
||||
});
|
||||
}
|
||||
|
||||
res.json(tag);
|
||||
res.json({
|
||||
success: true,
|
||||
message: 'Tag fetched successfully',
|
||||
data: tag
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('Tag show API error:', err);
|
||||
res.status(500).json({ error: 'Error loading tag' });
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: 'Error loading tag',
|
||||
error: err.message || 'Error loading tag'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Quick create tag (for inline creation in blog form)
|
||||
exports.quickCreate = async (req, res) => {
|
||||
try {
|
||||
const { name } = req.body;
|
||||
|
||||
if (!name || !name.trim()) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: 'Tag name is required'
|
||||
});
|
||||
}
|
||||
|
||||
const tagName = name.trim();
|
||||
|
||||
// Generate slug
|
||||
const slug = slugify(tagName, {
|
||||
lower: true,
|
||||
strict: true,
|
||||
locale: 'vi'
|
||||
});
|
||||
|
||||
// Check if tag already exists
|
||||
let tag = await BlogTag.findOne({ slug });
|
||||
|
||||
if (tag) {
|
||||
return res.json({
|
||||
success: true,
|
||||
message: 'Tag already exists',
|
||||
data: tag.toObject()
|
||||
});
|
||||
}
|
||||
|
||||
// Create new tag
|
||||
tag = new BlogTag({
|
||||
name: tagName,
|
||||
slug,
|
||||
isActive: true
|
||||
});
|
||||
|
||||
await tag.save();
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: 'Tag created successfully',
|
||||
data: tag.toObject()
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('Quick create tag error:', err);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: 'Error creating tag',
|
||||
error: err.message || 'Error creating tag'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user