auth works

This commit is contained in:
KoenDR06 2025-09-01 23:26:30 +02:00
parent 745a4014a5
commit f9266ee695
6 changed files with 79 additions and 16 deletions

View file

@ -1,6 +1,7 @@
package me.koendev package me.koendev
import io.github.cdimascio.dotenv.Dotenv import io.github.cdimascio.dotenv.Dotenv
import me.koendev.utils.println
import java.io.File import java.io.File
import java.time.LocalDate import java.time.LocalDate
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
@ -15,23 +16,30 @@ data class ReactableOffer(
) )
fun main() { fun main() {
val sessionToken = auth()
print("Getting rooms")
val rooms = getRooms().filter { room -> val rooms = getRooms().filter { room ->
room.unitType == config.general.unitType room.unitType == config.general.unitType
} }
if (rooms.isEmpty()) { if (rooms.isEmpty()) {
println("No suitable offers were found, quitting.") System.err.println("No suitable offers were found, quitting.")
return return
} }
val offers = getOffers(rooms.map { it.wocasId }).offers.filter { offer -> val offers = getOffers(rooms.map { it.wocasId }).offers.filter { offer ->
offer.adres[0].plaats in listOf( offer.adres[0].plaats in listOf(
"UTRECHT", "UTRECHT",
) + if (config.general.allowZeist) "ZEIST" else "" ) + if (config.general.allowZeist) "ZEIST" else ""
} }
print("\rFiltering on personal filters")
var index = 0
val coupled = rooms.mapNotNull { room -> val coupled = rooms.mapNotNull { room ->
val offer: Offer? = offers.find { room.wocasId.toInt() == it.eenheidNummer.toInt() } val offer: Offer? = offers.find { room.wocasId.toInt() == it.eenheidNummer.toInt() }
if (offer == null) null else ReactableOffer(room, offer, getFloorInfo(room)) print("\rFiltering per room: ${index++} / ${rooms.size}")
if (offer == null) null else ReactableOffer(room, offer, getFloorInfo(room, sessionToken))
}.filter { }.filter {
val gender = it.floor.floorInfo.genderPreference val gender = it.floor.floorInfo.genderPreference
@ -40,13 +48,16 @@ fun main() {
val date2 = LocalDate.parse(date, DateTimeFormatter.ofPattern("yyyy-MM-dd")) val date2 = LocalDate.parse(date, DateTimeFormatter.ofPattern("yyyy-MM-dd"))
val daysLeft = ChronoUnit.DAYS.between(date1, date2) val daysLeft = ChronoUnit.DAYS.between(date1, date2)
val smoking = it.floor.floorInfo.smokingAllowed ?: true
val pets = it.floor.floorInfo.petsAllowed ?: false
((gender == "female" && config.gender.female) || ((gender == "female" && config.gender.female) ||
(gender == "male" && config.gender.male) || (gender == "male" && config.gender.male) ||
(gender == "none" && config.gender.none)) && (gender == "none" && config.gender.none)) &&
((config.general.smoking == -1 && !(it.floor.floorInfo.smokingAllowed ?: true)) || (config.general.smoking == 1 && it.floor.floorInfo.smokingAllowed ?: true) || config.general.smoking == 0) && ((config.general.smoking == -1 && !smoking) || (config.general.smoking == 1 && smoking) || config.general.smoking == 0) &&
((config.general.pets == -1 && !it.floor.floorInfo.petsAllowed) || (config.general.pets == 1 && it.floor.floorInfo.petsAllowed) || config.general.pets == 0) && ((config.general.pets == -1 && !pets) || (config.general.pets == 1 && pets) || config.general.pets == 0) &&
daysLeft == 0L daysLeft == 0L
} }
@ -76,7 +87,7 @@ fun main() {
str.append("| Geslacht | ${genderString.padEnd(18, ' ')} |\n") str.append("| Geslacht | ${genderString.padEnd(18, ' ')} |\n")
str.append("| Roken | ${(if (it.floor.floorInfo.smokingAllowed ?: true) "✅ Mag" else "❌ Mag niet").padEnd(17, ' ')} |\n") str.append("| Roken | ${(if (it.floor.floorInfo.smokingAllowed ?: true) "✅ Mag" else "❌ Mag niet").padEnd(17, ' ')} |\n")
str.append("| Huisdieren | ${(if (it.floor.floorInfo.petsAllowed) "✅ Mogen" else "❌ Mogen niet").padEnd(17, ' ')} |\n") str.append("| Huisdieren | ${(if (it.floor.floorInfo.petsAllowed ?: false) "✅ Mogen" else "❌ Mogen niet").padEnd(17, ' ')} |\n")
val positionString = "${it.floor.potentialPosition} / ${it.floor.applicantCount}." val positionString = "${it.floor.potentialPosition} / ${it.floor.applicantCount}."
str.append("| Reacties | ${positionString.padEnd(18, ' ')} |\n") str.append("| Reacties | ${positionString.padEnd(18, ' ')} |\n")
@ -90,11 +101,11 @@ fun main() {
val etage = getEtage(it.offer.assSubjectPersk.first { it.pkHeeftAsp == 52.0 }.waarde!!) val etage = getEtage(it.offer.assSubjectPersk.first { it.pkHeeftAsp == 52.0 }.waarde!!)
str.append("![Foto](${etage.photos[0].etagePhoto[0].url})\n\n") if (etage != null) str.append("![Foto](${etage.photos[0].etagePhoto[0].url})\n\n")
str.append("### Message: \n\n${it.floor.floorInfo.description ?: "Deze pannekoeken hebben geen bericht achtergelaten"}\n") str.append("### Message: \n\n${it.floor.floorInfo.description ?: "Deze pannekoeken hebben geen bericht achtergelaten"}\n")
str.append("\n\n") str.append("\n\n")
} }
out.writeText(str.toString()) out.writeText(str.toString())
println("${coupled.size} offers found, wrote to $fileName") println("\r${coupled.size} offers found, wrote to $fileName")
} }

View file

@ -0,0 +1,51 @@
package me.koendev
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonIgnoreUnknownKeys
import me.koendev.utils.println
import java.net.URI
import java.net.http.HttpClient
import java.net.http.HttpRequest
import java.net.http.HttpResponse
fun auth(): String {
val data: Map<String, String> = mapOf(
"Email" to dotEnv["EMAIL"],
"Password" to dotEnv["PASSWORD"],
"Pin" to "",
"Role" to ""
)
val req = HttpRequest.newBuilder()
.uri(URI.create("https://www.sshxl.nl/api/portal/ApiLogin"))
.header("User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:138.0) Gecko/20100101 Firefox/138.0")
.header("Accept", "*/*")
.header("Content-Type", "application/json")
.header("Accept-Language", "en-US,en;q=0.5")
.header(
"Cookie",
listOf(
"cookie_consent_analytics=no",
"cookie_consent=no",
"SSHContext=${dotEnv["AUTH"]}"
).joinToString("; ")
)
.POST(HttpRequest.BodyPublishers.ofString(Json.encodeToString(data)))
.build()
val client = HttpClient.newBuilder()
.followRedirects(HttpClient.Redirect.NORMAL)
.build()
val res = client.send(req, HttpResponse.BodyHandlers.ofString())
if (res.statusCode() != 200) {
throw Exception("auth failed with status code ${res.statusCode()}")
}
return Json.decodeFromString<Auth>(res.body()).session
}
@JsonIgnoreUnknownKeys
@Serializable
private data class Auth(val session: String)

View file

@ -33,8 +33,8 @@ data class EtagePhotoItem(
@SerialName("Photo") val url: String @SerialName("Photo") val url: String
) )
fun getEtage(id: String): Etage { fun getEtage(id: String): Etage? {
val response = getEndpoint("OData/Etage?\$filter=(EtageWocasId%20eq%20'$id')&\$expand=Etage_EtagePhoto!(\$select=Id,EtagePhotoId,EtageId;\$expand=EtagePhoto!(\$select=Id,Photo))&\$select=Id,EtageWocasId") val response = getEndpoint("OData/Etage?\$filter=(EtageWocasId%20eq%20'$id')&\$expand=Etage_EtagePhoto!(\$select=Id,EtagePhotoId,EtageId;\$expand=EtagePhoto!(\$select=Id,Photo))&\$select=Id,EtageWocasId")
return Json.decodeFromString<Etages>(response).offers.first() return Json.decodeFromString<Etages>(response).offers.firstOrNull()
} }

