-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsorteio_init.js
More file actions
326 lines (281 loc) · 14.9 KB
/
sorteio_init.js
File metadata and controls
326 lines (281 loc) · 14.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
// sorteio_init.js (Versão com campo de senha no HTML, Hash para a senha e Sincronização JSONBin.io)
setTimeout(function() {
const passwordContainer = document.getElementById('password-container');
const passwordInput = document.getElementById('password-input');
const authBtn = document.getElementById('auth-btn');
const sortearBtn = document.getElementById('sortear-btn');
if (sortearBtn) {
console.log("SortearBtn encontrado! Adicionando listener...", sortearBtn);
} else {
console.error("ERRO GRAVE: Botão 'sortear-btn' NÃO ENCONTRADO no DOM do iframe. Verifique o HTML.");
return;
}
if (!passwordInput || !authBtn || !passwordContainer) {
console.error("ERRO GRAVE: Elementos de autenticação (password-input, auth-btn, password-container) NÃO ENCONTRADOS. Verifique o HTML.");
return;
}
const sorteioInfo = document.getElementById('sorteio-info');
const sorteioResultado = document.getElementById('sorteio-resultado');
const networkContainer = document.getElementById('mynetwork-sorteio');
// !!! ATENÇÃO: COLOQUE AQUI O HASH SHA-256 DA SUA SENHA DE ADMINISTRADOR !!!
const ADMIN_PASSWORD_HASH = "70634fbd18273fdc823c0e55d173d842e0ca16523fbebfbda0979b021e626530";
// --- NOVAS VARIÁVEIS PARA JSONBIN.IO ---
// !!! ATENÇÃO: COLOQUE SUA MASTER KEY REAL AQUI !!!
const JSONBIN_MASTER_KEY = "$2a$10$Dqq7na7JDXk8dBFI/0a81uiQT7.YO5RgFhgzdbWwNrbaeaYio7oc.";
// !!! ATENÇÃO: COLOQUE SEU BIN ID REAL AQUI !!!
const JSONBIN_BIN_ID = "684ad82d8561e97a5022ff63";
const JSONBIN_API_URL = `https://api.jsonbin.io/v3/b/${JSONBIN_BIN_ID}`;
// ------------------------------------
// Função assíncrona para gerar o hash SHA-256 de uma string
async function sha256(message) {
const msgBuffer = new TextEncoder().encode(message);
const hashBuffer = await crypto.subtle.digest('SHA-256', msgBuffer);
const hashArray = Array.from(new Uint8Array(hashBuffer));
const hexHash = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
return hexHash;
}
let pessoasData = [];
let network = null;
let lastSorteioUpdateTime = null;
const corAreaSorteada = '#d52c01';
const corPessoa1 = '#a30161';
const corPessoa2 = '#0097b2';
const corArestasSorteio = '#5D3B2E';
// --- FUNÇÃO PARA CARREGAR DADOS DO GRAFO (DO JSON LOCAL) ---
function loadGraphDataFromJson() {
fetch('graph_data.json')
.then(response => {
if (!response.ok) {
throw new Error(`Erro ao carregar graph_data.json: ${response.statusText} (Status: ${response.status})`);
}
return response.json();
})
.then(data => {
const nodes = data.nodes;
const edges = data.edges;
if (!nodes || !edges || nodes.length === 0 || edges.length === 0) {
throw new Error("Dados do grafo JSON não contêm 'nodes' ou 'edges' válidos ou estão vazios.");
}
const tempPessoasData = {};
nodes.forEach(node => {
if (node.tipo === 'pessoa') {
tempPessoasData[node.label] = {
nome: node.label,
interesses: []
};
}
});
edges.forEach(edge => {
const fromNode = nodes.find(n => n.id === edge.from);
const toNode = nodes.find(n => n.id === edge.to);
if (fromNode && toNode) {
if (fromNode.tipo === 'pessoa' && toNode.tipo === 'interesse') {
if (tempPessoasData[fromNode.label]) {
tempPessoasData[fromNode.label].interesses.push(toNode.label);
}
} else if (toNode.tipo === 'pessoa' && fromNode.tipo === 'interesse') {
if (tempPessoasData[toNode.label]) {
tempPessoasData[toNode.label].interesses.push(fromNode.label);
}
}
}
});
pessoasData = Object.values(tempPessoasData);
console.log("Dados de pessoas e interesses extraídos do JSON para sorteio:", pessoasData);
sorteioInfo.textContent = "Dados prontos para o sorteio!";
// Chamar checkAndUpdateSorteioResult para carregar o estado inicial do sorteio do JSONBin.io
checkAndUpdateSorteioResult();
})
.catch(error => {
console.error('Erro ao carregar ou processar dados do grafo JSON:', error);
sorteioInfo.textContent = `Erro ao carregar e processar dados do grafo: ${error.message}`;
});
}
// --- FUNÇÃO PARA ATUALIZAR O RESULTADO DO SORTEIO NA TELA ---
function displaySorteioResult(data) {
if (network) {
network.destroy();
network = null;
}
// Se data for null ou vazio, limpa a exibição
if (!data || !data.area_sorteada || !data.pessoa1 || !data.pessoa2) {
sorteioInfo.textContent = "Nenhum sorteio realizado ainda ou dados incompletos.";
sorteioResultado.innerHTML = "";
if (networkContainer) networkContainer.innerHTML = "";
return; // Sai da função se não houver dados válidos para exibir
}
sorteioInfo.textContent = `Última Área sorteada: ${data.area_sorteada}`;
sorteioResultado.innerHTML = `Últimas Pessoas sorteadas: <span style="color:#700041">${data.pessoa1}</span> e <span style="color:#700041">${data.pessoa2}</span>!`;
const nodes = new vis.DataSet([
{ id: data.pessoa1, label: data.pessoa1, shape: 'dot', size: 60, color: corPessoa1, font: { size: 30, color: '#333' } },
{ id: data.pessoa2, label: data.pessoa2, shape: 'dot', size: 60, color: corPessoa2, font: { size: 30, color: '#333' } },
{ id: data.area_sorteada, label: data.area_sorteada, shape: 'circle', size: 8, color: corAreaSorteada, font: { size: 12, color: 'black' } }
]);
const edges = new vis.DataSet([
{ from: data.pessoa1, to: data.area_sorteada, width: 4, color: corArestasSorteio },
{ from: data.pessoa2, to: data.area_sorteada, width: 4, color: corArestasSorteio }
]);
const visData = { nodes: nodes, edges: edges };
const options = {
physics: {
enabled: true, // Garante que a física está ativada
barnesHut: {
gravitationalConstant: -2000, // Substitua 'gravity' por 'gravitationalConstant'
// Valores negativos repelem, positivos atraem.
// -2000 é um bom ponto de partida.
centralGravity: 0.3,
springLength: 200, // Ajuste este valor se precisar de molas mais longas
springConstant: 0.05, // Substitua 'springStrength' por 'springConstant'
// Valor da constante da mola.
damping: 0.09 // Adicione damping para estabilizar a rede (opcional, mas recomendado)
},
solver: 'barnesHut', // Especifica o algoritmo de física
stabilization: {
iterations: 100,
updateInterval: 25 // Atualiza a cada 25ms durante a estabilização
}
},
interaction: {
zoomView: true,
dragNodes: true,
dragView: true
}
};
network = new vis.Network(networkContainer, visData, options);
}
// --- FUNÇÃO PARA LER O RESULTADO DO SORTEIO (DO JSONBIN.IO) ---
function checkAndUpdateSorteioResult() {
fetch(`${JSONBIN_API_URL}/latest?t=${new Date().getTime()}`, { // Adiciona um timestamp para evitar cache
headers: {
'X-Master-Key': JSONBIN_MASTER_KEY // Necessário se o bin for privado ou para evitar rate limits
}
})
.then(response => {
if (!response.ok) {
// O status 404 pode significar que o bin está vazio ou não foi criado ainda.
// Isso é aceitável na primeira carga.
if (response.status === 404) {
console.warn("JSONBin não encontrado ou vazio. Isso é normal se o arquivo não tiver sido criado ou estiver vazio inicialmente.");
return null;
}
throw new Error(`Erro ao carregar dados do JSONBin: ${response.statusText} (Status: ${response.status})`);
}
return response.json();
})
.then(jsonBinResponse => {
// JSONBin.io retorna os dados dentro de um objeto 'record'
const data = jsonBinResponse ? jsonBinResponse.record : null;
if (data && data.ultima_atualizacao && data.ultima_atualizacao !== lastSorteioUpdateTime) {
console.log("Novo resultado de sorteio detectado do JSONBin:", data);
displaySorteioResult(data);
lastSorteioUpdateTime = data.ultima_atualizacao;
} else if (!data || !data.ultima_atualizacao) { // Se o bin estiver vazio ou sem dados de sorteio
if (lastSorteioUpdateTime !== null) { // Apenas se já houve um sorteio exibido antes
console.log("JSONBin esvaziado ou sem dados de sorteio. Limpando exibição.");
displaySorteioResult({}); // Passa um objeto vazio para limpar a tela
lastSorteioUpdateTime = null;
}
}
})
.catch(error => {
console.error('Erro ao verificar atualização do sorteio do JSONBin:', error);
// sorteioInfo.textContent = `Erro ao carregar sorteio (JSONBin): ${error.message}`; // Comentado para não exibir se sorteioInfo estiver oculto
});
}
// --- LÓGICA DE AUTENTICAÇÃO DO ADMINISTRADOR (AGORA COM HASH) ---
authBtn.addEventListener('click', async function() {
const enteredPassword = passwordInput.value;
const enteredPasswordHash = await sha256(enteredPassword);
if (enteredPasswordHash === ADMIN_PASSWORD_HASH) {
passwordContainer.style.display = 'none';
sortearBtn.style.display = 'block';
sorteioInfo.textContent = "Autenticação bem-sucedida! Pronto para sortear.";
console.log("Admin autenticado.");
// Opcional: force uma atualização imediata após a autenticação
checkAndUpdateSorteioResult();
} else {
alert("Senha incorreta. Apenas administradores podem realizar o sorteio.");
passwordInput.value = '';
console.warn("Tentativa de login falhou.");
}
});
// --- LÓGICA DO SORTEIO E ESCRITA (PARA O JSONBIN.IO) ---
sortearBtn.addEventListener('click', function() {
console.log("Botão Sortear Dupla CLICADO!");
if (pessoasData.length === 0) {
sorteioInfo.textContent = "Aguarde, os dados ainda não foram carregados ou não há participantes.";
return;
}
sorteioInfo.textContent = ""; // Limpa antes de sortear
sorteioResultado.textContent = "";
if (network) {
network.destroy();
network = null;
}
const todasAreas = new Set();
pessoasData.forEach(pessoa => {
pessoa.interesses.forEach(interesse => todasAreas.add(interesse));
});
const areasArray = Array.from(todasAreas);
if (areasArray.length === 0) {
sorteioInfo.textContent = "Nenhuma área de interesse encontrada para sorteio.";
return;
}
const areaSorteada = areasArray[Math.floor(Math.random() * areasArray.length)];
sorteioInfo.textContent = `Área sorteada: ${areaSorteada}`;
const pessoasComArea = pessoasData.filter(pessoa => pessoa.interesses.includes(areaSorteada));
if (pessoasComArea.length < 2) {
sorteioResultado.textContent = `Menos de duas pessoas com interesse em "${areaSorteada}". Tentando outra área...`;
setTimeout(() => sortearBtn.click(), 1000);
return;
}
let indicesSorteados = [];
while (indicesSorteados.length < 2) {
const randomIndex = Math.floor(Math.random() * pessoasComArea.length);
if (!indicesSorteados.includes(randomIndex)) {
indicesSorteados.push(randomIndex);
}
}
const pessoa1 = pessoasComArea[indicesSorteados[0]].nome;
const pessoa2 = pessoasComArea[indicesSorteados[1]].nome;
const sorteioResultData = {
ultima_atualizacao: new Date().toISOString(),
area_sorteada: areaSorteada,
pessoa1: pessoa1,
pessoa2: pessoa2
};
// Atualiza localmente imediatamente (para a tela do admin)
displaySorteioResult(sorteioResultData);
lastSorteioUpdateTime = sorteioResultData.ultima_atualizacao;
// --- SALVA O RESULTADO NO JSONBIN.IO ---
fetch(JSONBIN_API_URL, {
method: 'PUT', // PUT para atualizar o Bin existente
headers: {
'Content-Type': 'application/json',
'X-Master-Key': JSONBIN_MASTER_KEY, // A Master Key é crucial aqui para PERMISSÃO de escrita
'X-Bin-Meta': false // Não atualiza meta-dados do bin, apenas o conteúdo
},
body: JSON.stringify(sorteioResultData)
})
.then(response => {
if (!response.ok) {
// Se a requisição falhar (ex: chave incorreta, Bin ID errado, limite de requisições)
throw new Error(`Erro ${response.status} ao salvar sorteio no JSONBin: ${response.statusText}`);
}
return response.json();
})
.then(data => {
console.log("Sorteio salvo com sucesso no JSONBin.io:", data);
sorteioInfo.textContent = "Sorteio realizado e publicado!";
})
.catch(error => {
console.error('Erro ao salvar sorteio no JSONBin.io:', error);
alert("Erro ao publicar o sorteio online. Verifique o console.");
// sorteioInfo.textContent = `Erro ao publicar sorteio: ${error.message}`; // Comentado para não exibir se sorteioInfo estiver oculto
});
});
// Inicia a verificação periódica do JSONBin.io
setInterval(checkAndUpdateSorteioResult, 5000); // Verifica a cada 5 segundos
// Carrega os dados iniciais do grafo e então, o último sorteio do JSONBin.io
loadGraphDataFromJson();
}, 200);