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, timestamp: Date, contact_details: ContactDetails, plate: string ) { 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${ 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( /
  • Numer: ([0-9]+)<\/strong><\/li>/ ); if (matches === null) { throw new Error("Could not extract submission number"); } return matches[1]; }