View file

@ -10,7 +10,7 @@ data class FloorInfo(
@SerialName("Description") val description: String?, @SerialName("Description") val description: String?,
@SerialName("HospiteerDate") val hospiteerDate: String?, @SerialName("HospiteerDate") val hospiteerDate: String?,
@SerialName("PreferenceSmokingAllowed") val smokingAllowed: Boolean?, @SerialName("PreferenceSmokingAllowed") val smokingAllowed: Boolean?,
@SerialName("PreferencePetsAllowed") val petsAllowed: Boolean, @SerialName("PreferencePetsAllowed") val petsAllowed: Boolean?,
@SerialName("PreferenceGender") val genderPreference: String, @SerialName("PreferenceGender") val genderPreference: String,
@SerialName("NumberOfUnits") val numberOfUnits: Int, @SerialName("NumberOfUnits") val numberOfUnits: Int,
) )
@ -41,8 +41,8 @@ data class Floor(
@SerialName("Kind") val kind: String, @SerialName("Kind") val kind: String,
) )
fun getFloorInfo(room: Room): Floor { fun getFloorInfo(room: Room, session: String): Floor {
val response = getEndpoint("offer/${room.flowId}") val response = getEndpoint("offer/${room.flowId}", session)
return Json.decodeFromString<Floor>(response) return Json.decodeFromString<Floor>(response)
} }

