You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

192 lines
4.6 KiB
TypeScript

4 years ago
import { promisify } from "util";
import spawn from "async-spawner";
import FormData from "form-data";
import axios from "axios";
import tough from "tough-cookie";
import fs from "fs";
import axiosCookieJarSupport from "axios-cookiejar-support";
import * as path from "path";
import { LocationData, toCityCoordinates } from "./location";
import months from "./months";
axiosCookieJarSupport(axios);
const SM_URL =
"https://www.um.poznan.pl/mim/forms/sm_zgloszenia.html?instance=poznan_sm";
const headers = {
Accept:
"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
Host: "www.um.poznan.pl",
Origin: "https://www.um.poznan.pl",
Referer:
"https://www.um.poznan.pl/mim/forms/sm_zgloszenia.html?instance=poznan_sm",
"User-Agent":
"Mozilla/5.0 (X11; Linux x86_64; rv:72.0) Gecko/20100101 Firefox/72.0",
};
const minimal_data = {
lhs: "eurzad",
instance: "poznan_sm",
};
function formatTimestamp(timestamp: Date) {
const date_str = `${timestamp.getDate()} ${
months[timestamp.getMonth()]
} ${timestamp.getFullYear()}`;
const time = `${timestamp.getHours()}:${
timestamp.getMinutes() < 10 ? "0" : ""
}${timestamp.getMinutes()}`;
return [date_str, time];
}
type ContactDetails = {
email: string;
imie_nazwisko: string;
adres: string;
};
export async function submit(
location: LocationData,
reason: string,
photos: Array<string>,
timestamp: Date,
contact_details: ContactDetails,
plate: string
4 years ago
) {
if (location.address.includes("\n")) {
throw new Error("no newlines allowed in address");
}
const { x, y } = toCityCoordinates(location.coordinates);
const jar = new tough.CookieJar();
const transport = axios.create({
withCredentials: true,
});
await transport.get(SM_URL, {
headers,
jar,
});
const subject = `Nieprawidłowo zaparkowany samochód - ${location.address}`;
const [date_str, hour] = formatTimestamp(timestamp);
const body = `Samochód ${
reason || ""
}. Numer rejestracyjny samochodu: ${plate} Zdjęci${
4 years ago
photos.length === 1 ? "e" : "a"
} wykonane ${date_str} o godz. ${hour} w pobliżu ul. ${
location.address
}. Wnoszę o ukaranie.
`;
const main_data = {
...minimal_data,
srs: "EPSG:2177",
uz_process_personal_data_agreement: "Y",
uz_kategoria: 86808,
uz_temat: subject,
uz_tresc: body,
uz_email: contact_details.email,
uz_odpowiedz: "tak",
uz_imie_nazwisko: contact_details.imie_nazwisko,
uz_adres: contact_details.adres,
};
const forms = [
{
...main_data,
source: "sm_zgloszenia_step1",
goto_sm_zgloszenia_step1_1: "",
},
{
source: "sm_zgloszenia_step1_1",
x,
y,
lon: x,
lat: y,
srs: "EPSG:2177",
id_ulica_city: "Poznań",
srs_id: "EPSG:2177",
id_ulica_street_lookup: "Limanowskiego",
goto_sm_zgloszenia_step1: "",
},
{ ...main_data, goto_sm_zgloszenia_step1_2: "" },
...photos.map((file_path) => ({
...minimal_data,
source: "sm_zgloszenia_step1_2",
goto_sm_zgloszenia_step1_2: "",
uz_file: {
path: file_path,
filename: "photo1.jpg",
contentType: "image/jpeg",
},
})),
{
...minimal_data,
source: "sm_zgloszenia_step1_2",
goto_sm_zgloszenia_step1: "",
},
{ ...main_data, source: "sm_zgloszenia_step1", goto_summary: "" },
];
for (let form of forms) {
const formData = new FormData();
for (let [key, value] of Object.entries(form)) {
if (value.path) {
formData.append(key, fs.createReadStream(value.path), {
filename: value.filename,
contentType: value.contentType,
});
} else {
formData.append(key, value);
}
}
const response = await transport.post(SM_URL, formData, {
headers: { ...headers, ...formData.getHeaders() },
jar,
});
console.log(response.request._headers);
}
const session_id = (jar as any).store.idx["www.um.poznan.pl"]["/mim"]
.JSESSIONID.value;
const response = await spawn("curl", [
"https://www.um.poznan.pl/mim/forms/sm_zgloszenia.html?instance=poznan_sm",
"-H",
`User-Agent: ${headers["User-Agent"]}`,
"-H",
`Accept: ${headers.Accept}`,
"-H",
"Accept-Language: en-US,en;q=0.5",
"--compressed",
"-H",
"Content-Type: application/x-www-form-urlencoded",
"-H",
`Origin: ${headers.Origin}`,
"-H",
"DNT: 1",
"-H",
"Connection: keep-alive",
"-H",
`Referer: ${headers.Referer}`,
"-H",
`Cookie: mim_cookie_test=enabled; JSESSIONID=${session_id}`,
"-H",
"Upgrade-Insecure-Requests: 1",
"--data",
`action=save&source=summary&instance=poznan_sm&x=${x}&y=${y}&lon=${x}&lat=${y}&srs=EPSG%3A2177&goto_thanks=`,
]);
const matches = response.match(
/<li>Numer: <strong>([0-9]+)<\/strong><\/li>/
);
if (matches === null) {
throw new Error("Could not extract submission number");
}
return matches[1];
4 years ago
}