Skip to content

Commit

Permalink
refactor: deprecate api and move scrapper to client
Browse files Browse the repository at this point in the history
  • Loading branch information
Yizack committed Nov 7, 2024
1 parent 9a812c2 commit 84ffb1e
Show file tree
Hide file tree
Showing 9 changed files with 1,503 additions and 1,332 deletions.
8 changes: 8 additions & 0 deletions android/.idea/deploymentTargetSelector.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

106 changes: 86 additions & 20 deletions android/.idea/other.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
android:theme="@style/AppTheme"
android:networkSecurityConfig="@xml/network_security_config">
<activity
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode"
android:name="com.yizack.saldometrobus.MainActivity"
Expand Down
6 changes: 6 additions & 0 deletions android/app/src/main/res/xml/network_security_config.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">200.46.245.230</domain>
</domain-config>
</network-security-config>
41 changes: 29 additions & 12 deletions app/utils/api.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Preferences } from "@capacitor/preferences";

class SaldometrobusAPI {
base = import.meta.dev ? "http://localhost:5173" : "https://saldometrobus.yizack.com";
version = "v2";
baseAPI = `${this.base}/api/${this.version}`;
baseDB = `${this.base}/database/${this.version}`;
tarjetasAPI = `${this.baseAPI}/tarjeta`;
loginURL = `${this.baseDB}/login`;
registroURL = `${this.baseDB}/registro`;
addTarjetaURL = `${this.baseDB}/tarjetas_insert`;
Expand Down Expand Up @@ -35,25 +35,42 @@ class SaldometrobusAPI {
}

async getTarjetaAPI (numero: string, cached = false) {
const { tarjeta, status, error, error_key } = await CAPACITOR.doGet(`${this.tarjetasAPI}/${numero}`, cached);
if (!error && status === "ok" && tarjeta) {
return { tarjeta };
const pref = (await Preferences.get({ key: numero })).value;
const cachedResponse = pref ? JSON.parse(pref) : null;

const currentTime = Date.now();
if (cached && cachedResponse && cachedResponse.expires && currentTime < cachedResponse.expires) {
return {
error: true,
error_key: `${t("tarjeta_actualizada")}: ${numero}`
};
}
else if (!error && status === "error") {

const scrapped = await scrapperTarjeta(numero);
if (!scrapped) return { error: true, error_key: "error" };

const { tarjeta, status } = scrapped;

if (status !== "ok" || !tarjeta) {
return { error: true, error_key: "error_tarjeta_unknown" };
}
else {
return { error, error_key };

if (parseInt(numero)) {
const maxAge = 60; // 1 minuto
const expiresTime = currentTime + (maxAge * 1000);
await Preferences.set({ key: numero, value: JSON.stringify({ expires: expiresTime }) });
}

return { tarjeta };
}

async getDetallesTarjetas (tarjetas: SaldometrobusTarjeta[]) {
const arr = [];
for (const tarjeta of tarjetas) {
const data = await CAPACITOR.doGet(`${this.tarjetasAPI}/${tarjeta.numero}`).catch(() => ({}));
if (data.status === "ok") {
Object.assign(data.tarjeta, tarjeta);
arr.push(data.tarjeta);
const scrapped = await scrapperTarjeta(tarjeta.numero);
if (scrapped && scrapped.status === "ok" && scrapped.tarjeta) {
Object.assign(scrapped.tarjeta, tarjeta); // needed for 1st time
arr.push(scrapped.tarjeta);
}
}
return arr;
Expand Down
14 changes: 14 additions & 0 deletions app/utils/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,17 @@ export const getCardImage = (tipo: string, brand = false) => {
return brand ? "metrobus_brand.webp" : "metrobus.webp";
}
};

export const getCardType = (cardNumber: string) => {
const n = Number(cardNumber);
const rangeMap = [
{ min: 20000000, max: 30000000, label: "Tarjeta Escolar" },
{ min: 30000000, max: 40000000, label: "Tarjeta Rapipass" },
{ min: 40000000, max: 50000000, label: "Tarjeta Jubilado" }
];

const matchedRange = rangeMap.find(range => n >= range.min && n < range.max);

if (matchedRange) return matchedRange.label;
return "Tarjeta Normal al Portador b";
};
88 changes: 88 additions & 0 deletions app/utils/scrapper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { load } from "cheerio";
import { CapacitorHttp } from "@capacitor/core";

const scrapperURL = "http://200.46.245.230:8080";
const baseUrl = scrapperURL + "/PortalCAE-WAR-MODULE";

export const scrapperTarjeta = async (numero: string) => {
// Info
const infoParams = new URLSearchParams({
accion: "6",
NumDistribuidor: "99",
NomUsuario: "usuInternet",
NomHost: "AFT",
NomDominio: "aft.cl",
Trx: "",
RutUsuario: "0",
NumTarjeta: numero,
bloqueable: ""
});

const infoHTML = await CapacitorHttp.get({ url: `${baseUrl}/SesionPortalServlet?${infoParams}`, responseType: "text" }).then(async response => response.data as string).catch(() => "");
if (!infoHTML) return null;
const $1 = load(infoHTML);
const ksi = $1("input#KSI").eq(0).val() as string;

if (!ksi) {
// setResponseStatus(event, 400);
return {
status: "error",
tarjeta: null,
code: 400,
message: "Número de tarjeta no válido"
};
}

const td1 = $1("td[class=verdanabold-ckc]:eq(3), td[class=verdanabold-ckc]:eq(5), td[class=verdanabold-ckc]:eq(7), span[class=arial12-bold-azul]:eq(1)");
const estado = td1.eq(0).text().trim();
const saldo = td1.eq(1).text().trim();
const fecha = td1.eq(2).text().trim();
const tipoAltElement = td1.eq(3);
const tipo_alt = tipoAltElement.length ? tipoAltElement.text().trim().split("Tipo de contrato:")[1]?.trim() : null;
const tipo = saldo ? tipo_alt || getCardType(numero) : "";

// Movimientos
const movsParams = new URLSearchParams({
KSI: ksi,
accion: "1",
itemms: "3000",
item: "2",
DiasMov: "28"
});

const movsHTML = await CapacitorHttp.get({ url: `${baseUrl}/ComercialesPortalServlet?${movsParams}`, responseType: "arraybuffer" }).then((response) => {
const binaryString = atob(response.data);
const bytes = Uint8Array.from(binaryString, char => char.charCodeAt(0));
const decoder = new TextDecoder("iso-8859-1");
return decoder.decode(bytes as ArrayBuffer);
}).catch(() => "");
const $2 = load(movsHTML);
const movimientos: SaldometrobusMovimiento[] = [];

const movs = $2(".arial12-azul td");
for (let i = 0; i < movs.length; i += 7) {
movimientos.push({
transaccion: movs.eq(i + 1).text().trim(),
tipo: movs.eq(i + 2).text().split("-")[1]?.trim() || "Desconocido",
fecha_hora: movs.eq(i + 3).text().trim(),
monto: movs.eq(i + 5).text().trim(),
saldo_tarjeta: movs.eq(i + 6).text().trim(),
lugar: movs.eq(i + 4).text().trim()
});
}

const output = {
status: "ok",
tarjeta: {
numero,
ksi,
saldo,
estado,
fecha,
tipo,
movimientos
}
};

return output;
};
Loading

0 comments on commit 84ffb1e

Please sign in to comment.