View file

@ -3,6 +3,7 @@ package me.koendev
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import me.koendev.utils.println
@Serializable @Serializable
data class Offers( data class Offers(

View file

@ -10,7 +10,7 @@ import java.net.http.HttpResponse
* *
* @return a HttpRequest with all the necessary properties to GET the endpoint. * @return a HttpRequest with all the necessary properties to GET the endpoint.
*/ */
fun buildRequest(path: String): HttpRequest { fun buildRequest(path: String, session: String): HttpRequest {
return HttpRequest.newBuilder() return HttpRequest.newBuilder()
.uri(URI("https://www.sshxl.nl/api/v1/$path")) .uri(URI("https://www.sshxl.nl/api/v1/$path"))
.header("User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:138.0) Gecko/20100101 Firefox/138.0") .header("User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:138.0) Gecko/20100101 Firefox/138.0")
@ -21,19 +21,19 @@ fun buildRequest(path: String): HttpRequest {
listOf( listOf(
"cookie_consent_analytics=no", "cookie_consent_analytics=no",
"cookie_consent=no", "cookie_consent=no",
"SSHContext=${dotEnv["AUTH"]}" "SSHContext=$session"
).joinToString("; ") ).joinToString("; ")
) )
.GET() .GET()
.build() .build()
} }
fun getEndpoint(endpoint: String): String { fun getEndpoint(endpoint: String, session: String = ""): String {
val client = HttpClient.newBuilder() val client = HttpClient.newBuilder()
.followRedirects(HttpClient.Redirect.NORMAL) .followRedirects(HttpClient.Redirect.NORMAL)
.build() .build()
val request = buildRequest(endpoint) val request = buildRequest(endpoint, session)
return client.send(request, HttpResponse.BodyHandlers.ofString()).body() return client.send(request, HttpResponse.BodyHandlers.ofString()).body()
} }