Lompat ke konten Lompat ke sidebar Lompat ke footer
/** * E-Voting System 2026 - Code.gs * Backend logic for Google Apps Script */ // --- KONFIGURASI NAMA SHEET --- const DB_CONFIG = "Konfigurasi"; const DB_SISWA = "Data Siswa"; const DB_KANDIDAT = "Data Kandidat"; function doGet() { setupDatabase(); // Auto-setup saat dibuka return HtmlService.createTemplateFromFile('index') .evaluate() .setTitle('E-Voting OSIS Premium') .addMetaTag('viewport', 'width=device-width, initial-scale=1') .setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL); } // --- FUNGSI DATABASE AUTO-SETUP --- function setupDatabase() { const ss = SpreadsheetApp.getActiveSpreadsheet(); // 1. Setup Sheet Konfigurasi let sheetConfig = ss.getSheetByName(DB_CONFIG); if (!sheetConfig) { sheetConfig = ss.insertSheet(DB_CONFIG); sheetConfig.appendRow(["Key", "Value"]); sheetConfig.appendRow(["Nama Sekolah", "SMA Negeri Future"]); sheetConfig.appendRow(["Status Voting", "BUKA"]); } // 2. Setup Sheet Data Siswa let sheetSiswa = ss.getSheetByName(DB_SISWA); if (!sheetSiswa) { sheetSiswa = ss.insertSheet(DB_SISWA); sheetSiswa.appendRow(["NIS", "Nama", "Kelas", "Status Pemilihan"]); } // 3. Setup Sheet Kandidat let sheetKandidat = ss.getSheetByName(DB_KANDIDAT); if (!sheetKandidat) { sheetKandidat = ss.insertSheet(DB_KANDIDAT); sheetKandidat.appendRow(["ID", "Ketua", "Wakil", "Visi", "Misi", "FotoURL", "Jumlah Suara"]); } } // --- FUNGSI API (Dipanggil dari HTML) --- function getInitialData() { const ss = SpreadsheetApp.getActiveSpreadsheet(); const config = ss.getSheetByName(DB_CONFIG).getDataRange().getValues(); const sheetKandidat = ss.getSheetByName(DB_KANDIDAT); // Handle jika sheet kosong let candidates = []; if (sheetKandidat.getLastRow() > 1) { candidates = sheetKandidat.getDataRange().getValues(); } let candidateList = []; if (candidates.length > 1) { for (let i = 1; i < candidates.length; i++) { candidateList.push({ id: candidates[i][0], ketua: candidates[i][1], wakil: candidates[i][2], visi: candidates[i][3], misi: candidates[i][4], foto: candidates[i][5], suara: candidates[i][6] }); } } let schoolName = "Sekolah"; config.forEach(row => { if(row[0] === "Nama Sekolah") schoolName = row[1]; }); return { schoolName, candidates: candidateList }; } function saveSchoolConfig(name) { const ss = SpreadsheetApp.getActiveSpreadsheet(); const sheet = ss.getSheetByName(DB_CONFIG); const data = sheet.getDataRange().getValues(); for(let i=0; i 1 ? sheet.getRange(2, 1, lastRow-1).getValues().flat() : []; let newRows = []; let duplicateCount = 0; studentList.forEach(s => { // Validasi NIS harus string agar tidak error match if (!existingNIS.includes(String(s.nis)) && !existingNIS.includes(Number(s.nis))) { newRows.push([s.nis, s.nama, s.kelas, "BELUM"]); } else { duplicateCount++; } }); if (newRows.length > 0) { sheet.getRange(lastRow + 1, 1, newRows.length, 4).setValues(newRows); } return { success: true, added: newRows.length, skipped: duplicateCount }; } // REVISI: Fungsi Tambah Kandidat (Sekarang menerima String URL, bukan upload file) function addCandidate(data) { try { const ss = SpreadsheetApp.getActiveSpreadsheet(); const sheet = ss.getSheetByName(DB_KANDIDAT); const newId = new Date().getTime(); // ID unik pakai timestamp // Simpan URL langsung dari input user sheet.appendRow([ newId, data.namaKetua, data.namaWakil, data.visi, data.misi, data.fotoUrl, // URL Link 0 // Suara awal 0 ]); return { success: true }; } catch (e) { return { success: false, error: e.toString() }; } } function submitVote(nis, candidateId) { const lock = LockService.getScriptLock(); try { // Lock untuk mencegah race condition (vote ganda dalam milidetik yang sama) lock.waitLock(10000); const ss = SpreadsheetApp.getActiveSpreadsheet(); const sheetSiswa = ss.getSheetByName(DB_SISWA); const sheetKandidat = ss.getSheetByName(DB_KANDIDAT); // Cek Siswa const dataSiswa = sheetSiswa.getDataRange().getValues(); let studentRow = -1; for (let i = 1; i < dataSiswa.length; i++) { if (String(dataSiswa[i][0]) === String(nis)) { // Compare as string studentRow = i + 1; if (dataSiswa[i][3] === "SUDAH") { return { success: false, message: "Anda sudah menggunakan hak pilih sebelumnya." }; } break; } } if (studentRow === -1) { return { success: false, message: "NIS tidak ditemukan dalam daftar pemilih." }; } // Update Suara Kandidat const dataKandidat = sheetKandidat.getDataRange().getValues(); let candidateRow = -1; for (let i = 1; i < dataKandidat.length; i++) { // Compare ID if (String(dataKandidat[i][0]) === String(candidateId)) { candidateRow = i + 1; break; } } if (candidateRow !== -1) { // 1. Tandai Siswa Sudah Memilih sheetSiswa.getRange(studentRow, 4).setValue("SUDAH"); // 2. Tambah Hitungan Suara const currentVote = sheetKandidat.getRange(candidateRow, 7).getValue(); sheetKandidat.getRange(candidateRow, 7).setValue(currentVote + 1); return { success: true, message: "Voting Berhasil! Terima kasih." }; } else { return { success: false, message: "Data kandidat error." }; } } catch (e) { return { success: false, message: "Error: " + e.toString() }; } finally { lock.releaseLock(); } } function resetVotes() { const ss = SpreadsheetApp.getActiveSpreadsheet(); const sheetSiswa = ss.getSheetByName(DB_SISWA); const sheetKandidat = ss.getSheetByName(DB_KANDIDAT); const lastRowSiswa = sheetSiswa.getLastRow(); if(lastRowSiswa > 1) { sheetSiswa.getRange(2, 4, lastRowSiswa - 1, 1).setValue("BELUM"); } const lastRowKandidat = sheetKandidat.getLastRow(); if(lastRowKandidat > 1) { sheetKandidat.getRange(2, 7, lastRowKandidat - 1, 1).setValue(0); } return "Sistem berhasil di-reset ke 0."; } E-Voting OSIS Premium

Memproses...

E-Voting System

Suara Anda Menentukan Masa Depan

Memuat Kandidat...

Hasil Perolehan Suara
🏫 Konfigurasi Sekolah

👥 Data Pemilih (Siswa)
Format: NIS, Nama, Kelas (Enter per baris)
⭐ Tambah Paslon Baru
© 2026 E-Voting System. Built with Google Apps Script.

Posting Komentar untuk " "