Initial commit apps directory with .gitignore
This commit is contained in:
142
app-Izin_Keluar/server.js
Normal file
142
app-Izin_Keluar/server.js
Normal file
@@ -0,0 +1,142 @@
|
||||
|
||||
import express from 'express';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import cors from 'cors';
|
||||
|
||||
const app = express();
|
||||
const PORT = process.env.PORT || 3004;
|
||||
|
||||
// Karena kita menggunakan ES module, __dirname perlu didefinisikan secara manual
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
// URL yang akan di-proxy
|
||||
const GOOGLE_APPS_SCRIPT_URL = 'https://script.google.com/macros/s/AKfycbybbQyKyVPSVPXOqOjaOFMKetuYfyweGcjResfLi-B-8scqaoyXeSsmsqNTXeTLe7_Wvg/exec';
|
||||
const STUDENT_DATA_URL = 'https://docs.google.com/spreadsheets/d/18nVeas2TG5SbkTUsc1mQWmPP_0xu3fek-UfTQdjjvUc/gviz/tq?tqx=out:csv&sheet=DATABASE';
|
||||
const PERMIT_DATA_URL = 'https://docs.google.com/spreadsheets/d/18nVeas2TG5SbkTUsc1mQWmPP_0xu3fek-UfTQdjjvUc/gviz/tq?tqx=out:csv&sheet=REKAP IZIN';
|
||||
|
||||
// === CACHING SYSTEM ===
|
||||
const cache = {
|
||||
students: { data: null, timestamp: 0 },
|
||||
permits: { data: null, timestamp: 0 }
|
||||
};
|
||||
|
||||
// Cache TTL (Time To Live) in milliseconds
|
||||
const STUDENT_CACHE_TTL = 5 * 60 * 1000; // 5 menit - data siswa jarang berubah
|
||||
const PERMIT_CACHE_TTL = 30 * 1000; // 30 detik - data izin lebih sering berubah
|
||||
|
||||
const isCacheValid = (cacheEntry, ttl) => {
|
||||
return cacheEntry.data && (Date.now() - cacheEntry.timestamp) < ttl;
|
||||
};
|
||||
// === END CACHING SYSTEM ===
|
||||
|
||||
app.use(cors());
|
||||
app.use(express.json());
|
||||
|
||||
// Proxy untuk data CSV siswa (dengan cache)
|
||||
app.get('/api/students', async (req, res) => {
|
||||
try {
|
||||
// Check cache first
|
||||
if (isCacheValid(cache.students, STUDENT_CACHE_TTL)) {
|
||||
console.log('📦 Serving students from cache');
|
||||
return res.type('text/csv').send(cache.students.data);
|
||||
}
|
||||
|
||||
console.log('🌐 Fetching students from Google Sheets...');
|
||||
const response = await fetch(STUDENT_DATA_URL);
|
||||
if (!response.ok) throw new Error(`Network response was not ok: ${response.statusText}`);
|
||||
const csvText = await response.text();
|
||||
|
||||
// Update cache
|
||||
cache.students = { data: csvText, timestamp: Date.now() };
|
||||
console.log('✅ Students cached successfully');
|
||||
|
||||
res.type('text/csv').send(csvText);
|
||||
} catch (error) {
|
||||
console.error("Error proxying student data:", error);
|
||||
res.status(500).json({ error: "Failed to fetch student data." });
|
||||
}
|
||||
});
|
||||
|
||||
// Proxy untuk data CSV izin (dengan cache)
|
||||
app.get('/api/permits-csv', async (req, res) => {
|
||||
try {
|
||||
// Check cache first (shorter TTL for permits)
|
||||
if (isCacheValid(cache.permits, PERMIT_CACHE_TTL)) {
|
||||
console.log('📦 Serving permits from cache');
|
||||
return res.type('text/csv').send(cache.permits.data);
|
||||
}
|
||||
|
||||
console.log('🌐 Fetching permits from Google Sheets...');
|
||||
const url = `${PERMIT_DATA_URL}&t=${new Date().getTime()}`;
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) throw new Error(`Network response was not ok: ${response.statusText}`);
|
||||
const csvText = await response.text();
|
||||
|
||||
// Update cache
|
||||
cache.permits = { data: csvText, timestamp: Date.now() };
|
||||
console.log('✅ Permits cached successfully');
|
||||
|
||||
res.type('text/csv').send(csvText);
|
||||
} catch (error) {
|
||||
console.error("Error proxying permit data:", error);
|
||||
res.status(500).json({ error: "Failed to fetch permit data." });
|
||||
}
|
||||
});
|
||||
|
||||
// Proxy untuk semua aksi Google Apps Script (submit, update, delete)
|
||||
app.post('/api/action', async (req, res) => {
|
||||
try {
|
||||
const response = await fetch(GOOGLE_APPS_SCRIPT_URL, {
|
||||
method: 'POST',
|
||||
redirect: 'follow',
|
||||
body: JSON.stringify(req.body),
|
||||
headers: { "Content-Type": "text/plain;charset=utf-8" },
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorBody = await response.text();
|
||||
console.error('Apps Script Proxy Error Body:', errorBody);
|
||||
throw new Error(`Apps Script responded with status: ${response.status}`);
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
// Invalidate permits cache after any action (submit, update, delete)
|
||||
cache.permits = { data: null, timestamp: 0 };
|
||||
console.log('🗑️ Permits cache invalidated after action');
|
||||
|
||||
res.json(result);
|
||||
|
||||
} catch (error) {
|
||||
console.error("Error proxying to Google Apps Script:", error);
|
||||
res.status(500).json({ status: 'error', message: 'Proxy request to Google Apps Script failed.' });
|
||||
}
|
||||
});
|
||||
|
||||
// Endpoint untuk force refresh cache (opsional, berguna untuk admin)
|
||||
app.post('/api/refresh-cache', (req, res) => {
|
||||
cache.students = { data: null, timestamp: 0 };
|
||||
cache.permits = { data: null, timestamp: 0 };
|
||||
console.log('🗑️ All caches cleared');
|
||||
res.json({ status: 'success', message: 'Cache cleared successfully' });
|
||||
});
|
||||
|
||||
|
||||
// Tentukan path absolut ke folder 'dist'
|
||||
const distPath = path.resolve(__dirname, 'dist');
|
||||
|
||||
// Menyajikan file statis dari direktori build React
|
||||
app.use(express.static(distPath));
|
||||
|
||||
// "Catchall" handler: untuk permintaan apa pun yang tidak cocok dengan rute di atas, kirim file index.html React.
|
||||
app.get('*', (req, res) => {
|
||||
res.sendFile(path.resolve(distPath, 'index.html'));
|
||||
});
|
||||
|
||||
app.listen(PORT, () => {
|
||||
console.log(`🚀 Server is running on port ${PORT}`);
|
||||
console.log(`📂 Serving static files from ${distPath}`);
|
||||
console.log(`⏱️ Student cache TTL: ${STUDENT_CACHE_TTL / 1000}s, Permit cache TTL: ${PERMIT_CACHE_TTL / 1000}s`);
|
||||
});
|
||||
Reference in New Issue
Block a user