MIF_E31222519/API/controllers/AbsensiController.js

220 lines
8.6 KiB
JavaScript

const Absensi = require('../models/Absensi');
const LokasiAbsensi = require('../models/LokasiAbsensi');
const { KodePembelajaran, Pelajaran, JadwalPelajaran } = require('../models');
const jwt = require('jsonwebtoken');
const fs = require('fs');
const path = require('path');
const multer = require('multer');
// Konfigurasi penyimpanan untuk multer
const storage = multer.diskStorage({
destination: function (req, file, cb) {
const uploadDir = path.join(__dirname, '../public/uploads/absensi');
// Cek apakah direktori ada, jika tidak ada maka buat
if (!fs.existsSync(uploadDir)) {
fs.mkdirSync(uploadDir, { recursive: true });
}
cb(null, uploadDir);
},
filename: function (req, file, cb) {
// Membuat nama file unik dengan timestamp
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
const ext = path.extname(file.originalname);
cb(null, 'absensi-' + uniqueSuffix + ext);
}
});
// Filter untuk memastikan hanya file gambar yang di-upload
const fileFilter = (req, file, cb) => {
if (file.mimetype.startsWith('image/')) {
cb(null, true);
} else {
cb(new Error('Hanya file gambar yang diperbolehkan!'), false);
}
};
// Inisialisasi multer
const upload = multer({
storage: storage,
fileFilter: fileFilter,
limits: {
fileSize: 5 * 1024 * 1024 // Batas ukuran file (5MB)
}
}).single('foto_absen');
// Fungsi untuk menghitung jarak antara dua koordinat
function hitungJarak(lat1, lon1, lat2, lon2) {
const R = 6371; // Radius bumi dalam km
const dLat = (lat2 - lat1) * (Math.PI / 180);
const dLon = (lon2 - lon1) * (Math.PI / 180);
const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(lat1 * (Math.PI / 180)) * Math.cos(lat2 * (Math.PI / 180)) *
Math.sin(dLon / 2) * Math.sin(dLon / 2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return R * c * 1000; // Jarak dalam meter
}
// ✅ GET Absensi by ID Siswa
exports.getAbsensiByToken = async (req, res) => {
try {
// Ambil token dari header
const token = req.header("Authorization")?.replace("Bearer ", "");
if (!token) {
return res.status(401).json({ status: "error", message: "Token tidak ditemukan" });
}
// Decode token
const decoded = jwt.verify(token, "secret_key");
const id_siswa = decoded.id_siswa;
// Ambil data absensi
const absensi = await Absensi.findAll({
where: { id_siswa },
attributes: [
'id_absensi',
'id_siswa',
'id_kodepembelajaran',
'waktu_absen',
'status',
'batas_waktu_absen',
'foto_absen' // ✅ Tambahkan atribut foto_absen
],
include: [
{
model: KodePembelajaran,
as: "kode_pembelajaran",
attributes: ["id_pelajaran"],
include: [
{
model: Pelajaran,
as: "Pelajaran",
attributes: ["nama_pelajaran"]
}
]
}
]
});
if (!absensi.length) {
return res.status(404).json({ status: "error", message: "Data absensi tidak ditemukan" });
}
// Buat URL lengkap untuk foto absensi
const baseUrl = `${req.protocol}://${req.get('host')}`;
// ✅ Pastikan batas_waktu_absen tetap ada dalam response
const formattedAbsensi = absensi.map(item => ({
id_absensi: item.id_absensi,
id_siswa: item.id_siswa,
id_kodepembelajaran: item.id_kodepembelajaran,
waktu_absen: item.waktu_absen,
status: item.status,
batas_waktu_absen: item.batas_waktu_absen || "Tidak ada batas waktu", // ✅ Jika null, berikan default value
nama_pelajaran: item.kode_pembelajaran?.Pelajaran?.nama_pelajaran || "Tidak diketahui",
foto_absen: item.foto_absen ? `${baseUrl}/uploads/absensi/${item.foto_absen}` : null
}));
res.status(200).json({ status: "success", data: formattedAbsensi });
} catch (error) {
res.status(500).json({ status: "error", message: "Terjadi kesalahan pada server", error: error.message });
}
};
// ✅ PUT Update Absensi dengan Upload Gambar
exports.updateAbsensi = async (req, res) => {
try {
// Handle upload file dengan multer
upload(req, res, async function(err) {
if (err instanceof multer.MulterError) {
return res.status(400).json({ status: "error", message: "Kesalahan saat upload file", error: err.message });
} else if (err) {
return res.status(400).json({ status: "error", message: err.message });
}
// Proses data setelah upload berhasil
const { id_siswa, id_kodepembelajaran, waktu_absen, latitude, longitude, status, keterangan_absen } = req.body;
console.log("Body request:", req.body);
console.log("File:", req.file);
// Cek apakah absensi tersedia
const absensi = await Absensi.findOne({ where: { id_siswa, id_kodepembelajaran } });
if (!absensi) {
// Hapus file jika absensi tidak ditemukan
if (req.file) {
fs.unlinkSync(req.file.path);
}
return res.status(404).json({ status: "error", message: "Data absensi tidak ditemukan" });
}
// Ambil lokasi sekolah yang aktif
const lokasi = await LokasiAbsensi.findOne({ where: { status: 'aktif' } });
if (!lokasi) {
// Hapus file jika lokasi tidak tersedia
if (req.file) {
fs.unlinkSync(req.file.path);
}
return res.status(400).json({ status: "error", message: "Lokasi absensi tidak tersedia" });
}
// Hitung jarak siswa ke lokasi sekolah
const jarak = hitungJarak(latitude, longitude, parseFloat(lokasi.latitude), parseFloat(lokasi.longitude));
if (jarak > lokasi.radius) {
// Hapus file jika siswa diluar radius
if (req.file) {
fs.unlinkSync(req.file.path);
}
return res.status(400).json({ status: "error", message: "Anda tidak berada di radius sekolah" });
}
// Hapus foto lama jika ada dan jika ada foto baru
if (absensi.foto_absen && req.file) {
try {
// Pastikan foto_absen adalah string
if (typeof absensi.foto_absen === 'string') {
const oldFilePath = path.join(__dirname, '../public/uploads/absensi', absensi.foto_absen);
console.log("Mencoba menghapus file:", oldFilePath);
if (fs.existsSync(oldFilePath)) {
fs.unlinkSync(oldFilePath);
console.log("File lama berhasil dihapus");
} else {
console.log("File lama tidak ditemukan");
}
} else {
console.log("foto_absen bukan string:", typeof absensi.foto_absen);
}
} catch (err) {
console.error("Error saat menghapus file lama:", err);
// Lanjutkan proses meskipun ada error saat menghapus
}
}
// Update absensi
await Absensi.update(
{
waktu_absen: waktu_absen || new Date(),
foto_absen: req.file ? req.file.filename : absensi.foto_absen,
status,
keterangan_absen
},
{ where: { id_siswa, id_kodepembelajaran } }
);
res.status(200).json({
status: "success",
message: "Absensi berhasil diperbarui",
data: {
foto_absen: req.file ? req.file.filename : absensi.foto_absen,
foto_url: req.file ? `${req.protocol}://${req.get('host')}/uploads/absensi/${req.file.filename}` : null
}
});
});
} catch (error) {
console.error("Error:", error);
res.status(500).json({ status: "error", message: "Terjadi kesalahan pada server", error: error.message });
}
};