Feat: Implementar API de resultados y widget de prueba dinámico con selector
API (Backend):
Se crea el endpoint GET /api/resultados/municipio/{id} para servir los resultados detallados de un municipio específico.
Se añade el endpoint GET /api/catalogos/municipios para poblar selectores en el frontend.
Se incluye un endpoint simulado GET /api/resultados/provincia/{id} para facilitar el desarrollo futuro del frontend.
Worker (Servicio de Ingesta):
La lógica de sondeo se ha hecho dinámica. Ahora consulta todos los municipios presentes en la base de datos en lugar de uno solo.
El servicio falso (FakeElectoralApiService) se ha mejorado para generar datos aleatorios para cualquier municipio solicitado.
Frontend (React):
Se crea el componente <MunicipioSelector /> que se carga con datos desde la nueva API de catálogos.
Se integra el selector en la página principal, permitiendo al usuario elegir un municipio.
El componente <MunicipioWidget /> ahora recibe el ID del municipio como una prop y muestra los datos del municipio seleccionado, actualizándose en tiempo real.
Configuración:
Se ajusta la política de CORS en la API para permitir peticiones desde el servidor de desarrollo de Vite (localhost:5173), solucionando errores de conexión en el entorno local.
This commit is contained in:
24
Elecciones-Web/frontend/.gitignore
vendored
Normal file
24
Elecciones-Web/frontend/.gitignore
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
69
Elecciones-Web/frontend/README.md
Normal file
69
Elecciones-Web/frontend/README.md
Normal file
@@ -0,0 +1,69 @@
|
||||
# React + TypeScript + Vite
|
||||
|
||||
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
||||
|
||||
Currently, two official plugins are available:
|
||||
|
||||
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) for Fast Refresh
|
||||
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
|
||||
|
||||
## Expanding the ESLint configuration
|
||||
|
||||
If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
|
||||
|
||||
```js
|
||||
export default tseslint.config([
|
||||
globalIgnores(['dist']),
|
||||
{
|
||||
files: ['**/*.{ts,tsx}'],
|
||||
extends: [
|
||||
// Other configs...
|
||||
|
||||
// Remove tseslint.configs.recommended and replace with this
|
||||
...tseslint.configs.recommendedTypeChecked,
|
||||
// Alternatively, use this for stricter rules
|
||||
...tseslint.configs.strictTypeChecked,
|
||||
// Optionally, add this for stylistic rules
|
||||
...tseslint.configs.stylisticTypeChecked,
|
||||
|
||||
// Other configs...
|
||||
],
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
project: ['./tsconfig.node.json', './tsconfig.app.json'],
|
||||
tsconfigRootDir: import.meta.dirname,
|
||||
},
|
||||
// other options...
|
||||
},
|
||||
},
|
||||
])
|
||||
```
|
||||
|
||||
You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:
|
||||
|
||||
```js
|
||||
// eslint.config.js
|
||||
import reactX from 'eslint-plugin-react-x'
|
||||
import reactDom from 'eslint-plugin-react-dom'
|
||||
|
||||
export default tseslint.config([
|
||||
globalIgnores(['dist']),
|
||||
{
|
||||
files: ['**/*.{ts,tsx}'],
|
||||
extends: [
|
||||
// Other configs...
|
||||
// Enable lint rules for React
|
||||
reactX.configs['recommended-typescript'],
|
||||
// Enable lint rules for React DOM
|
||||
reactDom.configs.recommended,
|
||||
],
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
project: ['./tsconfig.node.json', './tsconfig.app.json'],
|
||||
tsconfigRootDir: import.meta.dirname,
|
||||
},
|
||||
// other options...
|
||||
},
|
||||
},
|
||||
])
|
||||
```
|
||||
23
Elecciones-Web/frontend/eslint.config.js
Normal file
23
Elecciones-Web/frontend/eslint.config.js
Normal file
@@ -0,0 +1,23 @@
|
||||
import js from '@eslint/js'
|
||||
import globals from 'globals'
|
||||
import reactHooks from 'eslint-plugin-react-hooks'
|
||||
import reactRefresh from 'eslint-plugin-react-refresh'
|
||||
import tseslint from 'typescript-eslint'
|
||||
import { globalIgnores } from 'eslint/config'
|
||||
|
||||
export default tseslint.config([
|
||||
globalIgnores(['dist']),
|
||||
{
|
||||
files: ['**/*.{ts,tsx}'],
|
||||
extends: [
|
||||
js.configs.recommended,
|
||||
tseslint.configs.recommended,
|
||||
reactHooks.configs['recommended-latest'],
|
||||
reactRefresh.configs.vite,
|
||||
],
|
||||
languageOptions: {
|
||||
ecmaVersion: 2020,
|
||||
globals: globals.browser,
|
||||
},
|
||||
},
|
||||
])
|
||||
13
Elecciones-Web/frontend/index.html
Normal file
13
Elecciones-Web/frontend/index.html
Normal file
@@ -0,0 +1,13 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vite + React + TS</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
3661
Elecciones-Web/frontend/package-lock.json
generated
Normal file
3661
Elecciones-Web/frontend/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
30
Elecciones-Web/frontend/package.json
Normal file
30
Elecciones-Web/frontend/package.json
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"name": "frontend",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc -b && vite build",
|
||||
"lint": "eslint .",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.11.0",
|
||||
"react": "^19.1.1",
|
||||
"react-dom": "^19.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.33.0",
|
||||
"@types/react": "^19.1.10",
|
||||
"@types/react-dom": "^19.1.7",
|
||||
"@vitejs/plugin-react": "^5.0.0",
|
||||
"eslint": "^9.33.0",
|
||||
"eslint-plugin-react-hooks": "^5.2.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.20",
|
||||
"globals": "^16.3.0",
|
||||
"typescript": "~5.8.3",
|
||||
"typescript-eslint": "^8.39.1",
|
||||
"vite": "^7.1.2"
|
||||
}
|
||||
}
|
||||
1
Elecciones-Web/frontend/public/vite.svg
Normal file
1
Elecciones-Web/frontend/public/vite.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
42
Elecciones-Web/frontend/src/App.css
Normal file
42
Elecciones-Web/frontend/src/App.css
Normal file
@@ -0,0 +1,42 @@
|
||||
#root {
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.logo {
|
||||
height: 6em;
|
||||
padding: 1.5em;
|
||||
will-change: filter;
|
||||
transition: filter 300ms;
|
||||
}
|
||||
.logo:hover {
|
||||
filter: drop-shadow(0 0 2em #646cffaa);
|
||||
}
|
||||
.logo.react:hover {
|
||||
filter: drop-shadow(0 0 2em #61dafbaa);
|
||||
}
|
||||
|
||||
@keyframes logo-spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
a:nth-of-type(2) .logo {
|
||||
animation: logo-spin infinite 20s linear;
|
||||
}
|
||||
}
|
||||
|
||||
.card {
|
||||
padding: 2em;
|
||||
}
|
||||
|
||||
.read-the-docs {
|
||||
color: #888;
|
||||
}
|
||||
30
Elecciones-Web/frontend/src/App.tsx
Normal file
30
Elecciones-Web/frontend/src/App.tsx
Normal file
@@ -0,0 +1,30 @@
|
||||
// src/App.tsx
|
||||
import { useState } from 'react';
|
||||
import { MunicipioWidget } from './components/MunicipioWidget';
|
||||
import { MunicipioSelector } from './components/MunicipioSelector';
|
||||
import './App.css';
|
||||
|
||||
function App() {
|
||||
const [selectedMunicipioId, setSelectedMunicipioId] = useState<string | null>(null);
|
||||
|
||||
return (
|
||||
<>
|
||||
<h1>Elecciones 2025 - Resultados en Vivo</h1>
|
||||
|
||||
{/* Aquí podrías poner el widget del Resumen Provincial */}
|
||||
|
||||
<hr />
|
||||
|
||||
<h2>Consulta por Municipio</h2>
|
||||
<MunicipioSelector onMunicipioChange={setSelectedMunicipioId} />
|
||||
|
||||
{selectedMunicipioId && (
|
||||
<div style={{ marginTop: '20px' }}>
|
||||
<MunicipioWidget municipioId={selectedMunicipioId} />
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
37
Elecciones-Web/frontend/src/components/MunicipioSelector.tsx
Normal file
37
Elecciones-Web/frontend/src/components/MunicipioSelector.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
// src/components/MunicipioSelector.tsx
|
||||
import { useState, useEffect } from 'react';
|
||||
import { getMunicipios, type MunicipioSimple } from '../services/api';
|
||||
|
||||
interface Props {
|
||||
onMunicipioChange: (municipioId: string) => void;
|
||||
}
|
||||
|
||||
export const MunicipioSelector = ({ onMunicipioChange }: Props) => {
|
||||
const [municipios, setMunicipios] = useState<MunicipioSimple[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
const loadMunicipios = async () => {
|
||||
try {
|
||||
const data = await getMunicipios();
|
||||
setMunicipios(data);
|
||||
} catch (error) {
|
||||
console.error("Error al cargar municipios", error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
loadMunicipios();
|
||||
}, []);
|
||||
|
||||
if (loading) return <p>Cargando municipios...</p>;
|
||||
|
||||
return (
|
||||
<select onChange={(e) => onMunicipioChange(e.target.value)} defaultValue="">
|
||||
<option value="" disabled>Seleccione un municipio</option>
|
||||
{municipios.map(m => (
|
||||
<option key={m.id} value={m.id}>{m.nombre}</option>
|
||||
))}
|
||||
</select>
|
||||
);
|
||||
};
|
||||
69
Elecciones-Web/frontend/src/components/MunicipioWidget.tsx
Normal file
69
Elecciones-Web/frontend/src/components/MunicipioWidget.tsx
Normal file
@@ -0,0 +1,69 @@
|
||||
// src/components/MunicipioWidget.tsx
|
||||
import { useState, useEffect } from 'react';
|
||||
import { getResultadosPorMunicipio, type MunicipioResultados } from '../services/api';
|
||||
|
||||
interface Props {
|
||||
municipioId: string;
|
||||
}
|
||||
|
||||
export const MunicipioWidget = ({ municipioId }: Props) => {
|
||||
const [data, setData] = useState<MunicipioResultados | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const resultados = await getResultadosPorMunicipio(municipioId);
|
||||
setData(resultados);
|
||||
setError(null);
|
||||
} catch (err) {
|
||||
setError('No se pudieron cargar los datos.');
|
||||
console.error(err);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// Hacemos la primera llamada inmediatamente
|
||||
fetchData();
|
||||
|
||||
// Creamos un intervalo para refrescar los datos cada 10 segundos
|
||||
const intervalId = setInterval(fetchData, 10000);
|
||||
|
||||
// ¡Importante! Limpiamos el intervalo cuando el componente se desmonta
|
||||
return () => clearInterval(intervalId);
|
||||
}, [municipioId]); // El efecto se volverá a ejecutar si el municipioId cambia
|
||||
|
||||
if (loading && !data) return <div>Cargando resultados...</div>;
|
||||
if (error) return <div style={{ color: 'red' }}>{error}</div>;
|
||||
if (!data) return <div>No hay datos disponibles.</div>;
|
||||
|
||||
return (
|
||||
<div style={{ fontFamily: 'sans-serif', border: '1px solid #ccc', padding: '16px', borderRadius: '8px' }}>
|
||||
<h2>{data.municipioNombre}</h2>
|
||||
<p>Escrutado: {data.porcentajeEscrutado.toFixed(2)}% | Participación: {data.porcentajeParticipacion.toFixed(2)}%</p>
|
||||
<hr />
|
||||
<table style={{ width: '100%', borderCollapse: 'collapse' }}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style={{ textAlign: 'left' }}>Agrupación</th>
|
||||
<th style={{ textAlign: 'right' }}>Votos</th>
|
||||
<th style={{ textAlign: 'right' }}>%</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{data.resultados.map((partido) => (
|
||||
<tr key={partido.nombre}>
|
||||
<td>{partido.nombre}</td>
|
||||
<td style={{ textAlign: 'right' }}>{partido.votos.toLocaleString('es-AR')}</td>
|
||||
<td style={{ textAlign: 'right' }}>{partido.porcentaje.toFixed(2)}%</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
<p style={{fontSize: '0.8em', color: '#666'}}>Última actualización: {new Date(data.ultimaActualizacion).toLocaleTimeString('es-AR')}</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
68
Elecciones-Web/frontend/src/index.css
Normal file
68
Elecciones-Web/frontend/src/index.css
Normal file
@@ -0,0 +1,68 @@
|
||||
:root {
|
||||
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
|
||||
line-height: 1.5;
|
||||
font-weight: 400;
|
||||
|
||||
color-scheme: light dark;
|
||||
color: rgba(255, 255, 255, 0.87);
|
||||
background-color: #242424;
|
||||
|
||||
font-synthesis: none;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
a {
|
||||
font-weight: 500;
|
||||
color: #646cff;
|
||||
text-decoration: inherit;
|
||||
}
|
||||
a:hover {
|
||||
color: #535bf2;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
display: flex;
|
||||
place-items: center;
|
||||
min-width: 320px;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 3.2em;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 8px;
|
||||
border: 1px solid transparent;
|
||||
padding: 0.6em 1.2em;
|
||||
font-size: 1em;
|
||||
font-weight: 500;
|
||||
font-family: inherit;
|
||||
background-color: #1a1a1a;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.25s;
|
||||
}
|
||||
button:hover {
|
||||
border-color: #646cff;
|
||||
}
|
||||
button:focus,
|
||||
button:focus-visible {
|
||||
outline: 4px auto -webkit-focus-ring-color;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
:root {
|
||||
color: #213547;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
a:hover {
|
||||
color: #747bff;
|
||||
}
|
||||
button {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
}
|
||||
10
Elecciones-Web/frontend/src/main.tsx
Normal file
10
Elecciones-Web/frontend/src/main.tsx
Normal file
@@ -0,0 +1,10 @@
|
||||
import { StrictMode } from 'react'
|
||||
import { createRoot } from 'react-dom/client'
|
||||
import './index.css'
|
||||
import App from './App.tsx'
|
||||
|
||||
createRoot(document.getElementById('root')!).render(
|
||||
<StrictMode>
|
||||
<App />
|
||||
</StrictMode>,
|
||||
)
|
||||
56
Elecciones-Web/frontend/src/services/api.ts
Normal file
56
Elecciones-Web/frontend/src/services/api.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
// src/services/api.ts
|
||||
import axios from 'axios';
|
||||
|
||||
// Creamos una instancia de Axios.
|
||||
// OJO: Usamos el puerto del PROXY (8600) que configuramos en docker-compose.yml
|
||||
// No usamos el puerto de la API de .NET directamente.
|
||||
const apiClient = axios.create({
|
||||
baseURL: 'http://localhost:5217/api'
|
||||
});
|
||||
|
||||
// Definimos las interfaces de TypeScript que coinciden con los DTOs de nuestra API.
|
||||
export interface AgrupacionResultado {
|
||||
nombre: string;
|
||||
votos: number;
|
||||
porcentaje: number;
|
||||
}
|
||||
|
||||
export interface VotosAdicionales {
|
||||
enBlanco: number;
|
||||
nulos: number;
|
||||
recurridos: number;
|
||||
}
|
||||
|
||||
export interface MunicipioResultados {
|
||||
municipioNombre: string;
|
||||
ultimaActualizacion: string; // La fecha viene como string
|
||||
porcentajeEscrutado: number;
|
||||
porcentajeParticipacion: number;
|
||||
resultados: AgrupacionResultado[];
|
||||
votosAdicionales: VotosAdicionales;
|
||||
}
|
||||
|
||||
export interface MunicipioSimple {
|
||||
id: string;
|
||||
nombre: string;
|
||||
}
|
||||
|
||||
export interface ResumenProvincial extends Omit<MunicipioResultados, 'municipioNombre'> {
|
||||
provinciaNombre: string;
|
||||
}
|
||||
|
||||
export const getMunicipios = async (): Promise<MunicipioSimple[]> => {
|
||||
const response = await apiClient.get<MunicipioSimple[]>('/catalogos/municipios');
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const getResumenProvincial = async (distritoId: string): Promise<ResumenProvincial> => {
|
||||
const response = await apiClient.get<ResumenProvincial>(`/resultados/provincia/${distritoId}`);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
// Función para obtener los resultados de un municipio
|
||||
export const getResultadosPorMunicipio = async (municipioId: string): Promise<MunicipioResultados> => {
|
||||
const response = await apiClient.get<MunicipioResultados>(`/resultados/municipio/${municipioId}`);
|
||||
return response.data;
|
||||
};
|
||||
1
Elecciones-Web/frontend/src/vite-env.d.ts
vendored
Normal file
1
Elecciones-Web/frontend/src/vite-env.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/// <reference types="vite/client" />
|
||||
27
Elecciones-Web/frontend/tsconfig.app.json
Normal file
27
Elecciones-Web/frontend/tsconfig.app.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
||||
"target": "ES2022",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"erasableSyntaxOnly": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedSideEffectImports": true
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
7
Elecciones-Web/frontend/tsconfig.json
Normal file
7
Elecciones-Web/frontend/tsconfig.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"files": [],
|
||||
"references": [
|
||||
{ "path": "./tsconfig.app.json" },
|
||||
{ "path": "./tsconfig.node.json" }
|
||||
]
|
||||
}
|
||||
25
Elecciones-Web/frontend/tsconfig.node.json
Normal file
25
Elecciones-Web/frontend/tsconfig.node.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
||||
"target": "ES2023",
|
||||
"lib": ["ES2023"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"erasableSyntaxOnly": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedSideEffectImports": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
||||
7
Elecciones-Web/frontend/vite.config.ts
Normal file
7
Elecciones-Web/frontend/vite.config.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
|
||||
// https://vite.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
})
|
||||
@@ -0,0 +1,38 @@
|
||||
using Elecciones.Core.DTOs.ApiResponses;
|
||||
using Elecciones.Database;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Elecciones.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class CatalogosController : ControllerBase
|
||||
{
|
||||
private readonly EleccionesDbContext _dbContext;
|
||||
|
||||
public CatalogosController(EleccionesDbContext dbContext)
|
||||
{
|
||||
_dbContext = dbContext;
|
||||
}
|
||||
|
||||
[HttpGet("municipios")]
|
||||
public async Task<IActionResult> GetMunicipios()
|
||||
{
|
||||
// El NivelId 5 corresponde a "Municipio" según los datos que hemos visto.
|
||||
var municipios = await _dbContext.AmbitosGeograficos
|
||||
.AsNoTracking()
|
||||
.Where(a => a.NivelId == 5 && a.MunicipioId != null)
|
||||
.Select(a => new MunicipioSimpleDto
|
||||
{
|
||||
Id = a.MunicipioId!,
|
||||
Nombre = a.Nombre
|
||||
})
|
||||
.OrderBy(m => m.Nombre)
|
||||
.ToListAsync();
|
||||
|
||||
return Ok(municipios);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
// src/Elecciones.Api/Controllers/ResultadosController.cs
|
||||
using Elecciones.Core.DTOs.ApiResponses;
|
||||
using Elecciones.Database;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Elecciones.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class ResultadosController : ControllerBase
|
||||
{
|
||||
private readonly EleccionesDbContext _dbContext;
|
||||
private readonly ILogger<ResultadosController> _logger;
|
||||
|
||||
public ResultadosController(EleccionesDbContext dbContext, ILogger<ResultadosController> logger)
|
||||
{
|
||||
_dbContext = dbContext;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
[HttpGet("municipio/{municipioId}")]
|
||||
public async Task<IActionResult> GetResultadosPorMunicipio(string municipioId)
|
||||
{
|
||||
// 1. Buscamos el ámbito geográfico correspondiente al municipio
|
||||
var ambito = await _dbContext.AmbitosGeograficos
|
||||
.AsNoTracking()
|
||||
.FirstOrDefaultAsync(a => a.MunicipioId == municipioId);
|
||||
|
||||
if (ambito == null)
|
||||
{
|
||||
return NotFound(new { message = $"No se encontró el municipio con ID {municipioId}" });
|
||||
}
|
||||
|
||||
// 2. Buscamos el estado del recuento para ese ámbito
|
||||
var estadoRecuento = await _dbContext.EstadosRecuentos
|
||||
.AsNoTracking()
|
||||
.FirstOrDefaultAsync(e => e.AmbitoGeograficoId == ambito.Id);
|
||||
|
||||
if (estadoRecuento == null)
|
||||
{
|
||||
return NotFound(new { message = $"No se han encontrado resultados para el municipio {ambito.Nombre}" });
|
||||
}
|
||||
|
||||
// 3. Buscamos todos los votos para ese ámbito, incluyendo el nombre de la agrupación
|
||||
var resultadosVotos = await _dbContext.ResultadosVotos
|
||||
.AsNoTracking()
|
||||
.Include(rv => rv.AgrupacionPolitica) // ¡Crucial para obtener el nombre del partido!
|
||||
.Where(rv => rv.AmbitoGeograficoId == ambito.Id)
|
||||
.ToListAsync();
|
||||
|
||||
// 4. Calculamos el total de votos positivos para el porcentaje
|
||||
long totalVotosPositivos = resultadosVotos.Sum(r => r.CantidadVotos);
|
||||
|
||||
// 5. Mapeamos todo a nuestro DTO de respuesta
|
||||
var respuestaDto = new MunicipioResultadosDto
|
||||
{
|
||||
MunicipioNombre = ambito.Nombre,
|
||||
UltimaActualizacion = estadoRecuento.FechaTotalizacion,
|
||||
PorcentajeEscrutado = estadoRecuento.MesasTotalizadas * 100.0m / (estadoRecuento.MesasEsperadas > 0 ? estadoRecuento.MesasEsperadas : 1),
|
||||
PorcentajeParticipacion = estadoRecuento.ParticipacionPorcentaje,
|
||||
Resultados = resultadosVotos.Select(rv => new AgrupacionResultadoDto
|
||||
{
|
||||
Nombre = rv.AgrupacionPolitica.Nombre,
|
||||
Votos = rv.CantidadVotos,
|
||||
Porcentaje = totalVotosPositivos > 0 ? (rv.CantidadVotos * 100.0m / totalVotosPositivos) : 0
|
||||
}).OrderByDescending(r => r.Votos).ToList(),
|
||||
VotosAdicionales = new VotosAdicionalesDto
|
||||
{
|
||||
EnBlanco = estadoRecuento.VotosEnBlanco,
|
||||
Nulos = estadoRecuento.VotosNulos,
|
||||
Recurridos = estadoRecuento.VotosRecurridos
|
||||
}
|
||||
};
|
||||
|
||||
// Devolvemos el resultado
|
||||
return Ok(respuestaDto);
|
||||
}
|
||||
|
||||
[HttpGet("provincia/{distritoId}")]
|
||||
public async Task<IActionResult> GetResultadosProvinciales(string distritoId)
|
||||
{
|
||||
// TODO: Esta lógica debe ser reemplazada para leer datos reales de la BD
|
||||
// cuando el worker comience a ingestar los totales a nivel provincial.
|
||||
// Por ahora, devolvemos datos simulados para permitir el desarrollo del frontend.
|
||||
|
||||
var ambito = await _dbContext.AmbitosGeograficos.AsNoTracking()
|
||||
.FirstOrDefaultAsync(a => a.DistritoId == distritoId && a.NivelId == 10);
|
||||
|
||||
if (ambito == null)
|
||||
{
|
||||
return NotFound(new { message = "No se encontró la provincia" });
|
||||
}
|
||||
|
||||
// Simulación
|
||||
var random = new Random();
|
||||
var respuestaSimulada = new ResumenProvincialDto
|
||||
{
|
||||
ProvinciaNombre = ambito.Nombre,
|
||||
UltimaActualizacion = DateTime.UtcNow,
|
||||
PorcentajeEscrutado = 78.45m,
|
||||
PorcentajeParticipacion = 65.12m,
|
||||
Resultados =
|
||||
[
|
||||
new() { Nombre = "ALIANZA POR EL FUTURO", Votos = 2500000 + random.Next(1, 1000), Porcentaje = 45.12m },
|
||||
new() { Nombre = "FRENTE DE AVANZADA", Votos = 2100000 + random.Next(1, 1000), Porcentaje = 38.78m },
|
||||
new() { Nombre = "UNION POPULAR", Votos = 800000 + random.Next(1, 1000), Porcentaje = 14.10m },
|
||||
],
|
||||
VotosAdicionales = new VotosAdicionalesDto { EnBlanco = 150000, Nulos = 80000, Recurridos = 1200 }
|
||||
};
|
||||
|
||||
return Ok(await Task.FromResult(respuestaSimulada));
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ builder.Services.AddCors(options =>
|
||||
{
|
||||
options.AddDefaultPolicy(policy =>
|
||||
{
|
||||
policy.WithOrigins("http://localhost:8600", "http://www.eldia.com", "http://elecciones2025.eldia.com") // Añade aquí los dominios que necesites
|
||||
policy.WithOrigins("http://localhost:5173", "http://localhost:8600", "http://www.eldia.com", "http://elecciones2025.eldia.com") // Añade aquí los dominios que necesites
|
||||
.AllowAnyHeader()
|
||||
.AllowAnyMethod();
|
||||
});
|
||||
|
||||
@@ -540,6 +540,18 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Configuration/9.0.8": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Primitives": "9.0.8"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net9.0/Microsoft.Extensions.Configuration.dll": {
|
||||
"assemblyVersion": "9.0.0.0",
|
||||
"fileVersion": "9.0.825.36511"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Configuration.Abstractions/9.0.8": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Primitives": "9.0.8"
|
||||
@@ -551,6 +563,17 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Configuration.Binder/9.0.8": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net9.0/Microsoft.Extensions.Configuration.Binder.dll": {
|
||||
"assemblyVersion": "9.0.0.0",
|
||||
"fileVersion": "9.0.825.36511"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection/9.0.8": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8"
|
||||
@@ -578,6 +601,47 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Diagnostics/9.0.8": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration": "9.0.8",
|
||||
"Microsoft.Extensions.Diagnostics.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Options.ConfigurationExtensions": "9.0.8"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net9.0/Microsoft.Extensions.Diagnostics.dll": {
|
||||
"assemblyVersion": "9.0.0.0",
|
||||
"fileVersion": "9.0.825.36511"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Diagnostics.Abstractions/9.0.8": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Options": "9.0.8"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net9.0/Microsoft.Extensions.Diagnostics.Abstractions.dll": {
|
||||
"assemblyVersion": "9.0.0.0",
|
||||
"fileVersion": "9.0.825.36511"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Http/9.0.8": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Diagnostics": "9.0.8",
|
||||
"Microsoft.Extensions.Logging": "9.0.8",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Options": "9.0.8"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net9.0/Microsoft.Extensions.Http.dll": {
|
||||
"assemblyVersion": "9.0.0.0",
|
||||
"fileVersion": "9.0.825.36511"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Logging/9.0.8": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.8",
|
||||
@@ -614,6 +678,21 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Options.ConfigurationExtensions/9.0.8": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Configuration.Binder": "9.0.8",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Options": "9.0.8",
|
||||
"Microsoft.Extensions.Primitives": "9.0.8"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net9.0/Microsoft.Extensions.Options.ConfigurationExtensions.dll": {
|
||||
"assemblyVersion": "9.0.0.0",
|
||||
"fileVersion": "9.0.825.36511"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Primitives/9.0.8": {
|
||||
"runtime": {
|
||||
"lib/net9.0/Microsoft.Extensions.Primitives.dll": {
|
||||
@@ -1090,7 +1169,9 @@
|
||||
},
|
||||
"Elecciones.Infrastructure/1.0.0": {
|
||||
"dependencies": {
|
||||
"Elecciones.Core": "1.0.0"
|
||||
"Elecciones.Core": "1.0.0",
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Http": "9.0.8"
|
||||
},
|
||||
"runtime": {
|
||||
"Elecciones.Infrastructure.dll": {
|
||||
@@ -1289,6 +1370,13 @@
|
||||
"path": "microsoft.extensions.caching.memory/9.0.8",
|
||||
"hashPath": "microsoft.extensions.caching.memory.9.0.8.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.Extensions.Configuration/9.0.8": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-6m+8Xgmf8UWL0p/oGqBM+0KbHE5/ePXbV1hKXgC59zEv0aa0DW5oiiyxDbK5kH5j4gIvyD5uWL0+HadKBJngvQ==",
|
||||
"path": "microsoft.extensions.configuration/9.0.8",
|
||||
"hashPath": "microsoft.extensions.configuration.9.0.8.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.Extensions.Configuration.Abstractions/9.0.8": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
@@ -1296,6 +1384,13 @@
|
||||
"path": "microsoft.extensions.configuration.abstractions/9.0.8",
|
||||
"hashPath": "microsoft.extensions.configuration.abstractions.9.0.8.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.Extensions.Configuration.Binder/9.0.8": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-0vK9DnYrYChdiH3yRZWkkp4x4LbrfkWEdBc5HOsQ8t/0CLOWKXKkkhOE8A1shlex0hGydbGrhObeypxz/QTm+w==",
|
||||
"path": "microsoft.extensions.configuration.binder/9.0.8",
|
||||
"hashPath": "microsoft.extensions.configuration.binder.9.0.8.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection/9.0.8": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
@@ -1317,6 +1412,27 @@
|
||||
"path": "microsoft.extensions.dependencymodel/9.0.8",
|
||||
"hashPath": "microsoft.extensions.dependencymodel.9.0.8.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.Extensions.Diagnostics/9.0.8": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-BKkLCFXzJvNmdngeYBf72VXoZqTJSb1orvjdzDLaGobicoGFBPW8ug2ru1nnEewMEwJzMgnsjHQY8EaKWmVhKg==",
|
||||
"path": "microsoft.extensions.diagnostics/9.0.8",
|
||||
"hashPath": "microsoft.extensions.diagnostics.9.0.8.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.Extensions.Diagnostics.Abstractions/9.0.8": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-UDY7blv4DCyIJ/8CkNrQKLaAZFypXQavRZ2DWf/2zi1mxYYKKw2t8AOCBWxNntyPZHPGhtEmL3snFM98ADZqTw==",
|
||||
"path": "microsoft.extensions.diagnostics.abstractions/9.0.8",
|
||||
"hashPath": "microsoft.extensions.diagnostics.abstractions.9.0.8.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.Extensions.Http/9.0.8": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-jDj+4aDByk47oESlDDTtk6LWzlXlmoCsjCn6ihd+i9OntN885aPLszUII5+w0B/7wYSZcS3KdjqLAIhKLSiBXQ==",
|
||||
"path": "microsoft.extensions.http/9.0.8",
|
||||
"hashPath": "microsoft.extensions.http.9.0.8.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.Extensions.Logging/9.0.8": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
@@ -1338,6 +1454,13 @@
|
||||
"path": "microsoft.extensions.options/9.0.8",
|
||||
"hashPath": "microsoft.extensions.options.9.0.8.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.Extensions.Options.ConfigurationExtensions/9.0.8": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-eW2s6n06x0w6w4nsX+SvpgsFYkl+Y0CttYAt6DKUXeqprX+hzNqjSfOh637fwNJBg7wRBrOIRHe49gKiTgJxzQ==",
|
||||
"path": "microsoft.extensions.options.configurationextensions/9.0.8",
|
||||
"hashPath": "microsoft.extensions.options.configurationextensions.9.0.8.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.Extensions.Primitives/9.0.8": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
|
||||
@@ -13,7 +13,7 @@ using System.Reflection;
|
||||
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Api")]
|
||||
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
||||
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+d9bcfd70865a12c229e6a761639094b45de862bd")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+b90baadeedb870b5b1c9eeeb7022a0d211b61bec")]
|
||||
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Api")]
|
||||
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Api")]
|
||||
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||
|
||||
@@ -167,3 +167,9 @@ E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\obj\Debug\net9.0\refint\Ele
|
||||
E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\obj\Debug\net9.0\Elecciones.Api.pdb
|
||||
E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\obj\Debug\net9.0\Elecciones.Api.genruntimeconfig.cache
|
||||
E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\obj\Debug\net9.0\ref\Elecciones.Api.dll
|
||||
E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Microsoft.Extensions.Configuration.dll
|
||||
E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Microsoft.Extensions.Configuration.Binder.dll
|
||||
E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Microsoft.Extensions.Diagnostics.dll
|
||||
E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Microsoft.Extensions.Diagnostics.Abstractions.dll
|
||||
E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Microsoft.Extensions.Http.dll
|
||||
E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Microsoft.Extensions.Options.ConfigurationExtensions.dll
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"GlobalPropertiesHash":"b5T/+ta4fUd8qpIzUTm3KyEwAYYUsU5ASo+CSFM3ByE=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["mhE0FuBM0BOF9SNOE0rY9setCw2ye3UUh7cEPjhgDdY=","AE1TAk4qas82IfXTyRHo\u002BfMlnTE4e7B1AJrEn9ZhBwo=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","ywKm3DCyXg4YCbZAIx3JUlT8N4Irff3GswYUVDST\u002BjQ=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","lxebrAqmCStl1yDKQUlHmeuz9HkimDnS\u002B/df3f1dyII="],"CachedAssets":{},"CachedCopyCandidates":{}}
|
||||
{"GlobalPropertiesHash":"b5T/+ta4fUd8qpIzUTm3KyEwAYYUsU5ASo+CSFM3ByE=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["mhE0FuBM0BOF9SNOE0rY9setCw2ye3UUh7cEPjhgDdY=","AE1TAk4qas82IfXTyRHo\u002BfMlnTE4e7B1AJrEn9ZhBwo=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","ywKm3DCyXg4YCbZAIx3JUlT8N4Irff3GswYUVDST\u002BjQ=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","r5wfLIFTEo2\u002Bd7Tsx44bFIb0SPNdPvg4KbBRNmbWVFA="],"CachedAssets":{},"CachedCopyCandidates":{}}
|
||||
@@ -1 +1 @@
|
||||
{"GlobalPropertiesHash":"tJTBjV/i0Ihkc6XuOu69wxL8PBac9c9Kak6srMso4pU=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["mhE0FuBM0BOF9SNOE0rY9setCw2ye3UUh7cEPjhgDdY=","AE1TAk4qas82IfXTyRHo\u002BfMlnTE4e7B1AJrEn9ZhBwo=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","ywKm3DCyXg4YCbZAIx3JUlT8N4Irff3GswYUVDST\u002BjQ=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","lxebrAqmCStl1yDKQUlHmeuz9HkimDnS\u002B/df3f1dyII="],"CachedAssets":{},"CachedCopyCandidates":{}}
|
||||
{"GlobalPropertiesHash":"tJTBjV/i0Ihkc6XuOu69wxL8PBac9c9Kak6srMso4pU=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["mhE0FuBM0BOF9SNOE0rY9setCw2ye3UUh7cEPjhgDdY=","AE1TAk4qas82IfXTyRHo\u002BfMlnTE4e7B1AJrEn9ZhBwo=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","ywKm3DCyXg4YCbZAIx3JUlT8N4Irff3GswYUVDST\u002BjQ=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","r5wfLIFTEo2\u002Bd7Tsx44bFIb0SPNdPvg4KbBRNmbWVFA="],"CachedAssets":{},"CachedCopyCandidates":{}}
|
||||
@@ -290,6 +290,16 @@
|
||||
"frameworks": {
|
||||
"net9.0": {
|
||||
"targetAlias": "net9.0",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration.Abstractions": {
|
||||
"target": "Package",
|
||||
"version": "[9.0.8, )"
|
||||
},
|
||||
"Microsoft.Extensions.Http": {
|
||||
"target": "Package",
|
||||
"version": "[9.0.8, )"
|
||||
}
|
||||
},
|
||||
"imports": [
|
||||
"net461",
|
||||
"net462",
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
<Import Project="$(NuGetPackageRoot)microsoft.extensions.apidescription.server\9.0.0\build\Microsoft.Extensions.ApiDescription.Server.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.apidescription.server\9.0.0\build\Microsoft.Extensions.ApiDescription.Server.targets')" />
|
||||
<Import Project="$(NuGetPackageRoot)mono.texttemplating\3.0.0\buildTransitive\Mono.TextTemplating.targets" Condition="Exists('$(NuGetPackageRoot)mono.texttemplating\3.0.0\buildTransitive\Mono.TextTemplating.targets')" />
|
||||
<Import Project="$(NuGetPackageRoot)microsoft.extensions.options\9.0.8\buildTransitive\net8.0\Microsoft.Extensions.Options.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.options\9.0.8\buildTransitive\net8.0\Microsoft.Extensions.Options.targets')" />
|
||||
<Import Project="$(NuGetPackageRoot)microsoft.extensions.configuration.binder\9.0.8\buildTransitive\netstandard2.0\Microsoft.Extensions.Configuration.Binder.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.configuration.binder\9.0.8\buildTransitive\netstandard2.0\Microsoft.Extensions.Configuration.Binder.targets')" />
|
||||
<Import Project="$(NuGetPackageRoot)microsoft.extensions.logging.abstractions\9.0.8\buildTransitive\net8.0\Microsoft.Extensions.Logging.Abstractions.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.logging.abstractions\9.0.8\buildTransitive\net8.0\Microsoft.Extensions.Logging.Abstractions.targets')" />
|
||||
<Import Project="$(NuGetPackageRoot)microsoft.codeanalysis.analyzers\3.3.4\buildTransitive\Microsoft.CodeAnalysis.Analyzers.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.codeanalysis.analyzers\3.3.4\buildTransitive\Microsoft.CodeAnalysis.Analyzers.targets')" />
|
||||
</ImportGroup>
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
namespace Elecciones.Core;
|
||||
|
||||
public class Class1
|
||||
{
|
||||
|
||||
}
|
||||
16
Elecciones-Web/src/Elecciones.Core/DTOs/AgrupacionDto.cs
Normal file
16
Elecciones-Web/src/Elecciones.Core/DTOs/AgrupacionDto.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
// src/Elecciones.Core/DTOs/AgrupacionDto.cs
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Elecciones.Core.DTOs;
|
||||
|
||||
public class AgrupacionDto
|
||||
{
|
||||
[JsonPropertyName("idAgrupacion")]
|
||||
public string IdAgrupacion { get; set; } = null!;
|
||||
|
||||
[JsonPropertyName("idAgrupacionTelegrama")]
|
||||
public string IdAgrupacionTelegrama { get; set; } = null!;
|
||||
|
||||
[JsonPropertyName("nombreAgrupacion")]
|
||||
public string NombreAgrupacion { get; set; } = null!;
|
||||
}
|
||||
16
Elecciones-Web/src/Elecciones.Core/DTOs/AmbitoDto.cs
Normal file
16
Elecciones-Web/src/Elecciones.Core/DTOs/AmbitoDto.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
// src/Elecciones.Core/DTOs/AmbitoDto.cs
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Elecciones.Core.DTOs;
|
||||
|
||||
public class AmbitoDto
|
||||
{
|
||||
[JsonPropertyName("nivelld")]
|
||||
public int NivelId { get; set; }
|
||||
|
||||
[JsonPropertyName("nombre")]
|
||||
public string Nombre { get; set; } = null!;
|
||||
|
||||
[JsonPropertyName("codigoAmbitos")]
|
||||
public CodigoAmbitoDto CodigoAmbitos { get; set; } = null!;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// src/Elecciones.Core/DTOs/ApiResponses/AgrupacionResultadoDto.cs
|
||||
namespace Elecciones.Core.DTOs.ApiResponses;
|
||||
|
||||
public class AgrupacionResultadoDto
|
||||
{
|
||||
public string Nombre { get; set; } = null!;
|
||||
public long Votos { get; set; }
|
||||
public decimal Porcentaje { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// src/Elecciones.Core/DTOs/ApiResponses/MunicipioResultadosDto.cs
|
||||
namespace Elecciones.Core.DTOs.ApiResponses;
|
||||
|
||||
public class MunicipioResultadosDto
|
||||
{
|
||||
public string MunicipioNombre { get; set; } = null!;
|
||||
public DateTime UltimaActualizacion { get; set; }
|
||||
public decimal PorcentajeEscrutado { get; set; }
|
||||
public decimal PorcentajeParticipacion { get; set; }
|
||||
|
||||
public List<AgrupacionResultadoDto> Resultados { get; set; } = [];
|
||||
|
||||
public VotosAdicionalesDto VotosAdicionales { get; set; } = null!;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Elecciones.Core.DTOs.ApiResponses;
|
||||
|
||||
public class MunicipioSimpleDto
|
||||
{
|
||||
public string Id { get; set; } = null!;
|
||||
public string Nombre { get; set; } = null!;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace Elecciones.Core.DTOs.ApiResponses;
|
||||
|
||||
public class ResumenProvincialDto
|
||||
{
|
||||
public string ProvinciaNombre { get; set; } = null!;
|
||||
public DateTime UltimaActualizacion { get; set; }
|
||||
public decimal PorcentajeEscrutado { get; set; }
|
||||
public decimal PorcentajeParticipacion { get; set; }
|
||||
public List<AgrupacionResultadoDto> Resultados { get; set; } = [];
|
||||
public VotosAdicionalesDto VotosAdicionales { get; set; } = null!;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// src/Elecciones.Core/DTOs/ApiResponses/VotosAdicionalesDto.cs
|
||||
namespace Elecciones.Core.DTOs.ApiResponses;
|
||||
|
||||
public class VotosAdicionalesDto
|
||||
{
|
||||
public long EnBlanco { get; set; }
|
||||
public long Nulos { get; set; }
|
||||
public long Recurridos { get; set; }
|
||||
}
|
||||
19
Elecciones-Web/src/Elecciones.Core/DTOs/CatalogoDto.cs
Normal file
19
Elecciones-Web/src/Elecciones.Core/DTOs/CatalogoDto.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
// src/Elecciones.Core/DTOs/CatalogoDto.cs
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Elecciones.Core.DTOs;
|
||||
|
||||
public class CatalogoDto
|
||||
{
|
||||
[JsonPropertyName("version")]
|
||||
public int Version { get; set; }
|
||||
|
||||
[JsonPropertyName("categoriald")]
|
||||
public int CategoriaId { get; set; }
|
||||
|
||||
[JsonPropertyName("ambitos")]
|
||||
public List<AmbitoDto> Ambitos { get; set; } = [];
|
||||
|
||||
[JsonPropertyName("niveles")]
|
||||
public List<NivelDto> Niveles { get; set; } = [];
|
||||
}
|
||||
20
Elecciones-Web/src/Elecciones.Core/DTOs/CodigoAmbitoDto.cs
Normal file
20
Elecciones-Web/src/Elecciones.Core/DTOs/CodigoAmbitoDto.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
// src/Elecciones.Core/DTOs/CodigoAmbitoDto.cs
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Elecciones.Core.DTOs;
|
||||
|
||||
public class CodigoAmbitoDto
|
||||
{
|
||||
[JsonPropertyName("distritold")]
|
||||
public string DistritoId { get; set; } = null!;
|
||||
|
||||
// Hacemos que los demás IDs acepten nulos para ser más flexibles
|
||||
[JsonPropertyName("seccionProvincialld")]
|
||||
public string? SeccionProvincialId { get; set; }
|
||||
|
||||
[JsonPropertyName("seccionld")]
|
||||
public string? SeccionId { get; set; }
|
||||
|
||||
[JsonPropertyName("municipiold")]
|
||||
public string? MunicipioId { get; set; }
|
||||
}
|
||||
19
Elecciones-Web/src/Elecciones.Core/DTOs/EstadoRecuentoDto.cs
Normal file
19
Elecciones-Web/src/Elecciones.Core/DTOs/EstadoRecuentoDto.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
// src/Elecciones.Core/DTOs/EstadoRecuentoDto.cs
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Elecciones.Core.DTOs;
|
||||
|
||||
public class EstadoRecuentoDto
|
||||
{
|
||||
[JsonPropertyName("mesasEsperadas")]
|
||||
public int MesasEsperadas { get; set; }
|
||||
|
||||
[JsonPropertyName("mesasTotalizadas")]
|
||||
public int MesasTotalizadas { get; set; }
|
||||
|
||||
[JsonPropertyName("cantidadElectores")]
|
||||
public int CantidadElectores { get; set; }
|
||||
|
||||
[JsonPropertyName("participacionPorcentaje")]
|
||||
public decimal ParticipacionPorcentaje { get; set; }
|
||||
}
|
||||
13
Elecciones-Web/src/Elecciones.Core/DTOs/NivelDto.cs
Normal file
13
Elecciones-Web/src/Elecciones.Core/DTOs/NivelDto.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
// src/Elecciones.Core/DTOs/NivelDto.cs
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Elecciones.Core.DTOs;
|
||||
|
||||
public class NivelDto
|
||||
{
|
||||
[JsonPropertyName("nivelld")]
|
||||
public int NivelId { get; set; }
|
||||
|
||||
[JsonPropertyName("nombre")]
|
||||
public string Nombre { get; set; } = null!;
|
||||
}
|
||||
19
Elecciones-Web/src/Elecciones.Core/DTOs/ResultadosDto.cs
Normal file
19
Elecciones-Web/src/Elecciones.Core/DTOs/ResultadosDto.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
// src/Elecciones.Core/DTOs/ResultadosDto.cs
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Elecciones.Core.DTOs;
|
||||
|
||||
public class ResultadosDto
|
||||
{
|
||||
[JsonPropertyName("fechaTotalizacion")]
|
||||
public string FechaTotalizacion { get; set; } = null!;
|
||||
|
||||
[JsonPropertyName("estadoRecuento")]
|
||||
public EstadoRecuentoDto EstadoRecuento { get; set; } = null!;
|
||||
|
||||
[JsonPropertyName("valoresTotalizadosPositivos")]
|
||||
public List<VotosPositivosDto> ValoresTotalizadosPositivos { get; set; } = [];
|
||||
|
||||
[JsonPropertyName("valoresTotalizadosOtros")]
|
||||
public VotosOtrosDto? ValoresTotalizadosOtros { get; set; }
|
||||
}
|
||||
13
Elecciones-Web/src/Elecciones.Core/DTOs/TokenData.cs
Normal file
13
Elecciones-Web/src/Elecciones.Core/DTOs/TokenData.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
// src/Elecciones.Core/DTOs/TokenData.cs
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Elecciones.Core.DTOs;
|
||||
|
||||
public class TokenData
|
||||
{
|
||||
[JsonPropertyName("access_token")]
|
||||
public string AccessToken { get; set; } = null!;
|
||||
|
||||
[JsonPropertyName("expires_in")]
|
||||
public int ExpiresIn { get; set; }
|
||||
}
|
||||
19
Elecciones-Web/src/Elecciones.Core/DTOs/TokenResponse.cs
Normal file
19
Elecciones-Web/src/Elecciones.Core/DTOs/TokenResponse.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
// src/Elecciones.Core/DTOs/TokenResponse.cs
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Elecciones.Core.DTOs;
|
||||
|
||||
public class TokenResponse
|
||||
{
|
||||
[JsonPropertyName("success")]
|
||||
public bool Success { get; set; }
|
||||
|
||||
[JsonPropertyName("message")]
|
||||
public string Message { get; set; } = null!;
|
||||
|
||||
[JsonPropertyName("data")]
|
||||
public TokenData? Data { get; set; }
|
||||
|
||||
[JsonPropertyName("error")]
|
||||
public string? Error { get; set; }
|
||||
}
|
||||
16
Elecciones-Web/src/Elecciones.Core/DTOs/VotosOtrosDto.cs
Normal file
16
Elecciones-Web/src/Elecciones.Core/DTOs/VotosOtrosDto.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
// src/Elecciones.Core/DTOs/VotosOtrosDto.cs
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Elecciones.Core.DTOs;
|
||||
|
||||
public class VotosOtrosDto
|
||||
{
|
||||
[JsonPropertyName("votosNulos")]
|
||||
public long VotosNulos { get; set; }
|
||||
|
||||
[JsonPropertyName("votosEnBlanco")]
|
||||
public long VotosEnBlanco { get; set; }
|
||||
|
||||
[JsonPropertyName("votosRecurridosComandoImpugnados")]
|
||||
public long VotosRecurridos { get; set; }
|
||||
}
|
||||
16
Elecciones-Web/src/Elecciones.Core/DTOs/VotosPositivosDto.cs
Normal file
16
Elecciones-Web/src/Elecciones.Core/DTOs/VotosPositivosDto.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
// src/Elecciones.Core/DTOs/VotosPositivosDto.cs
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Elecciones.Core.DTOs;
|
||||
|
||||
public class VotosPositivosDto
|
||||
{
|
||||
[JsonPropertyName("idAgrupacion")]
|
||||
public string IdAgrupacion { get; set; } = null!;
|
||||
|
||||
[JsonPropertyName("nombreAgrupacion")]
|
||||
public string NombreAgrupacion { get; set; } = null!;
|
||||
|
||||
[JsonPropertyName("votos")]
|
||||
public long Votos { get; set; }
|
||||
}
|
||||
@@ -13,7 +13,7 @@ using System.Reflection;
|
||||
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Core")]
|
||||
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
||||
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+d9bcfd70865a12c229e6a761639094b45de862bd")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+b90baadeedb870b5b1c9eeeb7022a0d211b61bec")]
|
||||
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Core")]
|
||||
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Core")]
|
||||
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
namespace Elecciones.Database;
|
||||
|
||||
public class Class1
|
||||
{
|
||||
|
||||
}
|
||||
@@ -13,7 +13,7 @@ using System.Reflection;
|
||||
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Database")]
|
||||
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
||||
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+d9bcfd70865a12c229e6a761639094b45de862bd")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+b90baadeedb870b5b1c9eeeb7022a0d211b61bec")]
|
||||
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Database")]
|
||||
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Database")]
|
||||
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
namespace Elecciones.Infrastructure;
|
||||
|
||||
public class Class1
|
||||
{
|
||||
|
||||
}
|
||||
@@ -4,6 +4,11 @@
|
||||
<ProjectReference Include="..\Elecciones.Core\Elecciones.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="9.0.8" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.8" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
using Elecciones.Core.DTOs;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Json;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Elecciones.Infrastructure.Services;
|
||||
|
||||
public class ElectoralApiService : IElectoralApiService
|
||||
{
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
private readonly IConfiguration _configuration;
|
||||
|
||||
public ElectoralApiService(IHttpClientFactory httpClientFactory, IConfiguration configuration)
|
||||
{
|
||||
_httpClientFactory = httpClientFactory;
|
||||
_configuration = configuration;
|
||||
}
|
||||
|
||||
public async Task<string?> GetAuthTokenAsync()
|
||||
{
|
||||
var client = _httpClientFactory.CreateClient("ElectoralApiClient");
|
||||
var username = _configuration["ElectoralApi:Username"];
|
||||
var password = _configuration["ElectoralApi:Password"];
|
||||
|
||||
if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password)) return null;
|
||||
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, "/api/createtoken");
|
||||
request.Headers.Add("username", username);
|
||||
request.Headers.Add("password", password);
|
||||
|
||||
var response = await client.SendAsync(request);
|
||||
if (!response.IsSuccessStatusCode) return null;
|
||||
|
||||
var tokenResponse = await response.Content.ReadFromJsonAsync<TokenResponse>();
|
||||
return (tokenResponse is { Success: true, Data.AccessToken: not null })
|
||||
? tokenResponse.Data.AccessToken
|
||||
: null;
|
||||
}
|
||||
|
||||
public async Task<List<CatalogoDto>?> GetCatalogoCompletoAsync(string authToken)
|
||||
{
|
||||
var client = _httpClientFactory.CreateClient("ElectoralApiClient");
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, "/api/catalogo/getCatalogo?categoriald=5");
|
||||
request.Headers.Add("Authorization", $"Bearer {authToken}");
|
||||
|
||||
var response = await client.SendAsync(request);
|
||||
return response.IsSuccessStatusCode
|
||||
? await response.Content.ReadFromJsonAsync<List<CatalogoDto>>()
|
||||
: null;
|
||||
}
|
||||
|
||||
public async Task<List<AgrupacionDto>?> GetAgrupacionesAsync(string authToken, string distritoId, int categoriaId)
|
||||
{
|
||||
var client = _httpClientFactory.CreateClient("ElectoralApiClient");
|
||||
var requestUri = $"/api/catalogo/getAgrupaciones?distritold={distritoId}&categoriald={categoriaId}";
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, requestUri);
|
||||
request.Headers.Add("Authorization", $"Bearer {authToken}");
|
||||
|
||||
var response = await client.SendAsync(request);
|
||||
return response.IsSuccessStatusCode
|
||||
? await response.Content.ReadFromJsonAsync<List<AgrupacionDto>>()
|
||||
: null;
|
||||
}
|
||||
|
||||
public async Task<ResultadosDto?> GetResultadosAsync(string authToken, string distritoId, string seccionId, string municipioId)
|
||||
{
|
||||
var client = _httpClientFactory.CreateClient("ElectoralApiClient");
|
||||
|
||||
// Construimos la URL con todos los parámetros requeridos. Usamos categoría 5 (Diputados) como ejemplo.
|
||||
var requestUri = $"/api/resultados/getResultados?distritold={distritoId}&seccionld={seccionId}&municipiold={municipioId}&categoriald=5";
|
||||
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, requestUri);
|
||||
request.Headers.Add("Authorization", $"Bearer {authToken}");
|
||||
|
||||
var response = await client.SendAsync(request);
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return await response.Content.ReadFromJsonAsync<ResultadosDto>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
// src/Elecciones.Infrastructure/Services/FakeElectoralApiService.cs
|
||||
using Elecciones.Core.DTOs;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Elecciones.Infrastructure.Services;
|
||||
|
||||
public class FakeElectoralApiService : IElectoralApiService
|
||||
{
|
||||
private readonly ILogger<FakeElectoralApiService> _logger;
|
||||
|
||||
public FakeElectoralApiService(ILogger<FakeElectoralApiService> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public Task<string?> GetAuthTokenAsync()
|
||||
{
|
||||
_logger.LogWarning("--- USANDO SERVICIO FALSO (FAKE) ---");
|
||||
_logger.LogInformation("Simulando obtención de token...");
|
||||
string fakeToken = "FAKE_TOKEN_FOR_DEVELOPMENT";
|
||||
return Task.FromResult<string?>(fakeToken);
|
||||
}
|
||||
|
||||
public Task<List<CatalogoDto>?> GetCatalogoCompletoAsync(string authToken)
|
||||
{
|
||||
_logger.LogInformation("Simulando obtención de Catálogo Completo...");
|
||||
|
||||
var catalogo = new List<CatalogoDto>
|
||||
{
|
||||
new() // Simulamos el catálogo para la categoría de Diputados (ID 5)
|
||||
{
|
||||
Version = 1,
|
||||
CategoriaId = 5,
|
||||
Ambitos =
|
||||
[
|
||||
new() { NivelId = 10, Nombre = "BUENOS AIRES", CodigoAmbitos = new() { DistritoId = "02" } },
|
||||
new() { NivelId = 5, Nombre = "LA PLATA", CodigoAmbitos = new() { DistritoId = "02", SeccionId = "0001", MunicipioId = "056" } },
|
||||
new() { NivelId = 5, Nombre = "MAR DEL PLATA", CodigoAmbitos = new() { DistritoId = "02", SeccionId = "0005", MunicipioId = "035" } }
|
||||
],
|
||||
Niveles =
|
||||
[
|
||||
new() { NivelId = 10, Nombre = "Provincia" },
|
||||
new() { NivelId = 5, Nombre = "Municipio" }
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
return Task.FromResult<List<CatalogoDto>?>(catalogo);
|
||||
}
|
||||
|
||||
public Task<List<AgrupacionDto>?> GetAgrupacionesAsync(string authToken, string distritoId, int categoriaId)
|
||||
{
|
||||
_logger.LogInformation("Simulando obtención de Agrupaciones Políticas para el distrito {Distrito} y categoría {Categoria}...", distritoId, categoriaId);
|
||||
|
||||
var agrupaciones = new List<AgrupacionDto>
|
||||
{
|
||||
new() { IdAgrupacion = "018", IdAgrupacionTelegrama = "131", NombreAgrupacion = "FRENTE DE AVANZADA" },
|
||||
new() { IdAgrupacion = "025", IdAgrupacionTelegrama = "132", NombreAgrupacion = "ALIANZA POR EL FUTURO" },
|
||||
new() { IdAgrupacion = "031", IdAgrupacionTelegrama = "133", NombreAgrupacion = "UNION POPULAR" },
|
||||
new() { IdAgrupacion = "045", IdAgrupacionTelegrama = "134", NombreAgrupacion = "PARTIDO VECINALISTA" }
|
||||
};
|
||||
|
||||
return Task.FromResult<List<AgrupacionDto>?>(agrupaciones);
|
||||
}
|
||||
|
||||
public Task<ResultadosDto?> GetResultadosAsync(string authToken, string distritoId, string seccionId, string municipioId)
|
||||
{
|
||||
_logger.LogInformation("Simulando obtención de Resultados para el municipio {MunicipioId}...", municipioId);
|
||||
|
||||
// YA NO FILTRAMOS POR ID. DEVOLVEMOS DATOS SIMULADOS PARA CUALQUIER MUNICIPIO.
|
||||
|
||||
var random = new Random();
|
||||
var resultados = new ResultadosDto
|
||||
{
|
||||
FechaTotalizacion = DateTime.Now.ToString("o"),
|
||||
EstadoRecuento = new EstadoRecuentoDto
|
||||
{
|
||||
MesasEsperadas = random.Next(100, 2000), // Hacemos que varíe
|
||||
MesasTotalizadas = random.Next(50, 100),
|
||||
CantidadElectores = random.Next(50000, 600000),
|
||||
ParticipacionPorcentaje = random.Next(60, 85) + (decimal)random.NextDouble()
|
||||
},
|
||||
ValoresTotalizadosPositivos =
|
||||
[
|
||||
// Usamos los IDs reales de nuestro catálogo de agrupaciones falsas
|
||||
new() { IdAgrupacion = "018", NombreAgrupacion = "FRENTE DE AVANZADA", Votos = random.Next(10000, 20000) },
|
||||
new() { IdAgrupacion = "025", NombreAgrupacion = "ALIANZA POR EL FUTURO", Votos = random.Next(15000, 25000) },
|
||||
new() { IdAgrupacion = "031", NombreAgrupacion = "UNION POPULAR", Votos = random.Next(5000, 10000) },
|
||||
new() { IdAgrupacion = "045", NombreAgrupacion = "PARTIDO VECINALISTA", Votos = random.Next(2000, 5000) }
|
||||
],
|
||||
ValoresTotalizadosOtros = new VotosOtrosDto
|
||||
{
|
||||
VotosEnBlanco = random.Next(1000, 2000),
|
||||
VotosNulos = random.Next(500, 1000),
|
||||
VotosRecurridos = random.Next(20, 50)
|
||||
}
|
||||
};
|
||||
|
||||
return Task.FromResult<ResultadosDto?>(resultados);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// src/Elecciones.Infrastructure/Services/IElectoralApiService.cs
|
||||
using Elecciones.Core.DTOs;
|
||||
|
||||
namespace Elecciones.Infrastructure.Services;
|
||||
|
||||
public interface IElectoralApiService
|
||||
{
|
||||
Task<string?> GetAuthTokenAsync();
|
||||
Task<List<CatalogoDto>?> GetCatalogoCompletoAsync(string authToken);
|
||||
Task<List<AgrupacionDto>?> GetAgrupacionesAsync(string authToken, string distritoId, int categoriaId);
|
||||
Task<ResultadosDto?> GetResultadosAsync(string authToken, string distritoId, string seccionId, string municipioId);
|
||||
}
|
||||
@@ -8,12 +8,167 @@
|
||||
".NETCoreApp,Version=v9.0": {
|
||||
"Elecciones.Infrastructure/1.0.0": {
|
||||
"dependencies": {
|
||||
"Elecciones.Core": "1.0.0"
|
||||
"Elecciones.Core": "1.0.0",
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Http": "9.0.8"
|
||||
},
|
||||
"runtime": {
|
||||
"Elecciones.Infrastructure.dll": {}
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Configuration/9.0.8": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Primitives": "9.0.8"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net9.0/Microsoft.Extensions.Configuration.dll": {
|
||||
"assemblyVersion": "9.0.0.0",
|
||||
"fileVersion": "9.0.825.36511"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Configuration.Abstractions/9.0.8": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Primitives": "9.0.8"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net9.0/Microsoft.Extensions.Configuration.Abstractions.dll": {
|
||||
"assemblyVersion": "9.0.0.0",
|
||||
"fileVersion": "9.0.825.36511"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Configuration.Binder/9.0.8": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net9.0/Microsoft.Extensions.Configuration.Binder.dll": {
|
||||
"assemblyVersion": "9.0.0.0",
|
||||
"fileVersion": "9.0.825.36511"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection/9.0.8": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net9.0/Microsoft.Extensions.DependencyInjection.dll": {
|
||||
"assemblyVersion": "9.0.0.0",
|
||||
"fileVersion": "9.0.825.36511"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions/9.0.8": {
|
||||
"runtime": {
|
||||
"lib/net9.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll": {
|
||||
"assemblyVersion": "9.0.0.0",
|
||||
"fileVersion": "9.0.825.36511"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Diagnostics/9.0.8": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration": "9.0.8",
|
||||
"Microsoft.Extensions.Diagnostics.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Options.ConfigurationExtensions": "9.0.8"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net9.0/Microsoft.Extensions.Diagnostics.dll": {
|
||||
"assemblyVersion": "9.0.0.0",
|
||||
"fileVersion": "9.0.825.36511"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Diagnostics.Abstractions/9.0.8": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Options": "9.0.8"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net9.0/Microsoft.Extensions.Diagnostics.Abstractions.dll": {
|
||||
"assemblyVersion": "9.0.0.0",
|
||||
"fileVersion": "9.0.825.36511"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Http/9.0.8": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Diagnostics": "9.0.8",
|
||||
"Microsoft.Extensions.Logging": "9.0.8",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Options": "9.0.8"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net9.0/Microsoft.Extensions.Http.dll": {
|
||||
"assemblyVersion": "9.0.0.0",
|
||||
"fileVersion": "9.0.825.36511"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Logging/9.0.8": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.8",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Options": "9.0.8"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net9.0/Microsoft.Extensions.Logging.dll": {
|
||||
"assemblyVersion": "9.0.0.0",
|
||||
"fileVersion": "9.0.825.36511"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Logging.Abstractions/9.0.8": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net9.0/Microsoft.Extensions.Logging.Abstractions.dll": {
|
||||
"assemblyVersion": "9.0.0.0",
|
||||
"fileVersion": "9.0.825.36511"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Options/9.0.8": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Primitives": "9.0.8"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net9.0/Microsoft.Extensions.Options.dll": {
|
||||
"assemblyVersion": "9.0.0.0",
|
||||
"fileVersion": "9.0.825.36511"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Options.ConfigurationExtensions/9.0.8": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Configuration.Binder": "9.0.8",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Options": "9.0.8",
|
||||
"Microsoft.Extensions.Primitives": "9.0.8"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net9.0/Microsoft.Extensions.Options.ConfigurationExtensions.dll": {
|
||||
"assemblyVersion": "9.0.0.0",
|
||||
"fileVersion": "9.0.825.36511"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Primitives/9.0.8": {
|
||||
"runtime": {
|
||||
"lib/net9.0/Microsoft.Extensions.Primitives.dll": {
|
||||
"assemblyVersion": "9.0.0.0",
|
||||
"fileVersion": "9.0.825.36511"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Elecciones.Core/1.0.0": {
|
||||
"runtime": {
|
||||
"Elecciones.Core.dll": {
|
||||
@@ -30,6 +185,97 @@
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Microsoft.Extensions.Configuration/9.0.8": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-6m+8Xgmf8UWL0p/oGqBM+0KbHE5/ePXbV1hKXgC59zEv0aa0DW5oiiyxDbK5kH5j4gIvyD5uWL0+HadKBJngvQ==",
|
||||
"path": "microsoft.extensions.configuration/9.0.8",
|
||||
"hashPath": "microsoft.extensions.configuration.9.0.8.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.Extensions.Configuration.Abstractions/9.0.8": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-yNou2KM35RvzOh4vUFtl2l33rWPvOCoba+nzEDJ+BgD8aOL/jew4WPCibQvntRfOJ2pJU8ARygSMD+pdjvDHuA==",
|
||||
"path": "microsoft.extensions.configuration.abstractions/9.0.8",
|
||||
"hashPath": "microsoft.extensions.configuration.abstractions.9.0.8.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.Extensions.Configuration.Binder/9.0.8": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-0vK9DnYrYChdiH3yRZWkkp4x4LbrfkWEdBc5HOsQ8t/0CLOWKXKkkhOE8A1shlex0hGydbGrhObeypxz/QTm+w==",
|
||||
"path": "microsoft.extensions.configuration.binder/9.0.8",
|
||||
"hashPath": "microsoft.extensions.configuration.binder.9.0.8.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection/9.0.8": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-JJjI2Fa+QtZcUyuNjbKn04OjIUX5IgFGFu/Xc+qvzh1rXdZHLcnqqVXhR4093bGirTwacRlHiVg1XYI9xum6QQ==",
|
||||
"path": "microsoft.extensions.dependencyinjection/9.0.8",
|
||||
"hashPath": "microsoft.extensions.dependencyinjection.9.0.8.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions/9.0.8": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-xY3lTjj4+ZYmiKIkyWitddrp1uL5uYiweQjqo4BKBw01ZC4HhcfgLghDpPZcUlppgWAFqFy9SgkiYWOMx365pw==",
|
||||
"path": "microsoft.extensions.dependencyinjection.abstractions/9.0.8",
|
||||
"hashPath": "microsoft.extensions.dependencyinjection.abstractions.9.0.8.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.Extensions.Diagnostics/9.0.8": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-BKkLCFXzJvNmdngeYBf72VXoZqTJSb1orvjdzDLaGobicoGFBPW8ug2ru1nnEewMEwJzMgnsjHQY8EaKWmVhKg==",
|
||||
"path": "microsoft.extensions.diagnostics/9.0.8",
|
||||
"hashPath": "microsoft.extensions.diagnostics.9.0.8.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.Extensions.Diagnostics.Abstractions/9.0.8": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-UDY7blv4DCyIJ/8CkNrQKLaAZFypXQavRZ2DWf/2zi1mxYYKKw2t8AOCBWxNntyPZHPGhtEmL3snFM98ADZqTw==",
|
||||
"path": "microsoft.extensions.diagnostics.abstractions/9.0.8",
|
||||
"hashPath": "microsoft.extensions.diagnostics.abstractions.9.0.8.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.Extensions.Http/9.0.8": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-jDj+4aDByk47oESlDDTtk6LWzlXlmoCsjCn6ihd+i9OntN885aPLszUII5+w0B/7wYSZcS3KdjqLAIhKLSiBXQ==",
|
||||
"path": "microsoft.extensions.http/9.0.8",
|
||||
"hashPath": "microsoft.extensions.http.9.0.8.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.Extensions.Logging/9.0.8": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-Z/7ze+0iheT7FJeZPqJKARYvyC2bmwu3whbm/48BJjdlGVvgDguoCqJIkI/67NkroTYobd5geai1WheNQvWrgA==",
|
||||
"path": "microsoft.extensions.logging/9.0.8",
|
||||
"hashPath": "microsoft.extensions.logging.9.0.8.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.Extensions.Logging.Abstractions/9.0.8": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-pYnAffJL7ARD/HCnnPvnFKSIHnTSmWz84WIlT9tPeQ4lHNiu0Az7N/8itihWvcF8sT+VVD5lq8V+ckMzu4SbOw==",
|
||||
"path": "microsoft.extensions.logging.abstractions/9.0.8",
|
||||
"hashPath": "microsoft.extensions.logging.abstractions.9.0.8.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.Extensions.Options/9.0.8": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-OmTaQ0v4gxGQkehpwWIqPoEiwsPuG/u4HUsbOFoWGx4DKET2AXzopnFe/fE608FIhzc/kcg2p8JdyMRCCUzitQ==",
|
||||
"path": "microsoft.extensions.options/9.0.8",
|
||||
"hashPath": "microsoft.extensions.options.9.0.8.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.Extensions.Options.ConfigurationExtensions/9.0.8": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-eW2s6n06x0w6w4nsX+SvpgsFYkl+Y0CttYAt6DKUXeqprX+hzNqjSfOh637fwNJBg7wRBrOIRHe49gKiTgJxzQ==",
|
||||
"path": "microsoft.extensions.options.configurationextensions/9.0.8",
|
||||
"hashPath": "microsoft.extensions.options.configurationextensions.9.0.8.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.Extensions.Primitives/9.0.8": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-tizSIOEsIgSNSSh+hKeUVPK7xmTIjR8s+mJWOu1KXV3htvNQiPMFRMO17OdI1y/4ZApdBVk49u/08QGC9yvLug==",
|
||||
"path": "microsoft.extensions.primitives/9.0.8",
|
||||
"hashPath": "microsoft.extensions.primitives.9.0.8.nupkg.sha512"
|
||||
},
|
||||
"Elecciones.Core/1.0.0": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
|
||||
@@ -13,7 +13,7 @@ using System.Reflection;
|
||||
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Infrastructure")]
|
||||
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
||||
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+d9bcfd70865a12c229e6a761639094b45de862bd")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+b90baadeedb870b5b1c9eeeb7022a0d211b61bec")]
|
||||
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Infrastructure")]
|
||||
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Infrastructure")]
|
||||
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||
|
||||
@@ -118,6 +118,16 @@
|
||||
"frameworks": {
|
||||
"net9.0": {
|
||||
"targetAlias": "net9.0",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration.Abstractions": {
|
||||
"target": "Package",
|
||||
"version": "[9.0.8, )"
|
||||
},
|
||||
"Microsoft.Extensions.Http": {
|
||||
"target": "Package",
|
||||
"version": "[9.0.8, )"
|
||||
}
|
||||
},
|
||||
"imports": [
|
||||
"net461",
|
||||
"net462",
|
||||
|
||||
@@ -1,2 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" />
|
||||
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
||||
<Import Project="$(NuGetPackageRoot)microsoft.extensions.options\9.0.8\buildTransitive\net8.0\Microsoft.Extensions.Options.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.options\9.0.8\buildTransitive\net8.0\Microsoft.Extensions.Options.targets')" />
|
||||
<Import Project="$(NuGetPackageRoot)microsoft.extensions.configuration.binder\9.0.8\buildTransitive\netstandard2.0\Microsoft.Extensions.Configuration.Binder.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.configuration.binder\9.0.8\buildTransitive\netstandard2.0\Microsoft.Extensions.Configuration.Binder.targets')" />
|
||||
<Import Project="$(NuGetPackageRoot)microsoft.extensions.logging.abstractions\9.0.8\buildTransitive\net8.0\Microsoft.Extensions.Logging.Abstractions.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.logging.abstractions\9.0.8\buildTransitive\net8.0\Microsoft.Extensions.Logging.Abstractions.targets')" />
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -10,6 +10,7 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.8" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.8" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Elecciones.Database;
|
||||
using Elecciones.Infrastructure.Services;
|
||||
using Elecciones.Worker;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
@@ -6,15 +7,32 @@ var builder = Host.CreateApplicationBuilder(args);
|
||||
|
||||
// --- Configuración de Servicios ---
|
||||
|
||||
// Añade la cadena de conexión y el DbContext. El worker lo necesita para guardar los datos.
|
||||
// 1. Configuración de Base de Datos (¡Este bloque es esencial!)
|
||||
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
|
||||
builder.Services.AddDbContext<EleccionesDbContext>(options =>
|
||||
options.UseSqlServer(connectionString));
|
||||
|
||||
// Registra el Worker como un servicio que se ejecuta en segundo plano.
|
||||
// 2. Configuración del Servicio de API (elegirá el Real o el Falso según el modo de compilación)
|
||||
#if DEBUG
|
||||
// En modo DEBUG (desarrollo local), usamos el servicio FALSO.
|
||||
// No es necesario registrar el ILogger, .NET lo inyecta automáticamente.
|
||||
builder.Services.AddSingleton<IElectoralApiService, FakeElectoralApiService>();
|
||||
#else
|
||||
// En modo RELEASE (producción), usamos el servicio REAL.
|
||||
builder.Services.AddHttpClient("ElectoralApiClient", client =>
|
||||
{
|
||||
var baseUrl = builder.Configuration["ElectoralApi:BaseUrl"];
|
||||
if (!string.IsNullOrEmpty(baseUrl))
|
||||
{
|
||||
client.BaseAddress = new Uri(baseUrl);
|
||||
}
|
||||
});
|
||||
builder.Services.AddSingleton<IElectoralApiService, ElectoralApiService>();
|
||||
#endif
|
||||
|
||||
// 3. Registrar el Worker como un servicio que se ejecuta en segundo plano.
|
||||
builder.Services.AddHostedService<Worker>();
|
||||
|
||||
var host = builder.Build();
|
||||
|
||||
// Inicia el host, que a su vez iniciará nuestro Worker.
|
||||
var host = builder.Build();
|
||||
host.Run();
|
||||
@@ -1,23 +1,233 @@
|
||||
using Elecciones.Database;
|
||||
using Elecciones.Database.Entities;
|
||||
using Elecciones.Infrastructure.Services;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Elecciones.Worker;
|
||||
|
||||
public class Worker : BackgroundService
|
||||
{
|
||||
private readonly ILogger<Worker> _logger;
|
||||
private readonly IElectoralApiService _apiService;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private string? _authToken; // Almacenamos el token para reutilizarlo en el ciclo de vida
|
||||
|
||||
public Worker(ILogger<Worker> logger)
|
||||
public Worker(ILogger<Worker> logger, IElectoralApiService apiService, IServiceProvider serviceProvider)
|
||||
{
|
||||
_logger = logger;
|
||||
_apiService = apiService;
|
||||
_serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
_logger.LogInformation("Elecciones Worker iniciado a las: {time}", DateTimeOffset.Now);
|
||||
|
||||
// --- 1. SINCRONIZACIÓN INICIAL DE CATÁLOGOS ---
|
||||
// Se ejecuta una sola vez al inicio para poblar las tablas maestras.
|
||||
await SincronizarCatalogosAsync(stoppingToken);
|
||||
|
||||
// --- 2. BUCLE DE SONDEO DE RESULTADOS ---
|
||||
_logger.LogInformation("-------------------------------------------------");
|
||||
_logger.LogInformation("Iniciando sondeo periódico de resultados...");
|
||||
_logger.LogInformation("-------------------------------------------------");
|
||||
while (!stoppingToken.IsCancellationRequested)
|
||||
{
|
||||
if (_logger.IsEnabled(LogLevel.Information))
|
||||
await SondearResultadosAsync(stoppingToken);
|
||||
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
|
||||
// Esperamos 10 segundos antes de la siguiente consulta.
|
||||
await Task.Delay(TimeSpan.FromSeconds(10), stoppingToken);
|
||||
}
|
||||
await Task.Delay(1000, stoppingToken);
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
// Es normal que esto ocurra cuando se detiene la aplicación.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_logger.LogInformation("Elecciones Worker se está deteniendo.");
|
||||
}
|
||||
|
||||
private async Task ObtenerTokenSiEsNecesario(CancellationToken stoppingToken)
|
||||
{
|
||||
// En un futuro, se podría añadir lógica para renovar el token solo cuando expire.
|
||||
// Por ahora, para asegurar que siempre sea válido, lo obtenemos cada vez.
|
||||
_authToken = await _apiService.GetAuthTokenAsync();
|
||||
if (string.IsNullOrEmpty(_authToken))
|
||||
{
|
||||
_logger.LogError("No se pudo obtener el token, se cancelan las operaciones.");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SondearResultadosAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
await ObtenerTokenSiEsNecesario(stoppingToken);
|
||||
if (string.IsNullOrEmpty(_authToken) || stoppingToken.IsCancellationRequested) return;
|
||||
|
||||
// Usamos un 'scope' propio para esta operación
|
||||
using var scope = _serviceProvider.CreateScope();
|
||||
var dbContext = scope.ServiceProvider.GetRequiredService<EleccionesDbContext>();
|
||||
|
||||
// 1. OBTENEMOS LA LISTA DE TODOS LOS MUNICIPIOS DE NUESTRA BD
|
||||
var municipiosASondear = await dbContext.AmbitosGeograficos
|
||||
.AsNoTracking()
|
||||
.Where(a => a.NivelId == 5 && a.MunicipioId != null && a.DistritoId != null && a.SeccionId != null)
|
||||
.Select(a => new { a.Id, a.MunicipioId, a.SeccionId, a.DistritoId })
|
||||
.ToListAsync(stoppingToken);
|
||||
|
||||
_logger.LogInformation("Iniciando sondeo para {count} municipios.", municipiosASondear.Count);
|
||||
|
||||
// 2. RECORREMOS LA LISTA Y PROCESAMOS CADA MUNICIPIO
|
||||
foreach (var municipio in municipiosASondear)
|
||||
{
|
||||
if (stoppingToken.IsCancellationRequested) break;
|
||||
|
||||
_logger.LogInformation("Sondeando resultados para el municipio: {municipioId}", municipio.MunicipioId);
|
||||
|
||||
var resultados = await _apiService.GetResultadosAsync(_authToken, municipio.DistritoId!, municipio.SeccionId!, municipio.MunicipioId!);
|
||||
if (resultados is null)
|
||||
{
|
||||
_logger.LogWarning("No se recibieron resultados para el municipio {municipioId}", municipio.MunicipioId);
|
||||
continue; // Saltamos al siguiente municipio
|
||||
}
|
||||
|
||||
// 3. GUARDAMOS LOS DATOS (Lógica de Upsert)
|
||||
// La lógica de guardado que ya teníamos funciona perfectamente para cada municipio.
|
||||
// La pasamos a un método separado para mayor claridad.
|
||||
await GuardarResultadosDeAmbitoAsync(dbContext, municipio.Id, resultados, stoppingToken);
|
||||
|
||||
_logger.LogInformation("Resultados para el municipio {municipioId} guardados/actualizados.", municipio.MunicipioId);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Ocurrió un error inesperado durante el sondeo de resultados.");
|
||||
}
|
||||
}
|
||||
|
||||
// NUEVO MÉTODO AUXILIAR PARA GUARDAR LOS DATOS
|
||||
private async Task GuardarResultadosDeAmbitoAsync(EleccionesDbContext dbContext, int ambitoId, Elecciones.Core.DTOs.ResultadosDto resultados, CancellationToken stoppingToken)
|
||||
{
|
||||
// --- ACTUALIZAR O INSERTAR ESTADO RECUENTO ---
|
||||
var estadoRecuento = await dbContext.EstadosRecuentos.FindAsync(new object[] { ambitoId }, cancellationToken: stoppingToken);
|
||||
if (estadoRecuento == null)
|
||||
{
|
||||
estadoRecuento = new EstadoRecuento { AmbitoGeograficoId = ambitoId };
|
||||
dbContext.EstadosRecuentos.Add(estadoRecuento);
|
||||
}
|
||||
estadoRecuento.FechaTotalizacion = DateTime.Parse(resultados.FechaTotalizacion).ToUniversalTime();
|
||||
estadoRecuento.MesasEsperadas = resultados.EstadoRecuento.MesasEsperadas;
|
||||
estadoRecuento.MesasTotalizadas = resultados.EstadoRecuento.MesasTotalizadas;
|
||||
estadoRecuento.CantidadElectores = resultados.EstadoRecuento.CantidadElectores;
|
||||
estadoRecuento.ParticipacionPorcentaje = resultados.EstadoRecuento.ParticipacionPorcentaje;
|
||||
if (resultados.ValoresTotalizadosOtros != null)
|
||||
{
|
||||
estadoRecuento.VotosEnBlanco = resultados.ValoresTotalizadosOtros.VotosEnBlanco;
|
||||
estadoRecuento.VotosNulos = resultados.ValoresTotalizadosOtros.VotosNulos;
|
||||
estadoRecuento.VotosRecurridos = resultados.ValoresTotalizadosOtros.VotosRecurridos;
|
||||
}
|
||||
|
||||
// --- ACTUALIZAR O INSERTAR VOTOS POSITIVOS ---
|
||||
foreach (var votoPositivo in resultados.ValoresTotalizadosPositivos)
|
||||
{
|
||||
var resultadoVoto = await dbContext.ResultadosVotos.FirstOrDefaultAsync(
|
||||
rv => rv.AmbitoGeograficoId == ambitoId && rv.AgrupacionPoliticaId == votoPositivo.IdAgrupacion, stoppingToken);
|
||||
|
||||
if (resultadoVoto == null)
|
||||
{
|
||||
resultadoVoto = new ResultadoVoto
|
||||
{
|
||||
AmbitoGeograficoId = ambitoId,
|
||||
AgrupacionPoliticaId = votoPositivo.IdAgrupacion
|
||||
};
|
||||
dbContext.ResultadosVotos.Add(resultadoVoto);
|
||||
}
|
||||
resultadoVoto.CantidadVotos = votoPositivo.Votos;
|
||||
}
|
||||
|
||||
await dbContext.SaveChangesAsync(stoppingToken);
|
||||
}
|
||||
|
||||
private async Task SincronizarCatalogosAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Iniciando sincronización de catálogos maestros...");
|
||||
await ObtenerTokenSiEsNecesario(stoppingToken);
|
||||
if (string.IsNullOrEmpty(_authToken) || stoppingToken.IsCancellationRequested) return;
|
||||
|
||||
using var scope = _serviceProvider.CreateScope();
|
||||
var dbContext = scope.ServiceProvider.GetRequiredService<EleccionesDbContext>();
|
||||
|
||||
_logger.LogInformation("Limpiando tablas maestras para la nueva ingesta...");
|
||||
await dbContext.Database.ExecuteSqlRawAsync("DELETE FROM ResultadosVotos", stoppingToken);
|
||||
await dbContext.Database.ExecuteSqlRawAsync("DELETE FROM EstadosRecuentos", stoppingToken);
|
||||
await dbContext.Database.ExecuteSqlRawAsync("DELETE FROM AgrupacionesPoliticas", stoppingToken);
|
||||
await dbContext.Database.ExecuteSqlRawAsync("DELETE FROM AmbitosGeograficos", stoppingToken);
|
||||
|
||||
// --- 1. INGESTA DE ÁMBITOS GEOGRÁFICOS ---
|
||||
var catalogos = await _apiService.GetCatalogoCompletoAsync(_authToken);
|
||||
if (catalogos is { Count: > 0 })
|
||||
{
|
||||
foreach (var ambitoDto in catalogos.SelectMany(c => c.Ambitos))
|
||||
{
|
||||
var nuevoAmbito = new AmbitoGeografico
|
||||
{
|
||||
Nombre = ambitoDto.Nombre,
|
||||
NivelId = ambitoDto.NivelId,
|
||||
DistritoId = ambitoDto.CodigoAmbitos.DistritoId,
|
||||
SeccionId = ambitoDto.CodigoAmbitos.SeccionId,
|
||||
MunicipioId = ambitoDto.CodigoAmbitos.MunicipioId,
|
||||
SeccionProvincialId = ambitoDto.CodigoAmbitos.SeccionProvincialId
|
||||
};
|
||||
await dbContext.AmbitosGeograficos.AddAsync(nuevoAmbito, stoppingToken);
|
||||
}
|
||||
_logger.LogInformation("Datos de Ámbitos Geográficos listos para ser guardados.");
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogWarning("No se recibieron datos del catálogo de Ámbitos.");
|
||||
}
|
||||
|
||||
// --- 2. INGESTA DE AGRUPACIONES POLÍTICAS ---
|
||||
var agrupaciones = await _apiService.GetAgrupacionesAsync(_authToken, "02", 5);
|
||||
if (agrupaciones is { Count: > 0 })
|
||||
{
|
||||
foreach (var agrupacionDto in agrupaciones)
|
||||
{
|
||||
var nuevaAgrupacion = new AgrupacionPolitica
|
||||
{
|
||||
Id = agrupacionDto.IdAgrupacion,
|
||||
IdTelegrama = agrupacionDto.IdAgrupacionTelegrama,
|
||||
Nombre = agrupacionDto.NombreAgrupacion
|
||||
};
|
||||
await dbContext.AgrupacionesPoliticas.AddAsync(nuevaAgrupacion, stoppingToken);
|
||||
}
|
||||
_logger.LogInformation("Datos de Agrupaciones Políticas listos para ser guardados.");
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogWarning("No se recibieron datos del catálogo de Agrupaciones.");
|
||||
}
|
||||
|
||||
// --- 3. GUARDADO FINAL EN LA BASE DE DATOS ---
|
||||
int registrosGuardados = await dbContext.SaveChangesAsync(stoppingToken);
|
||||
_logger.LogInformation("{count} registros totales han sido guardados en la base de datos.", registrosGuardados);
|
||||
|
||||
_logger.LogInformation("Sincronización de catálogos completada exitosamente.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Ocurrió un error CRÍTICO durante la sincronización de catálogos. El worker podría no funcionar correctamente.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,5 +4,13 @@
|
||||
"Default": "Information",
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
},
|
||||
"ElectoralApi": {
|
||||
"BaseUrl": "https://api.eleccionesbonaerenses.gba.gob.ar",
|
||||
"Username": "30500094156@elecciones2025.onmicrosoft.com",
|
||||
"Password": "PTP847elec"
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"DefaultConnection": "Server=TECNICA3;Database=Elecciones2025;User Id=apielecciones2025;Password=PTP847Elecciones2025;Encrypt=False;MultipleActiveResultSets=True;TrustServerCertificate=True;"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,5 +4,10 @@
|
||||
"Default": "Information",
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
},
|
||||
"ElectoralApi": {
|
||||
"BaseUrl": "https://api.eleccionesbonaerenses.gba.gob.ar",
|
||||
"Username": "30500094156@elecciones2025.onmicrosoft.com",
|
||||
"Password": "PTP847elec"
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,8 @@
|
||||
"Elecciones.Database": "1.0.0",
|
||||
"Elecciones.Infrastructure": "1.0.0",
|
||||
"Microsoft.EntityFrameworkCore.SqlServer": "9.0.8",
|
||||
"Microsoft.Extensions.Hosting": "9.0.5"
|
||||
"Microsoft.Extensions.Hosting": "9.0.5",
|
||||
"Microsoft.Extensions.Http": "9.0.8"
|
||||
},
|
||||
"runtime": {
|
||||
"Elecciones.Worker.dll": {}
|
||||
@@ -202,7 +203,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Configuration/9.0.5": {
|
||||
"Microsoft.Extensions.Configuration/9.0.8": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Primitives": "9.0.8"
|
||||
@@ -210,7 +211,7 @@
|
||||
"runtime": {
|
||||
"lib/net9.0/Microsoft.Extensions.Configuration.dll": {
|
||||
"assemblyVersion": "9.0.0.0",
|
||||
"fileVersion": "9.0.525.21509"
|
||||
"fileVersion": "9.0.825.36511"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -225,20 +226,20 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Configuration.Binder/9.0.5": {
|
||||
"Microsoft.Extensions.Configuration.Binder/9.0.8": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net9.0/Microsoft.Extensions.Configuration.Binder.dll": {
|
||||
"assemblyVersion": "9.0.0.0",
|
||||
"fileVersion": "9.0.525.21509"
|
||||
"fileVersion": "9.0.825.36511"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Configuration.CommandLine/9.0.5": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration": "9.0.5",
|
||||
"Microsoft.Extensions.Configuration": "9.0.8",
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8"
|
||||
},
|
||||
"runtime": {
|
||||
@@ -250,7 +251,7 @@
|
||||
},
|
||||
"Microsoft.Extensions.Configuration.EnvironmentVariables/9.0.5": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration": "9.0.5",
|
||||
"Microsoft.Extensions.Configuration": "9.0.8",
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8"
|
||||
},
|
||||
"runtime": {
|
||||
@@ -262,7 +263,7 @@
|
||||
},
|
||||
"Microsoft.Extensions.Configuration.FileExtensions/9.0.5": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration": "9.0.5",
|
||||
"Microsoft.Extensions.Configuration": "9.0.8",
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.FileProviders.Abstractions": "9.0.5",
|
||||
"Microsoft.Extensions.FileProviders.Physical": "9.0.5",
|
||||
@@ -277,7 +278,7 @@
|
||||
},
|
||||
"Microsoft.Extensions.Configuration.Json/9.0.5": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration": "9.0.5",
|
||||
"Microsoft.Extensions.Configuration": "9.0.8",
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Configuration.FileExtensions": "9.0.5",
|
||||
"Microsoft.Extensions.FileProviders.Abstractions": "9.0.5"
|
||||
@@ -322,20 +323,20 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Diagnostics/9.0.5": {
|
||||
"Microsoft.Extensions.Diagnostics/9.0.8": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration": "9.0.5",
|
||||
"Microsoft.Extensions.Diagnostics.Abstractions": "9.0.5",
|
||||
"Microsoft.Extensions.Options.ConfigurationExtensions": "9.0.5"
|
||||
"Microsoft.Extensions.Configuration": "9.0.8",
|
||||
"Microsoft.Extensions.Diagnostics.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Options.ConfigurationExtensions": "9.0.8"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net9.0/Microsoft.Extensions.Diagnostics.dll": {
|
||||
"assemblyVersion": "9.0.0.0",
|
||||
"fileVersion": "9.0.525.21509"
|
||||
"fileVersion": "9.0.825.36511"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Diagnostics.Abstractions/9.0.5": {
|
||||
"Microsoft.Extensions.Diagnostics.Abstractions/9.0.8": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Options": "9.0.8"
|
||||
@@ -343,7 +344,7 @@
|
||||
"runtime": {
|
||||
"lib/net9.0/Microsoft.Extensions.Diagnostics.Abstractions.dll": {
|
||||
"assemblyVersion": "9.0.0.0",
|
||||
"fileVersion": "9.0.525.21509"
|
||||
"fileVersion": "9.0.825.36511"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -381,9 +382,9 @@
|
||||
},
|
||||
"Microsoft.Extensions.Hosting/9.0.5": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration": "9.0.5",
|
||||
"Microsoft.Extensions.Configuration": "9.0.8",
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Configuration.Binder": "9.0.5",
|
||||
"Microsoft.Extensions.Configuration.Binder": "9.0.8",
|
||||
"Microsoft.Extensions.Configuration.CommandLine": "9.0.5",
|
||||
"Microsoft.Extensions.Configuration.EnvironmentVariables": "9.0.5",
|
||||
"Microsoft.Extensions.Configuration.FileExtensions": "9.0.5",
|
||||
@@ -391,7 +392,7 @@
|
||||
"Microsoft.Extensions.Configuration.UserSecrets": "9.0.5",
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.8",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Diagnostics": "9.0.5",
|
||||
"Microsoft.Extensions.Diagnostics": "9.0.8",
|
||||
"Microsoft.Extensions.FileProviders.Abstractions": "9.0.5",
|
||||
"Microsoft.Extensions.FileProviders.Physical": "9.0.5",
|
||||
"Microsoft.Extensions.Hosting.Abstractions": "9.0.5",
|
||||
@@ -415,7 +416,7 @@
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Diagnostics.Abstractions": "9.0.5",
|
||||
"Microsoft.Extensions.Diagnostics.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.FileProviders.Abstractions": "9.0.5",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.8"
|
||||
},
|
||||
@@ -426,6 +427,22 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Http/9.0.8": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Diagnostics": "9.0.8",
|
||||
"Microsoft.Extensions.Logging": "9.0.8",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Options": "9.0.8"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net9.0/Microsoft.Extensions.Http.dll": {
|
||||
"assemblyVersion": "9.0.0.0",
|
||||
"fileVersion": "9.0.825.36511"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Logging/9.0.8": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.8",
|
||||
@@ -452,14 +469,14 @@
|
||||
},
|
||||
"Microsoft.Extensions.Logging.Configuration/9.0.5": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration": "9.0.5",
|
||||
"Microsoft.Extensions.Configuration": "9.0.8",
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Configuration.Binder": "9.0.5",
|
||||
"Microsoft.Extensions.Configuration.Binder": "9.0.8",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Logging": "9.0.8",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Options": "9.0.8",
|
||||
"Microsoft.Extensions.Options.ConfigurationExtensions": "9.0.5"
|
||||
"Microsoft.Extensions.Options.ConfigurationExtensions": "9.0.8"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net9.0/Microsoft.Extensions.Logging.Configuration.dll": {
|
||||
@@ -538,10 +555,10 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Options.ConfigurationExtensions/9.0.5": {
|
||||
"Microsoft.Extensions.Options.ConfigurationExtensions/9.0.8": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Configuration.Binder": "9.0.5",
|
||||
"Microsoft.Extensions.Configuration.Binder": "9.0.8",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Options": "9.0.8",
|
||||
"Microsoft.Extensions.Primitives": "9.0.8"
|
||||
@@ -549,7 +566,7 @@
|
||||
"runtime": {
|
||||
"lib/net9.0/Microsoft.Extensions.Options.ConfigurationExtensions.dll": {
|
||||
"assemblyVersion": "9.0.0.0",
|
||||
"fileVersion": "9.0.525.21509"
|
||||
"fileVersion": "9.0.825.36511"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -918,7 +935,9 @@
|
||||
},
|
||||
"Elecciones.Infrastructure/1.0.0": {
|
||||
"dependencies": {
|
||||
"Elecciones.Core": "1.0.0"
|
||||
"Elecciones.Core": "1.0.0",
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8",
|
||||
"Microsoft.Extensions.Http": "9.0.8"
|
||||
},
|
||||
"runtime": {
|
||||
"Elecciones.Infrastructure.dll": {
|
||||
@@ -1026,12 +1045,12 @@
|
||||
"path": "microsoft.extensions.caching.memory/9.0.8",
|
||||
"hashPath": "microsoft.extensions.caching.memory.9.0.8.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.Extensions.Configuration/9.0.5": {
|
||||
"Microsoft.Extensions.Configuration/9.0.8": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-uYXLg2Gt8KUH5nT3u+TBpg9VrRcN5+2zPmIjqEHR4kOoBwsbtMDncEJw9HiLvZqGgIo2TR4oraibAoy5hXn2bQ==",
|
||||
"path": "microsoft.extensions.configuration/9.0.5",
|
||||
"hashPath": "microsoft.extensions.configuration.9.0.5.nupkg.sha512"
|
||||
"sha512": "sha512-6m+8Xgmf8UWL0p/oGqBM+0KbHE5/ePXbV1hKXgC59zEv0aa0DW5oiiyxDbK5kH5j4gIvyD5uWL0+HadKBJngvQ==",
|
||||
"path": "microsoft.extensions.configuration/9.0.8",
|
||||
"hashPath": "microsoft.extensions.configuration.9.0.8.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.Extensions.Configuration.Abstractions/9.0.8": {
|
||||
"type": "package",
|
||||
@@ -1040,12 +1059,12 @@
|
||||
"path": "microsoft.extensions.configuration.abstractions/9.0.8",
|
||||
"hashPath": "microsoft.extensions.configuration.abstractions.9.0.8.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.Extensions.Configuration.Binder/9.0.5": {
|
||||
"Microsoft.Extensions.Configuration.Binder/9.0.8": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-7pQ4Tkyofm8DFWFhqn9ZmG8qSAC2VitWleATj5qob9V9KtoxCVdwRtmiVl/ha3WAgjkEfW++JLWXox9MJwMgkg==",
|
||||
"path": "microsoft.extensions.configuration.binder/9.0.5",
|
||||
"hashPath": "microsoft.extensions.configuration.binder.9.0.5.nupkg.sha512"
|
||||
"sha512": "sha512-0vK9DnYrYChdiH3yRZWkkp4x4LbrfkWEdBc5HOsQ8t/0CLOWKXKkkhOE8A1shlex0hGydbGrhObeypxz/QTm+w==",
|
||||
"path": "microsoft.extensions.configuration.binder/9.0.8",
|
||||
"hashPath": "microsoft.extensions.configuration.binder.9.0.8.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.Extensions.Configuration.CommandLine/9.0.5": {
|
||||
"type": "package",
|
||||
@@ -1096,19 +1115,19 @@
|
||||
"path": "microsoft.extensions.dependencyinjection.abstractions/9.0.8",
|
||||
"hashPath": "microsoft.extensions.dependencyinjection.abstractions.9.0.8.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.Extensions.Diagnostics/9.0.5": {
|
||||
"Microsoft.Extensions.Diagnostics/9.0.8": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-fRiUjmhm9e4vMp6WEO9MgWNxVtWSr4Pcgh1W4DyJIr8bRANlZz9JU7uicf7ShzMspDxo/9Ejo9zJ6qQZY0IhVw==",
|
||||
"path": "microsoft.extensions.diagnostics/9.0.5",
|
||||
"hashPath": "microsoft.extensions.diagnostics.9.0.5.nupkg.sha512"
|
||||
"sha512": "sha512-BKkLCFXzJvNmdngeYBf72VXoZqTJSb1orvjdzDLaGobicoGFBPW8ug2ru1nnEewMEwJzMgnsjHQY8EaKWmVhKg==",
|
||||
"path": "microsoft.extensions.diagnostics/9.0.8",
|
||||
"hashPath": "microsoft.extensions.diagnostics.9.0.8.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.Extensions.Diagnostics.Abstractions/9.0.5": {
|
||||
"Microsoft.Extensions.Diagnostics.Abstractions/9.0.8": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-6YfTcULCYREMTqtk+s3UiszsFV2xN2FXtxdQpurmQJY9Cp/QGiM4MTKfJKUo7AzdLuzjOKKMWjQITmvtK7AsUg==",
|
||||
"path": "microsoft.extensions.diagnostics.abstractions/9.0.5",
|
||||
"hashPath": "microsoft.extensions.diagnostics.abstractions.9.0.5.nupkg.sha512"
|
||||
"sha512": "sha512-UDY7blv4DCyIJ/8CkNrQKLaAZFypXQavRZ2DWf/2zi1mxYYKKw2t8AOCBWxNntyPZHPGhtEmL3snFM98ADZqTw==",
|
||||
"path": "microsoft.extensions.diagnostics.abstractions/9.0.8",
|
||||
"hashPath": "microsoft.extensions.diagnostics.abstractions.9.0.8.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.Extensions.FileProviders.Abstractions/9.0.5": {
|
||||
"type": "package",
|
||||
@@ -1145,6 +1164,13 @@
|
||||
"path": "microsoft.extensions.hosting.abstractions/9.0.5",
|
||||
"hashPath": "microsoft.extensions.hosting.abstractions.9.0.5.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.Extensions.Http/9.0.8": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-jDj+4aDByk47oESlDDTtk6LWzlXlmoCsjCn6ihd+i9OntN885aPLszUII5+w0B/7wYSZcS3KdjqLAIhKLSiBXQ==",
|
||||
"path": "microsoft.extensions.http/9.0.8",
|
||||
"hashPath": "microsoft.extensions.http.9.0.8.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.Extensions.Logging/9.0.8": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
@@ -1201,12 +1227,12 @@
|
||||
"path": "microsoft.extensions.options/9.0.8",
|
||||
"hashPath": "microsoft.extensions.options.9.0.8.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.Extensions.Options.ConfigurationExtensions/9.0.5": {
|
||||
"Microsoft.Extensions.Options.ConfigurationExtensions/9.0.8": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-CJbAVdovKPFh2FoKxesu20odRVSbL/vtvzzObnG+5u38sOfzRS2Ncy25id0TjYUGQzMhNnJUHgTUzTMDl/3c9g==",
|
||||
"path": "microsoft.extensions.options.configurationextensions/9.0.5",
|
||||
"hashPath": "microsoft.extensions.options.configurationextensions.9.0.5.nupkg.sha512"
|
||||
"sha512": "sha512-eW2s6n06x0w6w4nsX+SvpgsFYkl+Y0CttYAt6DKUXeqprX+hzNqjSfOh637fwNJBg7wRBrOIRHe49gKiTgJxzQ==",
|
||||
"path": "microsoft.extensions.options.configurationextensions/9.0.8",
|
||||
"hashPath": "microsoft.extensions.options.configurationextensions.9.0.8.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.Extensions.Primitives/9.0.8": {
|
||||
"type": "package",
|
||||
|
||||
@@ -4,5 +4,13 @@
|
||||
"Default": "Information",
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
},
|
||||
"ElectoralApi": {
|
||||
"BaseUrl": "https://api.eleccionesbonaerenses.gba.gob.ar",
|
||||
"Username": "30500094156@elecciones2025.onmicrosoft.com",
|
||||
"Password": "PTP847elec"
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"DefaultConnection": "Server=TECNICA3;Database=Elecciones2025;User Id=apielecciones2025;Password=PTP847Elecciones2025;Encrypt=False;MultipleActiveResultSets=True;TrustServerCertificate=True;"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,5 +4,10 @@
|
||||
"Default": "Information",
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
},
|
||||
"ElectoralApi": {
|
||||
"BaseUrl": "https://api.eleccionesbonaerenses.gba.gob.ar",
|
||||
"Username": "30500094156@elecciones2025.onmicrosoft.com",
|
||||
"Password": "PTP847elec"
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@ using System.Reflection;
|
||||
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Worker")]
|
||||
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
||||
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+d9bcfd70865a12c229e6a761639094b45de862bd")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+b90baadeedb870b5b1c9eeeb7022a0d211b61bec")]
|
||||
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Worker")]
|
||||
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Worker")]
|
||||
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||
|
||||
@@ -95,3 +95,4 @@ E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Worker\obj\Debug\net9.0\refint\
|
||||
E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Worker\obj\Debug\net9.0\Elecciones.Worker.pdb
|
||||
E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Worker\obj\Debug\net9.0\Elecciones.Worker.genruntimeconfig.cache
|
||||
E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Worker\obj\Debug\net9.0\ref\Elecciones.Worker.dll
|
||||
E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Worker\bin\Debug\net9.0\Microsoft.Extensions.Http.dll
|
||||
|
||||
@@ -195,6 +195,16 @@
|
||||
"frameworks": {
|
||||
"net9.0": {
|
||||
"targetAlias": "net9.0",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration.Abstractions": {
|
||||
"target": "Package",
|
||||
"version": "[9.0.8, )"
|
||||
},
|
||||
"Microsoft.Extensions.Http": {
|
||||
"target": "Package",
|
||||
"version": "[9.0.8, )"
|
||||
}
|
||||
},
|
||||
"imports": [
|
||||
"net461",
|
||||
"net462",
|
||||
@@ -275,6 +285,10 @@
|
||||
"Microsoft.Extensions.Hosting": {
|
||||
"target": "Package",
|
||||
"version": "[9.0.5, )"
|
||||
},
|
||||
"Microsoft.Extensions.Http": {
|
||||
"target": "Package",
|
||||
"version": "[9.0.8, )"
|
||||
}
|
||||
},
|
||||
"imports": [
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
||||
<Import Project="$(NuGetPackageRoot)system.text.json\9.0.8\buildTransitive\net8.0\System.Text.Json.targets" Condition="Exists('$(NuGetPackageRoot)system.text.json\9.0.8\buildTransitive\net8.0\System.Text.Json.targets')" />
|
||||
<Import Project="$(NuGetPackageRoot)microsoft.extensions.options\9.0.8\buildTransitive\net8.0\Microsoft.Extensions.Options.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.options\9.0.8\buildTransitive\net8.0\Microsoft.Extensions.Options.targets')" />
|
||||
<Import Project="$(NuGetPackageRoot)microsoft.extensions.configuration.binder\9.0.5\buildTransitive\netstandard2.0\Microsoft.Extensions.Configuration.Binder.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.configuration.binder\9.0.5\buildTransitive\netstandard2.0\Microsoft.Extensions.Configuration.Binder.targets')" />
|
||||
<Import Project="$(NuGetPackageRoot)microsoft.extensions.configuration.binder\9.0.8\buildTransitive\netstandard2.0\Microsoft.Extensions.Configuration.Binder.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.configuration.binder\9.0.8\buildTransitive\netstandard2.0\Microsoft.Extensions.Configuration.Binder.targets')" />
|
||||
<Import Project="$(NuGetPackageRoot)microsoft.extensions.logging.abstractions\9.0.8\buildTransitive\net8.0\Microsoft.Extensions.Logging.Abstractions.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.logging.abstractions\9.0.8\buildTransitive\net8.0\Microsoft.Extensions.Logging.Abstractions.targets')" />
|
||||
<Import Project="$(NuGetPackageRoot)microsoft.extensions.configuration.usersecrets\9.0.5\buildTransitive\net8.0\Microsoft.Extensions.Configuration.UserSecrets.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.configuration.usersecrets\9.0.5\buildTransitive\net8.0\Microsoft.Extensions.Configuration.UserSecrets.targets')" />
|
||||
</ImportGroup>
|
||||
|
||||
Reference in New Issue
Block a user