A começar
/** * LOT SUPERPODER v2.0 * Secure server-side scoring + organiser email + sealed reveal. * The participant browser never receives the animal until reveal code validation. */ const SP = Object.freeze({ VERSION: '2.0.0', CACHE_TTL_SECONDS: 21600, // 6 horas FAIL_LOCK_SECONDS: 120, MAX_FAILED_REVEAL_ATTEMPTS: 5 }); const SP_ANIMALS = Object.freeze({ bear: { name: 'URSO ENCARNADO', short: 'URSO', cake: 'ENCARNADO', superpower: 'MODO GO' }, fox: { name: 'RAPOSA AMARELA', short: 'RAPOSA', cake: 'AMARELO', superpower: 'FAÍSCA' }, horse: { name: 'CAVALO VERDE', short: 'CAVALO', cake: 'VERDE', superpower: 'SINCRONIA' }, owl: { name: 'CORUJA AZUL', short: 'CORUJA', cake: 'AZUL', superpower: 'RADAR' } }); const SP_ORDER = ['bear', 'fox', 'horse', 'owl']; /* * CHAVE CANÓNICA DAS 12 PERGUNTAS * * IMPORTANTE: * Esta chave existe APENAS no GAS. * Não deve ser colocada no HTML. * * Cada pergunta tem exatamente: * 1 Urso * 1 Raposa * 1 Cavalo * 1 Coruja * * E cada animal aparece exatamente: * 3 vezes em A * 3 vezes em B * 3 vezes em C * 3 vezes em D */ const SP_KEY = Object.freeze({ q1: { q1a: 'bear', q1b: 'fox', q1c: 'horse', q1d: 'owl' }, q2: { q2a: 'owl', q2b: 'horse', q2c: 'fox', q2d: 'bear' }, q3: { q3a: 'horse', q3b: 'owl', q3c: 'bear', q3d: 'fox' }, q4: { q4a: 'fox', q4b: 'bear', q4c: 'owl', q4d: 'horse' }, q5: { q5a: 'bear', q5b: 'horse', q5c: 'owl', q5d: 'fox' }, q6: { q6a: 'owl', q6b: 'fox', q6c: 'horse', q6d: 'bear' }, q7: { q7a: 'horse', q7b: 'bear', q7c: 'fox', q7d: 'owl' }, q8: { q8a: 'fox', q8b: 'owl', q8c: 'bear', q8d: 'horse' }, q9: { q9a: 'bear', q9b: 'owl', q9c: 'fox', q9d: 'horse' }, q10: { q10a: 'owl', q10b: 'horse', q10c: 'bear', q10d: 'fox' }, q11: { q11a: 'horse', q11b: 'fox', q11c: 'owl', q11d: 'bear' }, q12: { q12a: 'fox', q12b: 'bear', q12c: 'horse', q12d: 'owl' } }); /* * EXECUTAR UMA VEZ DEPOIS DE COLAR O CÓDIGO */ function setupSuperpoder() { const audit = testSuperpowerBalance(); if (!audit.ok) { throw new Error( 'BALANCE QA FALHOU: ' + JSON.stringify(audit.errors) ); } const props = PropertiesService.getScriptProperties(); let email = String( props.getProperty('RESULT_RECIPIENT_EMAIL') || Session.getEffectiveUser().getEmail() || '' ).trim(); if (!email || email.indexOf('@') < 1) { throw new Error( 'Não consegui detetar o email. ' + 'Adicione RESULT_RECIPIENT_EMAIL nas Script Properties.' ); } let code = String( props.getProperty('REVEAL_CODE') || '' ).trim(); if (!/^\d{6}$/.test(code)) { code = String( Math.floor( 100000 + Math.random() * 900000 ) ); } props.setProperties({ RESULT_RECIPIENT_EMAIL: email, REVEAL_CODE: code }); MailApp.sendEmail({ to: email, subject: 'LOT Superpoder pronto | código de revelação ' + code, htmlBody: '
LOT Superpoder v2 está configurado.
' + 'Email de resultados: ' + html_(email) + '
' + 'Código comum de revelação: ' + '' + code + '
' + 'Guarde este código e anuncie-o apenas depois de todos partirem o bolo.
' }); console.log('LOT Superpoder OK'); console.log( 'RESULT_RECIPIENT_EMAIL: ' + email ); console.log( 'REVEAL_CODE: ' + code ); console.log( JSON.stringify(audit) ); return { ok: true, email: email, revealCode: code, balance: audit, version: SP.VERSION }; } /* * WEB APP */ function doGet(e) { const p = e && e.parameter ? e.parameter : {}; if (String(p.bridge || '') === '1') { return bridgeHtml_(); } return ContentService .createTextOutput( JSON.stringify({ ok: true, service: 'lot-superpoder', version: SP.VERSION }) ) .setMimeType( ContentService.MimeType.JSON ); } /* * BRIDGE PARA O HTML NO LINDO */ function bridgeHtml_() { const html = '' + '' + '