fix(cliente): exibir qrcode e acoes de whatsapp apenas apos aprovacao da conexao
This commit is contained in:
@@ -457,7 +457,7 @@ public final class ClienteHandlers implements HttpHandler {
|
|||||||
}
|
}
|
||||||
private boolean adminEmpresa(String cargo){return "admin_empresa".equals(cargo);}
|
private boolean adminEmpresa(String cargo){return "admin_empresa".equals(cargo);}
|
||||||
|
|
||||||
private void conectarEvolution(HttpExchange ex,long empresaId)throws Exception{Map<String,String>b=body(ex);String url=b.getOrDefault("instance_url","");String numero=EvolutionApiClient.onlyDigits(req(b,"numero_whatsapp"));if(numero.length()<10){HttpResponses.json(ex,400,Map.of("erro","numero_whatsapp_invalido","mensagem","Informe o número com DDD e código do país."));return;}try(Connection m=masterDs.getMasterConnection()){liberarCadastrosEvolutionOrfaos(m,numero);Map<String,Object> existente=one(m,"SELECT id,empresa_id,status FROM evolution_instancias WHERE numero_whatsapp=? ORDER BY id DESC LIMIT 1",Arrays.asList(numero));if(existente!=null){HttpResponses.json(ex,409,Map.of("erro","numero_whatsapp_ja_cadastrado","mensagem","Este número de WhatsApp já está cadastrado em uma conexão."));return;}}String instance="empresa"+empresaId+"_"+System.currentTimeMillis();String token=UUID.randomUUID().toString().replace("-","");var criada=evolutionApiClient.criarInstancia(url,instance,token,numero);try(Connection m=masterDs.getMasterConnection();PreparedStatement ps=m.prepareStatement("INSERT INTO evolution_instancias (empresa_id,instance_url,instance_token_enc,numero_whatsapp,status) VALUES (?,?,?,?, 'pendente') RETURNING id")){ps.setLong(1,empresaId);ps.setString(2,url);ps.setString(3,criada.instanceName()+":"+criada.token());ps.setString(4,numero);try(ResultSet rs=ps.executeQuery()){rs.next();Map<String,Object> resp=new LinkedHashMap<>();resp.put("id",rs.getLong(1));resp.put("instance_name",criada.instanceName());resp.put("status","pendente");resp.put("qrcode_base64",criada.qrcodeBase64());resp.put("mock",criada.mock());HttpResponses.json(ex,201,resp);}}}
|
private void conectarEvolution(HttpExchange ex,long empresaId)throws Exception{Map<String,String>b=body(ex);String url=b.getOrDefault("instance_url","");String numero=EvolutionApiClient.onlyDigits(req(b,"numero_whatsapp"));if(numero.length()<10){HttpResponses.json(ex,400,Map.of("erro","numero_whatsapp_invalido","mensagem","Informe o número com DDD e código do país."));return;}try(Connection m=masterDs.getMasterConnection()){liberarCadastrosEvolutionOrfaos(m,numero);Map<String,Object> existente=one(m,"SELECT id,empresa_id,status FROM evolution_instancias WHERE numero_whatsapp=? ORDER BY id DESC LIMIT 1",Arrays.asList(numero));if(existente!=null){HttpResponses.json(ex,409,Map.of("erro","numero_whatsapp_ja_cadastrado","mensagem","Este número de WhatsApp já está cadastrado em uma conexão."));return;}}String instance="empresa"+empresaId+"_"+System.currentTimeMillis();String token=UUID.randomUUID().toString().replace("-","");var criada=evolutionApiClient.criarInstancia(url,instance,token,numero);try(Connection m=masterDs.getMasterConnection();PreparedStatement ps=m.prepareStatement("INSERT INTO evolution_instancias (empresa_id,instance_url,instance_token_enc,numero_whatsapp,status) VALUES (?,?,?,?, 'pendente') RETURNING id")){ps.setLong(1,empresaId);ps.setString(2,url);ps.setString(3,criada.instanceName()+":"+criada.token());ps.setString(4,numero);try(ResultSet rs=ps.executeQuery()){rs.next();Map<String,Object> resp=new LinkedHashMap<>();resp.put("id",rs.getLong(1));resp.put("instance_name",criada.instanceName());resp.put("status","pendente");resp.put("mock",criada.mock());HttpResponses.json(ex,201,resp);}}}
|
||||||
private void liberarCadastrosEvolutionOrfaos(Connection m,String numero)throws Exception{List<Map<String,Object>> existentes=rows(m,"SELECT id,instance_url,instance_token_enc FROM evolution_instancias WHERE numero_whatsapp=? ORDER BY id",Arrays.asList(numero));for(Map<String,Object> inst:existentes){String token=str(inst.get("instance_token_enc"));String instanceName=token.split(":",2)[0];if(instanceName.isBlank())continue;try{evolutionApiClient.estado(str(inst.get("instance_url")),instanceName);}catch(Exception err){if(!evolutionNaoEncontrada(err))throw err;try(PreparedStatement ps=m.prepareStatement("DELETE FROM evolution_instancias WHERE id=?")){ps.setLong(1,((Number)inst.get("id")).longValue());ps.executeUpdate();}}}}
|
private void liberarCadastrosEvolutionOrfaos(Connection m,String numero)throws Exception{List<Map<String,Object>> existentes=rows(m,"SELECT id,instance_url,instance_token_enc FROM evolution_instancias WHERE numero_whatsapp=? ORDER BY id",Arrays.asList(numero));for(Map<String,Object> inst:existentes){String token=str(inst.get("instance_token_enc"));String instanceName=token.split(":",2)[0];if(instanceName.isBlank())continue;try{evolutionApiClient.estado(str(inst.get("instance_url")),instanceName);}catch(Exception err){if(!evolutionNaoEncontrada(err))throw err;try(PreparedStatement ps=m.prepareStatement("DELETE FROM evolution_instancias WHERE id=?")){ps.setLong(1,((Number)inst.get("id")).longValue());ps.executeUpdate();}}}}
|
||||||
private boolean evolutionNaoEncontrada(Exception err){String msg=err.getMessage()==null?"":err.getMessage().toLowerCase(Locale.ROOT);return msg.contains("404")||msg.contains("not found")||msg.contains("instance not found")||msg.contains("nao encontrada")||msg.contains("não encontrada");}
|
private boolean evolutionNaoEncontrada(Exception err){String msg=err.getMessage()==null?"":err.getMessage().toLowerCase(Locale.ROOT);return msg.contains("404")||msg.contains("not found")||msg.contains("instance not found")||msg.contains("nao encontrada")||msg.contains("não encontrada");}
|
||||||
private void statusEvolution(HttpExchange ex,long empresaId)throws Exception{
|
private void statusEvolution(HttpExchange ex,long empresaId)throws Exception{
|
||||||
@@ -494,6 +494,10 @@ public final class ClienteHandlers implements HttpHandler {
|
|||||||
Long id=optLong(b.get("id"));
|
Long id=optLong(b.get("id"));
|
||||||
Map<String,Object> inst=id!=null?evolutionInstanciaPorId(empresaId,id):evolutionInstancia(empresaId);
|
Map<String,Object> inst=id!=null?evolutionInstanciaPorId(empresaId,id):evolutionInstancia(empresaId);
|
||||||
if(inst==null){HttpResponses.json(ex,404,Map.of("erro","instancia_nao_configurada"));return;}
|
if(inst==null){HttpResponses.json(ex,404,Map.of("erro","instancia_nao_configurada"));return;}
|
||||||
|
if(!"aprovada".equalsIgnoreCase(str(inst.get("status")))){
|
||||||
|
HttpResponses.json(ex,403,Map.of("erro","instancia_pendente_aprovacao","mensagem","Esta conexão está pendente de aprovação pelo administrador."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
String[] parts=String.valueOf(inst.get("instance_token_enc")).split(":",2);
|
String[] parts=String.valueOf(inst.get("instance_token_enc")).split(":",2);
|
||||||
Map<String,Object> qr=evolutionApiClient.conectar(str(inst.get("instance_url")),parts[0],str(inst.get("numero_whatsapp")));
|
Map<String,Object> qr=evolutionApiClient.conectar(str(inst.get("instance_url")),parts[0],str(inst.get("numero_whatsapp")));
|
||||||
HttpResponses.json(ex,200,qr);
|
HttpResponses.json(ex,200,qr);
|
||||||
@@ -503,6 +507,10 @@ public final class ClienteHandlers implements HttpHandler {
|
|||||||
Long id=optLong(b.get("id"));
|
Long id=optLong(b.get("id"));
|
||||||
Map<String,Object> inst=id!=null?evolutionInstanciaPorId(empresaId,id):evolutionInstancia(empresaId);
|
Map<String,Object> inst=id!=null?evolutionInstanciaPorId(empresaId,id):evolutionInstancia(empresaId);
|
||||||
if(inst==null){HttpResponses.json(ex,404,Map.of("erro","instancia_nao_configurada"));return;}
|
if(inst==null){HttpResponses.json(ex,404,Map.of("erro","instancia_nao_configurada"));return;}
|
||||||
|
if(!"aprovada".equalsIgnoreCase(str(inst.get("status")))){
|
||||||
|
HttpResponses.json(ex,403,Map.of("erro","instancia_pendente_aprovacao","mensagem","Esta conexão está pendente de aprovação pelo administrador."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
String[] parts=String.valueOf(inst.get("instance_token_enc")).split(":",2);
|
String[] parts=String.valueOf(inst.get("instance_token_enc")).split(":",2);
|
||||||
HttpResponses.json(ex,200,evolutionApiClient.logout(str(inst.get("instance_url")),parts[0]));
|
HttpResponses.json(ex,200,evolutionApiClient.logout(str(inst.get("instance_url")),parts[0]));
|
||||||
}
|
}
|
||||||
@@ -511,6 +519,10 @@ public final class ClienteHandlers implements HttpHandler {
|
|||||||
Long id=optLong(b.get("id"));
|
Long id=optLong(b.get("id"));
|
||||||
Map<String,Object> inst=id!=null?evolutionInstanciaPorId(empresaId,id):evolutionInstancia(empresaId);
|
Map<String,Object> inst=id!=null?evolutionInstanciaPorId(empresaId,id):evolutionInstancia(empresaId);
|
||||||
if(inst==null){HttpResponses.json(ex,404,Map.of("erro","instancia_nao_configurada"));return;}
|
if(inst==null){HttpResponses.json(ex,404,Map.of("erro","instancia_nao_configurada"));return;}
|
||||||
|
if(!"aprovada".equalsIgnoreCase(str(inst.get("status")))){
|
||||||
|
HttpResponses.json(ex,403,Map.of("erro","instancia_pendente_aprovacao","mensagem","Esta conexão está pendente de aprovação pelo administrador."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
String[] parts=String.valueOf(inst.get("instance_token_enc")).split(":",2);
|
String[] parts=String.valueOf(inst.get("instance_token_enc")).split(":",2);
|
||||||
HttpResponses.json(ex,200,evolutionApiClient.reiniciar(str(inst.get("instance_url")),parts[0]));
|
HttpResponses.json(ex,200,evolutionApiClient.reiniciar(str(inst.get("instance_url")),parts[0]));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ function renderCards(list) {
|
|||||||
const evoState = evo.state || 'close';
|
const evoState = evo.state || 'close';
|
||||||
const instName = inst.instance_name || ('instancia_' + inst.id);
|
const instName = inst.instance_name || ('instancia_' + inst.id);
|
||||||
const phoneFormatted = formatPhone(inst.numero_whatsapp);
|
const phoneFormatted = formatPhone(inst.numero_whatsapp);
|
||||||
|
const isAprovada = String(inst.status || '').toLowerCase() === 'aprovada';
|
||||||
|
|
||||||
return `
|
return `
|
||||||
<article class="wa-card" data-id="${inst.id}">
|
<article class="wa-card" data-id="${inst.id}">
|
||||||
@@ -129,15 +130,19 @@ function renderCards(list) {
|
|||||||
<footer class="wa-card-footer">
|
<footer class="wa-card-footer">
|
||||||
<span style="font-size: 12px; font-weight: 600; color: var(--muted-strong);">Ações:</span>
|
<span style="font-size: 12px; font-weight: 600; color: var(--muted-strong);">Ações:</span>
|
||||||
<div class="table-actions">
|
<div class="table-actions">
|
||||||
<button class="table-icon-btn" type="button" title="Conectar via QR Code" aria-label="Conectar via QR Code" onclick="abrirModalQr(${inst.id})">
|
${isAprovada ? `
|
||||||
${Icons.qrCode}
|
<button class="table-icon-btn" type="button" title="Conectar via QR Code" aria-label="Conectar via QR Code" onclick="abrirModalQr(${inst.id})">
|
||||||
</button>
|
${Icons.qrCode}
|
||||||
<button class="table-icon-btn" type="button" title="Reconectar WhatsApp" aria-label="Reconectar WhatsApp" onclick="abrirModalReconectar(${inst.id})">
|
</button>
|
||||||
${Icons.restart}
|
<button class="table-icon-btn" type="button" title="Reconectar WhatsApp" aria-label="Reconectar WhatsApp" onclick="abrirModalReconectar(${inst.id})">
|
||||||
</button>
|
${Icons.restart}
|
||||||
<button class="table-icon-btn danger" type="button" title="Desconectar WhatsApp" aria-label="Desconectar WhatsApp" onclick="abrirModalDesconectar(${inst.id})">
|
</button>
|
||||||
${Icons.power}
|
<button class="table-icon-btn danger" type="button" title="Desconectar WhatsApp" aria-label="Desconectar WhatsApp" onclick="abrirModalDesconectar(${inst.id})">
|
||||||
</button>
|
${Icons.power}
|
||||||
|
</button>
|
||||||
|
` : `
|
||||||
|
<span class="badge warn" style="font-size: 11px; padding: 4px 8px; font-weight: 600;">Aguardando aprovação</span>
|
||||||
|
`}
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
</article>
|
</article>
|
||||||
@@ -200,6 +205,10 @@ async function requisitarQrCode() {
|
|||||||
function abrirModalQr(id, initialData = null) {
|
function abrirModalQr(id, initialData = null) {
|
||||||
selectedInstanciaId = id;
|
selectedInstanciaId = id;
|
||||||
const inst = conexoes.find(c => c.id === id);
|
const inst = conexoes.find(c => c.id === id);
|
||||||
|
if (inst && String(inst.status || '').toLowerCase() !== 'aprovada') {
|
||||||
|
Util.toast('Esta conexão ainda está pendente de aprovação pelo administrador.', true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (inst && inst.numero_whatsapp) {
|
if (inst && inst.numero_whatsapp) {
|
||||||
qrModalTitle.textContent = `Conectar ${formatPhonePlain(inst.numero_whatsapp)}`;
|
qrModalTitle.textContent = `Conectar ${formatPhonePlain(inst.numero_whatsapp)}`;
|
||||||
} else {
|
} else {
|
||||||
@@ -220,6 +229,11 @@ function fecharModalQr() {
|
|||||||
|
|
||||||
function abrirModalReconectar(id) {
|
function abrirModalReconectar(id) {
|
||||||
selectedInstanciaId = id;
|
selectedInstanciaId = id;
|
||||||
|
const inst = conexoes.find(c => c.id === id);
|
||||||
|
if (inst && String(inst.status || '').toLowerCase() !== 'aprovada') {
|
||||||
|
Util.toast('Esta conexão ainda está pendente de aprovação pelo administrador.', true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
reconectarStepConfirm.classList.remove('hidden');
|
reconectarStepConfirm.classList.remove('hidden');
|
||||||
reconectarStepLoading.classList.add('hidden');
|
reconectarStepLoading.classList.add('hidden');
|
||||||
reconectarModal.classList.remove('hidden');
|
reconectarModal.classList.remove('hidden');
|
||||||
@@ -251,6 +265,11 @@ async function executarReconectar() {
|
|||||||
|
|
||||||
function abrirModalDesconectar(id) {
|
function abrirModalDesconectar(id) {
|
||||||
selectedInstanciaId = id;
|
selectedInstanciaId = id;
|
||||||
|
const inst = conexoes.find(c => c.id === id);
|
||||||
|
if (inst && String(inst.status || '').toLowerCase() !== 'aprovada') {
|
||||||
|
Util.toast('Esta conexão ainda está pendente de aprovação pelo administrador.', true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
desconectarStepConfirm.classList.remove('hidden');
|
desconectarStepConfirm.classList.remove('hidden');
|
||||||
desconectarStepLoading.classList.add('hidden');
|
desconectarStepLoading.classList.add('hidden');
|
||||||
desconectarModal.classList.remove('hidden');
|
desconectarModal.classList.remove('hidden');
|
||||||
@@ -286,13 +305,10 @@ form.onsubmit = async (e) => {
|
|||||||
try {
|
try {
|
||||||
if (submitBtn) submitBtn.disabled = true;
|
if (submitBtn) submitBtn.disabled = true;
|
||||||
const body = Util.formData(form);
|
const body = Util.formData(form);
|
||||||
const d = await Api.post('/api/config/evolution-instancia/conectar', body);
|
await Api.post('/api/config/evolution-instancia/conectar', body);
|
||||||
form.reset();
|
form.reset();
|
||||||
Util.toast('WhatsApp cadastrado com sucesso!');
|
Util.toast('WhatsApp cadastrado com sucesso! Aguarde a aprovação do administrador para conectar via QR Code.');
|
||||||
await load();
|
await load();
|
||||||
if (d.id) {
|
|
||||||
abrirModalQr(d.id, d);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
Util.toast(err.message, true);
|
Util.toast(err.message, true);
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
Reference in New Issue
Block a user