forked from UKSOURCE/cms.hailearning.edu.vn
first commit
This commit is contained in:
165
controllers/qualificationController.js
Normal file
165
controllers/qualificationController.js
Normal file
@@ -0,0 +1,165 @@
|
||||
const path = require('path');
|
||||
const Qualification = require('../models/qualification');
|
||||
const Department = require('../models/department');
|
||||
const Level = require('../models/level');
|
||||
const writeAuditLog = require('../audit/writeAuditLog');
|
||||
const AUDIT_ACTIONS = require('../constants/auditAction');
|
||||
|
||||
function normalizePath(filePath) {
|
||||
if (!filePath) return undefined;
|
||||
return path.basename(filePath.replace(/\\/g, '/'));
|
||||
}
|
||||
|
||||
// GET /admin/qualification
|
||||
exports.index = async (req, res) => {
|
||||
try {
|
||||
const { search, status } = req.query;
|
||||
const filter = {};
|
||||
if (search) {
|
||||
filter.$or = [
|
||||
{ qualification_number: { $regex: search, $options: 'i' } },
|
||||
{ student_name: { $regex: search, $options: 'i' } }
|
||||
];
|
||||
}
|
||||
if (status) filter.status = status;
|
||||
|
||||
const [qualifications, departments, levels] = await Promise.all([
|
||||
Qualification.find(filter).populate('department level').sort({ createdAt: -1 }),
|
||||
Department.find(), Level.find()
|
||||
]);
|
||||
|
||||
res.render('admin/qualification/index', {
|
||||
qualifications, departments, levels, query: req.query,
|
||||
user: req.session.user, layout: 'layouts/admin', title: 'Qualifications'
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
req.flash('error', 'Error loading qualifications');
|
||||
res.redirect('/admin/dashboard');
|
||||
}
|
||||
};
|
||||
|
||||
// GET /admin/qualification/create
|
||||
exports.createForm = async (req, res) => {
|
||||
try {
|
||||
const [departments, levels] = await Promise.all([Department.find(), Level.find()]);
|
||||
res.render('admin/qualification/create', {
|
||||
departments, levels, user: req.session.user,
|
||||
layout: 'layouts/admin', title: 'Create Qualification'
|
||||
});
|
||||
} catch (err) {
|
||||
req.flash('error', 'Error'); res.redirect('/admin/qualification');
|
||||
}
|
||||
};
|
||||
|
||||
// POST /admin/qualification/create
|
||||
exports.create = async (req, res) => {
|
||||
try {
|
||||
const data = { ...req.body };
|
||||
const imgPath = req.files?.degree_image?.[0]?.path;
|
||||
if (imgPath) data.degree_image = normalizePath(imgPath);
|
||||
|
||||
const qual = new Qualification(data);
|
||||
await qual.save();
|
||||
await writeAuditLog({ model: 'Qualification', documentId: qual._id, action: AUDIT_ACTIONS.CREATE_QUALIFICATION, before: null, after: qual.toObject(), req });
|
||||
|
||||
req.flash('success', 'Qualification created');
|
||||
res.redirect('/admin/qualification');
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
try {
|
||||
const [departments, levels] = await Promise.all([Department.find(), Level.find()]);
|
||||
res.render('admin/qualification/create', {
|
||||
error: err.message, formData: req.body, departments, levels,
|
||||
user: req.session.user, layout: 'layouts/admin', title: 'Create Qualification'
|
||||
});
|
||||
} catch { req.flash('error', err.message); res.redirect('/admin/qualification'); }
|
||||
}
|
||||
};
|
||||
|
||||
// GET /admin/qualification/:id/edit
|
||||
exports.editForm = async (req, res) => {
|
||||
try {
|
||||
const qual = await Qualification.findById(req.params.id).populate('department level');
|
||||
if (!qual) { req.flash('error', 'Not found'); return res.redirect('/admin/qualification'); }
|
||||
const [departments, levels] = await Promise.all([Department.find(), Level.find()]);
|
||||
res.render('admin/qualification/edit', {
|
||||
qual, departments, levels, user: req.session.user,
|
||||
layout: 'layouts/admin', title: 'Edit Qualification'
|
||||
});
|
||||
} catch (err) {
|
||||
req.flash('error', 'Error'); res.redirect('/admin/qualification');
|
||||
}
|
||||
};
|
||||
|
||||
// POST /admin/qualification/:id/edit
|
||||
exports.update = async (req, res) => {
|
||||
try {
|
||||
const qual = await Qualification.findById(req.params.id);
|
||||
if (!qual) { req.flash('error', 'Not found'); return res.redirect('/admin/qualification'); }
|
||||
const before = qual.toObject();
|
||||
|
||||
const fields = ['qualification_number','student_name','program_name','department','level',
|
||||
'issued_date','status','passport_number','address','topic_name','topic_short_desc'];
|
||||
fields.forEach(f => { if (req.body[f] !== undefined) qual[f] = req.body[f]; });
|
||||
|
||||
const imgPath = req.files?.degree_image?.[0]?.path;
|
||||
if (imgPath) qual.degree_image = normalizePath(imgPath);
|
||||
|
||||
await qual.save();
|
||||
await writeAuditLog({ model: 'Qualification', documentId: qual._id, action: AUDIT_ACTIONS.UPDATE_QUALIFICATION, before, after: qual.toObject(), req });
|
||||
|
||||
req.flash('success', 'Qualification updated');
|
||||
res.redirect('/admin/qualification');
|
||||
} catch (err) {
|
||||
req.flash('error', err.message); res.redirect('back');
|
||||
}
|
||||
};
|
||||
|
||||
// POST /admin/qualification/:id/delete
|
||||
exports.destroy = async (req, res) => {
|
||||
try {
|
||||
const qual = await Qualification.findById(req.params.id);
|
||||
if (!qual) { req.flash('error', 'Not found'); return res.redirect('/admin/qualification'); }
|
||||
await writeAuditLog({ model: 'Qualification', documentId: qual._id, action: AUDIT_ACTIONS.DELETE_QUALIFICATION, before: qual.toObject(), after: null, req });
|
||||
await qual.deleteOne();
|
||||
req.flash('success', 'Qualification deleted');
|
||||
res.redirect('/admin/qualification');
|
||||
} catch (err) {
|
||||
req.flash('error', 'Error deleting'); res.redirect('/admin/qualification');
|
||||
}
|
||||
};
|
||||
|
||||
// GET /api/verify-degree/:degree_id?api_key=xxx
|
||||
exports.apiVerify = async (req, res) => {
|
||||
try {
|
||||
const qual = await Qualification.findOne({
|
||||
qualification_number: { $regex: new RegExp('^' + req.params.degree_id + '$', 'i') }
|
||||
}).populate('department level');
|
||||
|
||||
if (!qual) return res.status(404).json({ error: 'Degree not found' });
|
||||
if (qual.status === 'revoked') return res.status(404).json({ error: 'Degree has been revoked' });
|
||||
|
||||
const baseUrl = `${req.protocol}://${req.get('host')}`;
|
||||
const buildUrl = (f) => f ? [`${baseUrl}/secure-files/${path.basename(f)}?api_key=${req.query.api_key}`] : undefined;
|
||||
|
||||
const response = {
|
||||
full_name: qual.student_name,
|
||||
program_name: qual.program_name,
|
||||
degree_id: qual.qualification_number,
|
||||
};
|
||||
if (qual.passport_number) response.passport_number = qual.passport_number;
|
||||
if (qual.address) response.address = qual.address;
|
||||
const imgs = buildUrl(qual.degree_image);
|
||||
if (imgs) response.degree_image = imgs;
|
||||
if (qual.topic_name) {
|
||||
response.topic_name = qual.topic_name;
|
||||
if (qual.topic_short_desc) response.topic_short_desc = qual.topic_short_desc;
|
||||
}
|
||||
|
||||
return res.json(response);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user