@ -40,10 +40,10 @@ struct PadelClubView: View {
if let currentMonth = monthData . first , currentMonth . incompleteMode {
if let currentMonth = monthData . first , currentMonth . incompleteMode {
Section {
Section {
Text ( " Attention, depuis Août 2024, les données fédérales publiques des joueurs (messieurs) récupérables sont incomplètes car limité au 4 0.000 premiers joueurs. " )
Text ( " Attention, depuis Août 2024, les données fédérales publiques des joueurs (messieurs) récupérables sont incomplètes car limité au 8 0.000 premiers joueurs. " )
if currentMonth . maleUnrankedValue = = nil {
if currentMonth . maleUnrankedValue = = nil {
Text ( " Le rang d'un joueur non-classé n'est donc pas calculable pour le moment, Padel Club utilisera une valeur par défaut de de 7 0.000. " )
Text ( " Le rang d'un joueur non-classé n'est donc pas calculable pour le moment, Padel Club utilisera une valeur par défaut de de 9 0.000. " )
}
}
Text ( " Un classement souligné comme ci-dessous indiquera que l'information provient d'un mois précédent. " )
Text ( " Un classement souligné comme ci-dessous indiquera que l'information provient d'un mois précédent. " )
@ -61,32 +61,22 @@ struct PadelClubView: View {
[ " 36435 " , " BRUL… " , " Romain " , " France " , " 2993139 " , " 15,00 " , " Non " , " 2 " , " NOUVELLE AQUITAINE " , " 59 33 0447 " , " SAINT LOUBES TC " ]
[ " 36435 " , " BRUL… " , " Romain " , " France " , " 2993139 " , " 15,00 " , " Non " , " 2 " , " NOUVELLE AQUITAINE " , " 59 33 0447 " , " SAINT LOUBES TC " ]
*/
*/
Section {
RowButtonView ( " Exporter en csv " ) {
for fileURL in SourceFileManager . shared . jsonFiles ( ) {
let decoder = JSONDecoder ( )
decoder . userInfo [ . maleData ] = fileURL . manData
do {
let data = try Data ( contentsOf : fileURL )
let players = try decoder . decode ( [ FederalPlayer ] . self , from : data )
var anonymousPlayers = players . filter { $0 . firstName . isEmpty && $0 . lastName . isEmpty }
let okPlayers = players . filter { $0 . firstName . isEmpty = = false && $0 . lastName . isEmpty = = false }
print ( " before anonymousPlayers.count " , anonymousPlayers . count )
FileImportManager . shared . updatePlayers ( isMale : fileURL . manData , players : & anonymousPlayers )
print ( " after local anonymousPlayers.count " , anonymousPlayers . filter { $0 . firstName . isEmpty && $0 . lastName . isEmpty } . count )
await fetchPlayersDataSequentially ( for : & anonymousPlayers )
Section {
RowButtonView ( " Retry Anonymous " ) {
await _retryAnonymous ( )
}
}
print ( " after beach anonymousPlayers.count " , anonymousPlayers . filter { $0 . firstName . isEmpty && $0 . lastName . isEmpty }
Section {
. count )
RowButtonView ( " Write anonymous " ) {
SourceFileManager . shared . exportToCSV ( players : okPlayers + anonymousPlayers , sourceFileType : fileURL . manData ? . messieurs : . dames , date : fileURL . dateFromPath )
_writeAnonymous ( )
SourceFileManager . shared . exportToCSV ( " anonymes " , players : anonymousPlayers . filter { $0 . firstName . isEmpty && $0 . lastName . isEmpty } , sourceFileType : fileURL . manData ? . messieurs : . dames , date : fileURL . dateFromPath )
} catch {
Logger . error ( error )
}
}
}
}
Section {
RowButtonView ( " Exporter en csv " ) {
await _exportCsv ( )
}
}
}
}
#endif
#endif
@ -169,7 +159,7 @@ struct PadelClubView: View {
if let maleUnrankedValue = monthData . maleUnrankedValue {
if let maleUnrankedValue = monthData . maleUnrankedValue {
Text ( maleUnrankedValue . formatted ( ) )
Text ( maleUnrankedValue . formatted ( ) )
} else {
} else {
Text ( 7 0_000.formatted ( ) )
Text ( 9 0_000.formatted ( ) )
}
}
} label : {
} label : {
Text ( " Rang d'un non classé " )
Text ( " Rang d'un non classé " )
@ -187,6 +177,11 @@ struct PadelClubView: View {
Text ( " Rang d'une non classée " )
Text ( " Rang d'une non classée " )
Text ( " Dames " )
Text ( " Dames " )
}
}
#if DEBUG
RowButtonView ( " recalc " ) {
await _calculateLastRank ( dataSource : monthData . monthKey )
}
#endif
} header : {
} header : {
HStack {
HStack {
Text ( monthData . monthKey )
Text ( monthData . monthKey )
@ -242,15 +237,110 @@ struct PadelClubView: View {
await SourceFileManager . shared . getAllFiles ( initialDate : " 08-2022 " )
await SourceFileManager . shared . getAllFiles ( initialDate : " 08-2022 " )
self . uuid = UUID ( )
self . uuid = UUID ( )
}
}
#if DEBUG
private func _calculateMonthData ( dataSource : String ? ) async {
if let dataSource , let mostRecentDate = URL . importDateFormatter . date ( from : dataSource ) {
await MonthData . calculateCurrentUnrankedValues ( fromDate : mostRecentDate )
}
}
private func _calculateLastRank ( dataSource : String ) async {
await _calculateMonthData ( dataSource : dataSource )
}
private func _writeAnonymous ( ) {
for fileURL in SourceFileManager . shared . anonymousFiles ( ) {
let lastDateString = URL . importDateFormatter . string ( from : fileURL . dateFromPath )
let sourceType = fileURL . manData ? SourceFile . messieurs : SourceFile . dames
let dateString = [ " CLASSEMENT-PADEL " , sourceType . rawValue , lastDateString ] . filter ( { $0 . isEmpty = = false } ) . joined ( separator : " - " ) + " . " + " csv "
let documentsUrl : URL = ( FileManager . default . urls ( for : . documentDirectory , in : . userDomainMask ) . first as URL ? ) !
let destinationFileUrl = documentsUrl . appendingPathComponent ( " rankings " ) . appendingPathComponent ( " \( dateString ) " )
updateCSVFile ( sourceCSVURL : destinationFileUrl , updatedCSVURL : fileURL )
}
}
private func _retryAnonymous ( ) async {
for fileURL in SourceFileManager . shared . anonymousFiles ( ) {
let players = FileImportManager . shared . readCSV ( inputFile : fileURL )
var anonymousPlayers = players
print ( " before anonymousPlayers.count " , anonymousPlayers . count )
await fetchPlayersDataSequentially ( for : & anonymousPlayers )
print ( " after beach anonymousPlayers.count " , anonymousPlayers . filter { $0 . firstName . isEmpty && $0 . lastName . isEmpty }
. count )
SourceFileManager . shared . exportToCSV ( " anonymes " , players : anonymousPlayers , sourceFileType : fileURL . manData ? . messieurs : . dames , date : fileURL . dateFromPath )
}
}
private func _exportCsv ( ) async {
for fileURL in SourceFileManager . shared . jsonFiles ( ) {
let decoder = JSONDecoder ( )
decoder . userInfo [ . maleData ] = fileURL . manData
do {
let data = try Data ( contentsOf : fileURL )
let players = try decoder . decode ( [ FederalPlayer ] . self , from : data )
var anonymousPlayers = players . filter { $0 . firstName . isEmpty && $0 . lastName . isEmpty }
let okPlayers = players . filter { $0 . firstName . isEmpty = = false && $0 . lastName . isEmpty = = false }
print ( " before anonymousPlayers.count " , anonymousPlayers . count )
FileImportManager . shared . updatePlayers ( isMale : fileURL . manData , players : & anonymousPlayers )
print ( " after local anonymousPlayers.count " , anonymousPlayers . filter { $0 . firstName . isEmpty && $0 . lastName . isEmpty } . count )
await fetchPlayersDataSequentially ( for : & anonymousPlayers )
print ( " after beach anonymousPlayers.count " , anonymousPlayers . filter { $0 . firstName . isEmpty && $0 . lastName . isEmpty }
. count )
SourceFileManager . shared . exportToCSV ( players : okPlayers + anonymousPlayers , sourceFileType : fileURL . manData ? . messieurs : . dames , date : fileURL . dateFromPath )
SourceFileManager . shared . exportToCSV ( " anonymes " , players : anonymousPlayers . filter { $0 . firstName . isEmpty && $0 . lastName . isEmpty } , sourceFileType : fileURL . manData ? . messieurs : . dames , date : fileURL . dateFromPath )
} catch {
Logger . error ( error )
}
}
}
#endif
}
func updateCSVFile ( sourceCSVURL : URL , updatedCSVURL : URL ) {
do {
let sourceCSVContent = try String ( contentsOf : sourceCSVURL , encoding : . utf8 )
var sourceCSVLines = sourceCSVContent . components ( separatedBy : " \n " )
let delimiter = " ; "
let updatedCSVContent = try String ( contentsOf : updatedCSVURL , encoding : . utf8 )
let updatedCSVLines = updatedCSVContent . components ( separatedBy : " \n " )
// C r e a t e a d i c t i o n a r y o f u p d a t e d p l a y e r d a t a b y l i c e n s e I d
var updatedPlayerDict : [ String : String ] = [ : ]
for line in updatedCSVLines {
let components = line . components ( separatedBy : delimiter )
if let licenseId = components . dropFirst ( 5 ) . first {
updatedPlayerDict [ licenseId ] = line
}
}
}
// # P r e v i e w {
// U p d a t e t h e s o u r c e C S V l i n e s i f l i c e n s e I d m a t c h e s
// P a d e l C l u b V i e w ( )
for ( index , line ) in sourceCSVLines . enumerated ( ) {
// }
let components = line . components ( separatedBy : delimiter )
if let licenseId = components . dropFirst ( 5 ) . first , let updatedLine = updatedPlayerDict [ licenseId ] {
sourceCSVLines [ index ] = updatedLine
}
}
// W r i t e b a c k t o t h e f i l e
let finalCSVContent = sourceCSVLines . joined ( separator : " \n " )
try finalCSVContent . write ( to : sourceCSVURL , atomically : true , encoding : . utf8 )
print ( " CSV file updated successfully. " )
} catch {
print ( " Error updating CSV file: \( error ) " )
}
}
// F u n c t i o n t o f e t c h d a t a f o r a s i n g l e l i c e n s e I D
// F u n c t i o n t o f e t c h d a t a f o r a s i n g l e l i c e n s e I D
func fetchPlayerData ( for licenseID : String ) async throws -> [ Player ] ? {
func fetchPlayerData ( for licenseID : String , idHomologation : String , sessionId : String ) async throws -> [ Player ] ? {
guard let url = URL ( string : " https://beach-padel.app.fft.fr/beachja/rechercheJoueur/licencies?idHomologation=82469282&numeroLicence= \( licenseID ) " ) else {
guard let url = URL ( string : " https://beach-padel.app.fft.fr/beachja/rechercheJoueur/licencies?idHomologation= \( idHomologation ) &numeroLicence= \( licenseID ) " ) else {
throw URLError ( . badURL )
throw URLError ( . badURL )
}
}
@ -268,7 +358,7 @@ func fetchPlayerData(for licenseID: String) async throws -> [Player]? {
request . setValue ( " XMLHttpRequest " , forHTTPHeaderField : " X-Requested-With " )
request . setValue ( " XMLHttpRequest " , forHTTPHeaderField : " X-Requested-With " )
// A d d c o o k i e s i f n e e d e d ( e x a m p l e c o o k i e h e a d e r v a l u e s h o w n , r e p l a c e w i t h v a l i d c o o k i e s )
// A d d c o o k i e s i f n e e d e d ( e x a m p l e c o o k i e h e a d e r v a l u e s h o w n , r e p l a c e w i t h v a l i d c o o k i e s )
request . setValue ( " JSESSIONID=48C272263C9454774F0DA95F491C3765; AWSALB=nNF/fDwCSm sO9PQD5jkXNUuoMuAzziHT eIkno1uRkNDkKfaOT7VVbh0KOdvGZ5afMw3epLw0p9J+4Ih6cpwqW+XdcLUrr9kJhpQEgP1oeLPR si/4Yn9uCLCRgPKI; AWSALBCORS=nNF/fDwCSm sO9PQD5jkXNUuoMuAzz iHTeIkn o1uRkNDkKfaOT7VVbh0KOdvGZ5afMw3epLw0p9J+4Ih6cpwqW+XdcLUrr9kJhpQEgP1oeLPRsi/4Y n9uCLCRgPK I; datadome=3T1lKPP7j_r9MhBRIq_5sBwcCuhI0lfYgQ414DuY7BdYm3jpvHECT05w6Ohl0xMvGVJi3XayxoRsnsKvPti_TIZ90B~boSu2LYs2lm_OssxFSoDGEHTFOf4HTjVkM6i8; TCID=125221542552726081269; TCSESSION=125221542558139099625; TCPID=125221535336434794787; incap_ses_2224_2712217=T+1ySNxxGx/yVRcIdDzdHrUlomcAAAAAAWv/NX2ushG21NP0K9l10g==; nlbi_2712217=Wd9XXxrrXQSWKZBPb9lUTgAAAADRjV4zuALYepgab2n0ra/7; xtan=-; xtant=1; xtvrn=$548419$; visid_incap_2712217=PSfJngzoSuiowsuXXhvOu5K+7mUAAAAAQUIPAAAAAAAleL9ldvN/FC1VykkU9ret; SessionStatId=10.91.140.42.1662124965429001 " , forHTTPHeaderField : " Cookie " )
request . setValue ( sessionId , forHTTPHeaderField : " Cookie " )
let ( data , _ ) = try await URLSession . shared . data ( for : request )
let ( data , _ ) = try await URLSession . shared . data ( for : request )
let decoder = JSONDecoder ( )
let decoder = JSONDecoder ( )
@ -288,9 +378,21 @@ func fetchPlayerData(for licenseID: String) async throws -> [Player]? {
// F u n c t i o n t o f e t c h d a t a f o r m u l t i p l e l i c e n s e I D s u s i n g T a s k G r o u p
// F u n c t i o n t o f e t c h d a t a f o r m u l t i p l e l i c e n s e I D s u s i n g T a s k G r o u p
func fetchPlayersDataSequentially ( for licenseIDs : inout [ FederalPlayer ] ) async {
func fetchPlayersDataSequentially ( for licenseIDs : inout [ FederalPlayer ] ) async {
var idHomologation : String = " 82469282 "
if let _idHomologation = PListReader . readString ( plist : " local " , key : " idHomologation " ) {
idHomologation = _idHomologation
}
var sessionId : String = " "
if let _sessionId = PListReader . readString ( plist : " local " , key : " JSESSIONID " ) {
sessionId = _sessionId
}
for licenseID in licenseIDs . filter ( { $0 . firstName . isEmpty && $0 . lastName . isEmpty } ) {
for licenseID in licenseIDs . filter ( { $0 . firstName . isEmpty && $0 . lastName . isEmpty } ) {
do {
do {
if let playerData = try await fetchPlayerData ( for : licenseID . license ) ? . first {
if let playerData = try await fetchPlayerData ( for : licenseID . license , idHomologation : idHomologation , sessionId : sessionId ) ? . first {
licenseID . lastName = playerData . nom
licenseID . lastName = playerData . nom
licenseID . firstName = playerData . prenom
licenseID . firstName = playerData . prenom
}
}