You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
197 lines
10 KiB
197 lines
10 KiB
//
|
|
// NetworkFederalService.swift
|
|
// PadelClub
|
|
//
|
|
// Created by Razmig Sarkissian on 21/03/2024.
|
|
//
|
|
|
|
import Foundation
|
|
import CoreLocation
|
|
|
|
class NetworkFederalService {
|
|
struct HttpCommand: Decodable {
|
|
let command: String
|
|
let results: HttpResults?
|
|
let method : String?
|
|
let selector : String?
|
|
let data: String?
|
|
}
|
|
|
|
struct HttpResults: Decodable {
|
|
let nb_results : Int
|
|
let items: [FederalTournament]?
|
|
}
|
|
|
|
static let shared: NetworkFederalService = NetworkFederalService()
|
|
var formId = ""
|
|
|
|
var tenupJsonDecoder: JSONDecoder = {
|
|
let decoder = JSONDecoder()
|
|
let dateFormatter = DateFormatter()
|
|
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS"
|
|
decoder.dateDecodingStrategy = .formatted(dateFormatter)
|
|
return decoder
|
|
}()
|
|
|
|
func runTenupTask<T:Decodable>(request: URLRequest) async throws -> T {
|
|
let task = try await URLSession.shared.data(for: request)
|
|
if request.httpMethod == "PUT" {
|
|
print("tried PUT: \(request.url!)")
|
|
if let urlResponse = task.1 as? HTTPURLResponse {
|
|
print(urlResponse.statusCode)
|
|
}
|
|
}
|
|
return try tenupJsonDecoder.decode(T.self, from: task.0)
|
|
}
|
|
|
|
func federalClubs(country: String = "fr", city: String, radius: Double, location: CLLocation? = nil) async throws -> FederalClubResponse {
|
|
|
|
/*
|
|
{
|
|
"geocoding[country]": "fr",
|
|
"geocoding[ville]": "Cayenne, 973, Guyane",
|
|
"geocoding[rayon]": "15",
|
|
"geocoding[userPosition][lng]": "-52.311583",
|
|
"geocoding[userPosition][lat]": "4.925248",
|
|
"geocoding[userPosition][showDistance]": "false",
|
|
"pratiqueOption[0]": "PADEL",
|
|
"nombreResultat": "6",
|
|
"diplomeEtatOption": "false",
|
|
"galaxieOption": "false",
|
|
"fauteuilOption": "false",
|
|
"tennisSanteOption": "false"
|
|
}
|
|
*/
|
|
|
|
var parameters = "geocoding[country]=\(country)&geocoding[ville]=\(city)&geocoding[rayon]=\(Int(radius))&pratiqueOption[0]=Padel"
|
|
|
|
if let location {
|
|
parameters = parameters + "&geocoding[userPosition][lat]=\(location.coordinate.latitude.formatted(.number.locale(Locale(identifier: "us"))))&geocoding[userPosition][lng]=\(location.coordinate.longitude.formatted(.number.locale(Locale(identifier: "us"))))&geocoding[userPosition][showDistance]=true"
|
|
}
|
|
//"geocoding%5Bcountry%5D=fr&geocoding%5Bville%5D=13%20Avenue%20Emile%20Bodin%2013260%20Cassis&geocoding%5Brayon%5D=15&geocoding%5BuserPosition%5D%5Blat%5D=43.22278594081477&geocoding%5BuserPosition%5D%5Blng%5D=5.556953900769194&geocoding%5BuserPosition%5D%5BshowDistance%5D=true&nombreResultat=0&diplomeEtatOption=false&galaxieOption=false&fauteuilOption=false&tennisSanteOption=false"
|
|
let postData = parameters.data(using: .utf8)
|
|
|
|
var request = URLRequest(url: URL(string: "https://tenup.fft.fr/recherche/clubs/ajax")!,timeoutInterval: Double.infinity)
|
|
request.addValue("application/json, text/plain, */*", forHTTPHeaderField: "Accept")
|
|
request.addValue("fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3", forHTTPHeaderField: "Accept-Language")
|
|
request.addValue("gzip, deflate, br", forHTTPHeaderField: "Accept-Encoding")
|
|
request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
|
|
request.addValue("https://tenup.fft.fr", forHTTPHeaderField: "Origin")
|
|
request.addValue("keep-alive", forHTTPHeaderField: "Connection")
|
|
request.addValue("https://tenup.fft.fr/recherche/clubs/list", forHTTPHeaderField: "Referer")
|
|
// request.addValue("a20ba3b563e5ce7ad731c2c1076b217f=a2de91fbefddf75ea4aa86297ed09bd5; visid_incap_2712217=TZgb6G1zTsiPtpJ4cCmOErtj8GQAAAAAQUIPAAAAAAC5nrgD+rm7QWCdUN5I8Y6T; nlbi_2712217=Ug01X5TrSizGkQw5qBb2twAAAAAOvBNMkIHMeRAJGDiOaFxs; incap_ses_391_2712217=E60LNJzW7B+BjW0qWx1tBbtj8GQAAAAAlw5keZVI9C7egwKQblAHeQ==; TCPID=1238411561211442193459; TCID=; incap_ses_391_2712217=MzHHL4jK9k4gpmkqWx1tBT9i8GQAAAAA1k2Eroyuow6SC5Zmf1WtVA==; visid_incap_2712217=lVlg9romTq6I9k4sVklsgr9F72QAAAAAQUIPAAAAAADw7ISp7aFXSsqidxqlj3Df", forHTTPHeaderField: "Cookie")
|
|
request.addValue("empty", forHTTPHeaderField: "Sec-Fetch-Dest")
|
|
request.addValue("cors", forHTTPHeaderField: "Sec-Fetch-Mode")
|
|
request.addValue("same-origin", forHTTPHeaderField: "Sec-Fetch-Site")
|
|
request.addValue("trailers", forHTTPHeaderField: "TE")
|
|
|
|
request.httpMethod = "POST"
|
|
request.httpBody = postData
|
|
|
|
return try await runTenupTask(request: request)
|
|
}
|
|
|
|
|
|
func getClubFederalTournaments(page: Int, tournaments: [FederalTournament], club: String, codeClub: String, startDate: Date? = nil, endDate: Date? = nil) async throws -> [FederalTournament] {
|
|
|
|
if formId.isEmpty {
|
|
do {
|
|
try await getNewBuildForm()
|
|
} catch {
|
|
print("getClubFederalTournaments", error)
|
|
}
|
|
}
|
|
|
|
var dateComponent = ""
|
|
if let startDate, let endDate {
|
|
dateComponent = "&date[start]=\(startDate.twoDigitsYearFormatted)&date[end]=\(endDate.endOfMonth.twoDigitsYearFormatted)"
|
|
} else if let startDate {
|
|
dateComponent = "&date[start]=\(startDate.twoDigitsYearFormatted)&date[end]=\(Calendar.current.date(byAdding: .month, value: 3, to: startDate)!.endOfMonth.twoDigitsYearFormatted)"
|
|
}
|
|
|
|
let parameters = """
|
|
recherche_type=club&club[autocomplete][value_container][value_field]=\(codeClub.replaceCharactersFromSet(characterSet: .whitespaces))&club[autocomplete][value_container][label_field]=\(club.replaceCharactersFromSet(characterSet: .whitespaces, replacementString: "+"))&pratique=PADEL\(dateComponent)&page=\(page)&sort=dateDebut+asc&form_build_id=\(formId)&form_id=recherche_tournois_form&_triggering_element_name=submit_page&_triggering_element_value=Submit+page
|
|
"""
|
|
let postData = parameters.data(using: .utf8)
|
|
|
|
var request = URLRequest(url: URL(string: "https://tenup.fft.fr/system/ajax")!,timeoutInterval: Double.infinity)
|
|
request.addValue("application/json, text/javascript, */*; q=0.01", forHTTPHeaderField: "Accept")
|
|
request.addValue("fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3", forHTTPHeaderField: "Accept-Language")
|
|
request.addValue("gzip, deflate, br", forHTTPHeaderField: "Accept-Encoding")
|
|
request.addValue("application/x-www-form-urlencoded; charset=UTF-8", forHTTPHeaderField: "Content-Type")
|
|
request.addValue("XMLHttpRequest", forHTTPHeaderField: "X-Requested-With")
|
|
request.addValue("https://tenup.fft.fr", forHTTPHeaderField: "Origin")
|
|
request.addValue("keep-alive", forHTTPHeaderField: "Connection")
|
|
request.addValue("https://tenup.fft.fr/recherche/tournois", forHTTPHeaderField: "Referer")
|
|
request.addValue("empty", forHTTPHeaderField: "Sec-Fetch-Dest")
|
|
request.addValue("cors", forHTTPHeaderField: "Sec-Fetch-Mode")
|
|
request.addValue("same-origin", forHTTPHeaderField: "Sec-Fetch-Site")
|
|
|
|
request.httpMethod = "POST"
|
|
request.httpBody = postData
|
|
|
|
let commands : [HttpCommand] = try await runTenupTask(request: request)
|
|
if commands.anySatisfy({ $0.command == "alert" }) {
|
|
throw NetworkManagerError.maintenance
|
|
}
|
|
let resultCommand = commands.first(where: { $0.results != nil })
|
|
if let gatheredTournaments = resultCommand?.results?.items {
|
|
var finalTournaments = tournaments + gatheredTournaments
|
|
if let count = resultCommand?.results?.nb_results {
|
|
if finalTournaments.count < count {
|
|
let newTournaments = try await getClubFederalTournaments(page: page+1, tournaments: finalTournaments, club: club, codeClub: codeClub)
|
|
finalTournaments = finalTournaments + newTournaments
|
|
}
|
|
}
|
|
|
|
return finalTournaments
|
|
}
|
|
|
|
// do {
|
|
// } catch {
|
|
// print("getClubFederalTournaments", error)
|
|
// }
|
|
//
|
|
return []
|
|
}
|
|
|
|
func getNewBuildForm() async throws {
|
|
var request = URLRequest(url: URL(string: "https://tenup.fft.fr/recherche/tournois")!,timeoutInterval: Double.infinity)
|
|
request.addValue("application/json, text/javascript, */*; q=0.01", forHTTPHeaderField: "Accept")
|
|
request.addValue("fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3", forHTTPHeaderField: "Accept-Language")
|
|
request.addValue("gzip, deflate, br", forHTTPHeaderField: "Accept-Encoding")
|
|
request.addValue("application/x-www-form-urlencoded; charset=UTF-8", forHTTPHeaderField: "Content-Type")
|
|
request.addValue("XMLHttpRequest", forHTTPHeaderField: "X-Requested-With")
|
|
request.addValue("https://tenup.fft.fr", forHTTPHeaderField: "Origin")
|
|
request.addValue("keep-alive", forHTTPHeaderField: "Connection")
|
|
request.addValue("https://tenup.fft.fr/recherche/tournois", forHTTPHeaderField: "Referer")
|
|
request.addValue("empty", forHTTPHeaderField: "Sec-Fetch-Dest")
|
|
request.addValue("cors", forHTTPHeaderField: "Sec-Fetch-Mode")
|
|
request.addValue("same-origin", forHTTPHeaderField: "Sec-Fetch-Site")
|
|
request.addValue("trailers", forHTTPHeaderField: "TE")
|
|
|
|
request.httpMethod = "GET"
|
|
let task = try await URLSession.shared.data(for: request)
|
|
|
|
if let stringData = String(data: task.0, encoding: .utf8) {
|
|
let stringDataFolded = stringData.replaceCharactersFromSet(characterSet: .whitespacesAndNewlines)
|
|
|
|
let prefix = "form_build_id\"value=\"form-"
|
|
var finalData = ""
|
|
if let lab = stringDataFolded.matches(of: try! Regex("\(prefix)")).last {
|
|
finalData = String(stringDataFolded[lab.range.upperBound...])
|
|
}
|
|
|
|
let suffix = "\"/><inputtype=\"hidden\"name=\"form_id\"value=\"recherche_tournois_form"
|
|
if let suff = finalData.firstMatch(of: try! Regex("\(suffix)")) {
|
|
finalData = String(finalData[..<suff.range.lowerBound])
|
|
}
|
|
print(finalData)
|
|
|
|
formId = "form-\(finalData)"
|
|
|
|
} else {
|
|
print("no data found in html")
|
|
}
|
|
}
|
|
}
|
|
|