fix may 2024 player rank source federal update

multistore
Razmig Sarkissian 2 years ago
parent 27beca502b
commit f417a084b9
  1. 74
      PadelClub/Data/Federal/FederalPlayer.swift
  2. 3
      PadelClub/Data/Tournament.swift
  3. 3
      PadelClub/Utils/FileImportManager.swift
  4. 28
      PadelClub/Utils/SourceFileManager.swift
  5. 6
      PadelClub/Views/Navigation/MainView.swift
  6. 67
      PadelClub/Views/Navigation/Toolbox/PadelClubView.swift

@ -7,7 +7,7 @@
import Foundation
struct FederalPlayer {
struct FederalPlayer: Decodable {
var rank: Int
var lastName: String
var firstName: String
@ -21,6 +21,74 @@ struct FederalPlayer {
var club: String
var isMale: Bool
// MARK: - Nationnalite
struct Nationnalite: Hashable, Codable {
let code, codeFov: String
}
init(from decoder: Decoder) throws {
enum CodingKeys: String, CodingKey {
case nom
case prenom
case licence
case meilleurClassement
case nationnalite
case anneeNaissance
case codeClub
case nomClub
case nomLigue
case rang
case progression
case points
case nombreDeTournois
case assimile
}
let container = try decoder.container(keyedBy: CodingKeys.self)
isMale = (decoder.userInfo[.maleData] as? Bool) == true
let _lastName = try container.decode(String.self, forKey: .nom)
let _firstName = try container.decode(String.self, forKey: .prenom)
lastName = _lastName
firstName = _firstName
if let lic = try? container.decodeIfPresent(Int.self, forKey: .licence) {
license = String(lic)
} else {
license = ""
}
let nationnalite = try container.decode(Nationnalite.self, forKey: .nationnalite)
country = nationnalite.code
//meilleurClassement = try container.decode(Int.self, forKey: .meilleurClassement)
//anneeNaissance = try container.decode(Int.self, forKey: .anneeNaissance)
clubCode = try container.decode(String.self, forKey: .codeClub)
club = try container.decode(String.self, forKey: .nomClub)
ligue = try container.decode(String.self, forKey: .nomLigue)
rank = try container.decode(Int.self, forKey: .rang)
//progression = try? container.decodeIfPresent(Int.self, forKey: .progression)
let pointsAsInt = try? container.decodeIfPresent(Int.self, forKey: .points)
if let pointsAsInt {
points = Double(pointsAsInt)
} else {
points = nil
}
tournamentCount = try? container.decodeIfPresent(Int.self, forKey: .nombreDeTournois)
let assimile = try container.decode(Bool.self, forKey: .assimile)
assimilation = assimile ? "Oui" : "Non"
fullNameCanonical = _lastName.canonicalVersion + " " + _firstName.canonicalVersion
}
func exportToCSV() -> String {
let pointsString = points != nil ? Int(points!).formatted() : ""
let tournamentCountString = tournamentCount != nil ? tournamentCount!.formatted() : ""
let strippedLicense = license.strippedLicense ?? ""
let line = ";\(rank);\(lastName);\(firstName);\(country);\(strippedLicense);\(pointsString);\(assimilation);\(tournamentCountString);\(ligue);\(clubCode);\(club);"
return line
}
var fullNameCanonical: String
/*
@ -115,3 +183,7 @@ struct FederalPlayer {
}
}
extension CodingUserInfoKey {
static let maleData = Self(rawValue: "maleData")!
}

@ -870,11 +870,10 @@ class Tournament : ModelObject, Storable {
let lastRankMan = currentMonthData()?.maleUnrankedValue
let lastRankWoman = currentMonthData()?.femaleUnrankedValue
try await unsortedPlayers().concurrentForEach { player in
let dataURLs = SourceFileManager.shared.allFiles.filter({ $0.dateFromPath == newDate })
let sources = dataURLs.map { CSVParser(url: $0) }
try await unsortedPlayers().concurrentForEach { player in
try await player.updateRank(from: sources, lastRank: (player.sex == .female ? lastRankWoman : lastRankMan) ?? 0)
}
}

@ -6,6 +6,7 @@
//
import Foundation
import LeStorage
class FileImportManager {
static let shared = FileImportManager()
@ -147,7 +148,7 @@ class FileImportManager {
}
func importingChunkOfPlayers(_ players: [FederalPlayer], importingDate: Date) async {
for chunk in players.chunked(into: 1000) {
for chunk in players.chunked(into: 2000) {
await PersistenceController.shared.batchInsertPlayers(chunk, importingDate: importingDate)
}
}

@ -6,6 +6,7 @@
//
import Foundation
import LeStorage
class SourceFileManager {
static let shared = SourceFileManager()
@ -60,6 +61,26 @@ class SourceFileManager {
}
}
func exportToCSV(players: [FederalPlayer], sourceFileType: SourceFile, date: Date) {
let lastDateString = URL.importDateFormatter.string(from: date)
let dateString = ["CLASSEMENT-PADEL", sourceFileType.rawValue, lastDateString].joined(separator: "-") + "." + "csv"
let documentsUrl:URL = (FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first as URL?)!
let destinationFileUrl = documentsUrl.appendingPathComponent("\(dateString)")
var csvText : String = ""
for player in players {
csvText.append(player.exportToCSV() + "\n")
}
do {
try csvText.write(to: destinationFileUrl, atomically: true, encoding: .utf8)
print("CSV file exported successfully.")
} catch {
print("Error writing CSV file:", error)
Logger.error(error)
}
}
func fetchData(fromDate current: Date) async {
let lastStringDate = URL.importDateFormatter.string(from: current)
@ -148,6 +169,13 @@ class SourceFileManager {
}
}
func jsonFiles() -> [URL] {
let allJSONFiles = try! FileManager.default.contentsOfDirectory(at: rankingSourceDirectory, includingPropertiesForKeys: nil).filter({ url in
url.pathExtension == "json"
})
return allJSONFiles
}
var allFiles: [URL] {
let allFiles = try! FileManager.default.contentsOfDirectory(at: rankingSourceDirectory, includingPropertiesForKeys: nil).filter({ url in
url.pathExtension == "csv"

@ -126,11 +126,7 @@ struct MainView: View {
Task {
let lastDataSource = await FileImportManager.shared.importDataFromFFT()
dataStore.appSettings.lastDataSource = lastDataSource
do {
try dataStore.appSettingsStorage.write()
} catch {
Logger.error(error)
}
dataStore.appSettingsStorage.write()
if let lastDataSource, let mostRecentDate = URL.importDateFormatter.date(from: lastDataSource) {
await MonthData.calculateCurrentUnrankedValues(mostRecentDateAvailable: mostRecentDate)
}

@ -47,6 +47,53 @@ struct PadelClubView: View {
Text("Classement mensuel utilisé")
}
}
if let mostRecentDateAvailable = SourceFileManager.shared.mostRecentDateAvailable, _lastDataSourceDate.isEarlierThan(mostRecentDateAvailable) {
Section {
RowButtonView("Importer \(URL.importDateFormatter.string(from: mostRecentDateAvailable))") {
_startImporting()
}
}
}
#if targetEnvironment(simulator)
/*
["36435", "BOUNOUA", "walid", "France", "3311600", "15,00", "Non", "2", "AUVERGNE RHONE-ALPES", "50 73 0046", "CHAMBERY 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)
SourceFileManager.shared.exportToCSV(players: players, sourceFileType: fileURL.manData ? .messieurs : .dames, date: fileURL.dateFromPath)
} catch {
Logger.error(error)
}
}
}
}
#endif
}
if importingFiles {
ContentUnavailableView("Importation en cours", systemImage: "server.rack", description: Text("Une importation des données fédérales publiques est en cours, veuillez patienter."))
} else if (players.isEmpty || lastDataSource == nil) {
ContentUnavailableView {
Label("Aucun joueur importé", systemImage: "person.slash")
} description: {
Text("Padel Club peut importer toutes les données publiques de la FFT concernant tous les compétiteurs et compétitrices.")
} actions: {
RowButtonView("Démarrer l'importation") {
_startImporting()
}
}
}
let monthData = dataStore.monthData.sorted(by: \.creationDate).reversed()
@ -72,20 +119,6 @@ struct PadelClubView: View {
Text(monthData.monthKey)
}
}
if importingFiles {
ContentUnavailableView("Importation en cours", systemImage: "server.rack", description: Text("Une importation des données fédérales publiques est en cours, veuillez patienter."))
} else if (players.isEmpty || lastDataSource == nil) {
ContentUnavailableView {
Label("Aucun joueur importé", systemImage: "person.slash")
} description: {
Text("Padel Club peut importer toutes les données publiques de la FFT concernant tous les compétiteurs et compétitrices.")
} actions: {
RowButtonView("Démarrer l'importation") {
_startImporting()
}
}
}
}
.task {
await self._checkSourceFileAvailability()
@ -130,11 +163,7 @@ struct PadelClubView: View {
Task {
let lastDataSource = await FileImportManager.shared.importDataFromFFT()
dataStore.appSettings.lastDataSource = lastDataSource
do {
try dataStore.appSettingsStorage.write()
} catch {
Logger.error(error)
}
dataStore.appSettingsStorage.write()
if let lastDataSource, let mostRecentDate = URL.importDateFormatter.date(from: lastDataSource) {
await MonthData.calculateCurrentUnrankedValues(mostRecentDateAvailable: mostRecentDate)
}

Loading…
Cancel
Save