add new variable to drawlog and fix filterByStoreIdentifier

improve ranking data debug export
paca_championship
Raz 1 year ago
parent 0c0b492d8f
commit 619702bcff
  1. 71
      PadelClub/Data/DrawLog.swift
  2. 2
      PadelClub/Data/TeamRegistration.swift
  3. 3
      PadelClub/Utils/FileImportManager.swift
  4. 4
      PadelClub/Utils/SourceFileManager.swift
  5. 72
      PadelClub/Views/GroupStage/GroupStageQualificationManagerView.swift
  6. 76
      PadelClub/Views/Navigation/Umpire/PadelClubView.swift
  7. 2
      PadelClub/Views/Round/RoundSettingsView.swift
  8. 4
      PadelClub/Views/Tournament/Shared/TournamentCellView.swift
  9. 3
      PadelClubTests/ServerDataTests.swift

@ -13,7 +13,7 @@ import LeStorage
final class DrawLog: ModelObject, Storable {
static func resourceName() -> String { return "draw-logs" }
static func tokenExemptedMethods() -> [HTTPMethod] { return [] }
static func filterByStoreIdentifier() -> Bool { return false }
static func filterByStoreIdentifier() -> Bool { return true }
static var relationshipNames: [String] = []
var id: String = Store.randomId()
@ -22,14 +22,16 @@ final class DrawLog: ModelObject, Storable {
var drawSeed: Int
var drawMatchIndex: Int
var drawTeamPosition: TeamPosition
var drawType: DrawType
internal init(id: String = Store.randomId(), tournament: String, drawDate: Date = Date(), drawSeed: Int, drawMatchIndex: Int, drawTeamPosition: TeamPosition) {
internal init(id: String = Store.randomId(), tournament: String, drawDate: Date = Date(), drawSeed: Int, drawMatchIndex: Int, drawTeamPosition: TeamPosition, drawType: DrawType) {
self.id = id
self.tournament = tournament
self.drawDate = drawDate
self.drawSeed = drawSeed
self.drawMatchIndex = drawMatchIndex
self.drawTeamPosition = drawTeamPosition
self.drawType = drawType
}
func tournamentObject() -> Tournament? {
@ -48,24 +50,34 @@ final class DrawLog: ModelObject, Storable {
}
func exportedDrawLog() -> String {
[drawDate.localizedDate(), localizedDrawLogLabel(), localizedDrawBranch()].joined(separator: " ")
[drawType.localizedDrawType(), drawDate.localizedDate(), localizedDrawLogLabel(), localizedDrawBranch()].filter({ $0.isEmpty == false }).joined(separator: " ")
}
func localizedDrawSeedLabel() -> String {
return "Tête de série #\(drawSeed + 1)"
return "\(drawType.localizedDrawType()) #\(drawSeed + 1)"
}
func localizedDrawLogLabel() -> String {
return [localizedDrawSeedLabel(), positionLabel()].joined(separator: " -> ")
return [localizedDrawSeedLabel(), positionLabel()].filter({ $0.isEmpty == false }).joined(separator: " -> ")
}
func localizedDrawBranch() -> String {
drawTeamPosition.localizedBranchLabel()
switch drawType {
case .seed:
return drawTeamPosition.localizedBranchLabel()
default:
return ""
}
}
func drawMatch() -> Match? {
let roundIndex = RoundRule.roundIndex(fromMatchIndex: drawMatchIndex)
return tournamentStore.rounds.first(where: { $0.parent == nil && $0.index == roundIndex })?._matches().first(where: { $0.index == drawMatchIndex })
switch drawType {
case .seed:
let roundIndex = RoundRule.roundIndex(fromMatchIndex: drawMatchIndex)
return tournamentStore.rounds.first(where: { $0.parent == nil && $0.index == roundIndex })?._matches().first(where: { $0.index == drawMatchIndex })
default:
return nil
}
}
func positionLabel() -> String {
@ -94,6 +106,32 @@ final class DrawLog: ModelObject, Storable {
case _drawSeed = "drawSeed"
case _drawMatchIndex = "drawMatchIndex"
case _drawTeamPosition = "drawTeamPosition"
case _drawType = "drawType"
}
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(String.self, forKey: ._id)
tournament = try container.decode(String.self, forKey: ._tournament)
drawDate = try container.decode(Date.self, forKey: ._drawDate)
drawSeed = try container.decode(Int.self, forKey: ._drawSeed)
drawMatchIndex = try container.decode(Int.self, forKey: ._drawMatchIndex)
drawTeamPosition = try container.decode(TeamPosition.self, forKey: ._drawTeamPosition)
drawType = try container.decodeIfPresent(DrawType.self, forKey: ._drawType) ?? .seed
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: ._id)
try container.encode(tournament, forKey: ._tournament)
try container.encode(drawDate, forKey: ._drawDate)
try container.encode(drawSeed, forKey: ._drawSeed)
try container.encode(drawMatchIndex, forKey: ._drawMatchIndex)
try container.encode(drawTeamPosition, forKey: ._drawTeamPosition)
try container.encode(drawType, forKey: ._drawType)
}
func insertOnServer() throws {
@ -101,3 +139,20 @@ final class DrawLog: ModelObject, Storable {
}
}
enum DrawType: Int, Codable {
case seed
case groupStage
case court
func localizedDrawType() -> String {
switch self {
case .seed:
return "Tête de série"
case .groupStage:
return "Poule"
case .court:
return "Terrain"
}
}
}

@ -140,7 +140,7 @@ final class TeamRegistration: ModelObject, Storable {
}
if let tournament = tournamentObject() {
if let index = index(in: tournament.selectedSortedTeams()) {
let drawLog = DrawLog(tournament: tournament.id, drawSeed: index, drawMatchIndex: match.index, drawTeamPosition: teamPosition)
let drawLog = DrawLog(tournament: tournament.id, drawSeed: index, drawMatchIndex: match.index, drawTeamPosition: teamPosition, drawType: .seed)
do {
try tournamentStore.drawLogs.addOrUpdate(instance: drawLog)
} catch {

@ -64,9 +64,10 @@ class FileImportManager {
importedPlayer.firstName = firstName.trimmed.capitalized
}
}
playersLeft.removeAll(where: { $0.lastName.isEmpty == false })
}
})
players = playersLeft
}
func foundInWomenData(license: String?) -> Bool {

@ -60,9 +60,9 @@ class SourceFileManager {
}
}
func exportToCSV(players: [FederalPlayer], sourceFileType: SourceFile, date: Date) {
func exportToCSV(_ prefix: String = "", players: [FederalPlayer], sourceFileType: SourceFile, date: Date) {
let lastDateString = URL.importDateFormatter.string(from: date)
let dateString = ["CLASSEMENT-PADEL", sourceFileType.rawValue, lastDateString].joined(separator: "-") + "." + "csv"
let dateString = [prefix, "CLASSEMENT-PADEL", sourceFileType.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("\(dateString)")

@ -0,0 +1,72 @@
//
// GroupStageQualificationManager.swift
// PadelClub
//
// Created by razmig on 05/11/2024.
//
class GroupStageQualificationManager {
private let tournament: Tournament
private let tournamentStore: TournamentStore
init(tournament: Tournament, tournamentStore: TournamentStore) {
self.tournament = tournament
self.tournamentStore = tournamentStore
}
func qualificationSection() -> some View {
guard tournament.groupStageAdditionalQualified > 0 else { return EmptyView() }
let name = "\(tournament.qualifiedPerGroupStage + 1).ordinalFormatted()"
let missingQualifiedFromGroupStages = tournament.missingQualifiedFromGroupStages()
return Section {
NavigationLink {
SpinDrawView(
drawees: missingQualifiedFromGroupStages.isEmpty
? tournament.groupStageAdditionalQualifiedPreDraw()
: ["Qualification d'un \(name) de poule"],
segments: missingQualifiedFromGroupStages.isEmpty
? tournament.groupStageAdditionalLeft()
: missingQualifiedFromGroupStages
) { results in
if !missingQualifiedFromGroupStages.isEmpty {
self.handleDrawResults(results, missingQualifiedFromGroupStages)
}
}
} label: {
Label {
Text("Qualifier un \(name) de poule par tirage au sort")
} icon: {
Image(systemName: "exclamationmark.circle.fill")
.foregroundStyle(.logoBackground)
}
}
.disabled(tournament.moreQualifiedToDraw() == 0)
} footer: {
footerText(missingQualifiedFromGroupStages.isEmpty)
}
}
private func handleDrawResults(_ results: [DrawResult], _ missingQualifiedFromGroupStages: [Team]) {
results.forEach { drawResult in
var team = missingQualifiedFromGroupStages[drawResult.drawIndex]
team.qualified = true
do {
try tournamentStore.teamRegistrations.addOrUpdate(instance: team)
} catch {
Logger.error(error)
}
}
}
private func footerText(_ noMoreTeams: Bool) -> Text {
if tournament.moreQualifiedToDraw() == 0 {
return Text("Aucune équipe supplémentaire à qualifier. Vous pouvez en rajouter en modifiant le paramètre dans structure.")
} else if noMoreTeams {
return Text("Aucune équipe supplémentaire à tirer au sort. Attendez la fin des poules.")
}
return Text("")
}
}

@ -7,6 +7,7 @@
import SwiftUI
import LeStorage
import Foundation
struct PadelClubView: View {
@State private var uuid: UUID = UUID()
@ -74,9 +75,14 @@ struct PadelClubView: View {
print("before anonymousPlayers.count", anonymousPlayers.count)
FileImportManager.shared.updatePlayers(isMale: fileURL.manData, players: &anonymousPlayers)
print("after anonymousPlayers.count", anonymousPlayers.filter { $0.firstName.isEmpty && $0.lastName.isEmpty }
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)
}
@ -241,3 +247,71 @@ struct PadelClubView: View {
//#Preview {
// PadelClubView()
//}
// Function to fetch data for a single license ID
func fetchPlayerData(for licenseID: String) async throws -> [Player]? {
guard let url = URL(string: "https://beach-padel.app.fft.fr/beachja/rechercheJoueur/licencies?idHomologation=82477107&numeroLicence=\(licenseID)") else {
throw URLError(.badURL)
}
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.setValue("application/json, text/javascript, */*; q=0.01", forHTTPHeaderField: "Accept")
request.setValue("same-origin", forHTTPHeaderField: "Sec-Fetch-Site")
request.setValue("fr-FR,fr;q=0.9", forHTTPHeaderField: "Accept-Language")
request.setValue("gzip, deflate, br", forHTTPHeaderField: "Accept-Encoding")
request.setValue("cors", forHTTPHeaderField: "Sec-Fetch-Mode")
request.setValue("beach-padel.app.fft.fr", forHTTPHeaderField: "Host")
request.setValue("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.6 Safari/605.1.15", forHTTPHeaderField: "User-Agent")
request.setValue("keep-alive", forHTTPHeaderField: "Connection")
request.setValue("https://beach-padel.app.fft.fr/beachja/competitionFiche/inscrireEquipe?identifiantHomologation=82477107", forHTTPHeaderField: "Referer")
request.setValue("XMLHttpRequest", forHTTPHeaderField: "X-Requested-With")
// Add cookies if needed (example cookie header value shown, replace with valid cookies)
request.setValue("JSESSIONID=F4ED2A1BCF3CD2694FE0B111B8027999; AWSALB=JoZEC/+cnAzmCdbbm3Vuc4CtMGx8BvbveFx+RBRuj8dQCQD52C9iDDbL/OVm98uMb7vc8Jv6/bVPkaByXWmOZmSGwAsN2s8/jt6W5L8QGz7omzNbYF01kvqffRvo; AWSALBCORS=JoZEC/+cnAzmCdbbm3Vuc4CtMGx8BvbveFx+RBRuj8dQCQD52C9iDDbL/OVm98uMb7vc8Jv6/bVPkaByXWmOZmSGwAsN2s8/jt6W5L8QGz7omzNbYF01kvqffRvo; datadome=KlbIdnrCgaY1zLVIZ5CfLJm~KXv9_YnXGhaQdqMEn6Ja9R6imBH~vhzmyuiLxGi1D0z90v5x2EiGDvQ7zsw~fajWLbOupFEajulc86PSJ7RIHpOiduCQ~cNoITQYJOXa; tc_cj_v2=m_iZZZ%22**%22%27%20ZZZKQLNQOPLOSLJOZZZ%5D777%5Ecl_%5Dny%5B%5D%5D_mmZZZZZZKQLQJRKOQKSMOZZZ%5D777m_iZZZ%22**%22%27%20ZZZKQLQJRKOQMSLNZZZ%5D777%5Ecl_%5Dny%5B%5D%5D_mmZZZZZZKQLQJRKOQNSJMZZZ%5D777m_iZZZ%22**%22%27%20ZZZKQLQJRKOSJMLJZZZ%5D777%5Ecl_%5Dny%5B%5D%5D_mmZZZZZZKQLRPQMQQNRQRZZZ%5D777m_iZZZ%22**%22%27%20ZZZKQLRPQNKSLOMSZZZ%5D777%5Ecl_%5Dny%5B%5D%5D_mmZZZZZZKQLSNSOPMSOPJZZZ%5D777m_iZZZ%22**%22%27%20ZZZKQMJQSRLJSOOJZZZ%5D777%5Ecl_%5Dny%5B%5D%5D_mmZZZZZZKQMJRJPJMSSKRZZZ%5D; tc_cj_v2_cmp=; tc_cj_v2_med=; tCdebugLib=1; incap_ses_2222_2712217=ui9wOOAjNziUTlU3gCHWHtv/KWcAAAAAhSzbpyITRp7YwRT3vJB2vg==; incap_ses_2224_2712217=NepDAr2kUDShMiCJaDzdHqbjKWcAAAAA0kLlk3lgvGnwWSTMceZoEw==; xtan=-; xtant=1; incap_ses_1350_2712217=g+XhSJRwOS8JlWTYCSq8EtOBJGcAAAAAffg2IobkPUW2BtvgJGHbMw==; TCSESSION=124101910177775608913; nlbi_2712217=jnhtOC5KDiLvfpy/b9lUTgAAAAA7zduh8JyZOVrEfGsEdFlq; TCID=12481811494814553052; xtvrn=$548419$; TCPID=12471746148351334672; visid_incap_2712217=PSfJngzoSuiowsuXXhvOu5K+7mUAAAAAQUIPAAAAAAAleL9ldvN/FC1VykkU9ret; SessionStatId=10.91.140.42.1662124965429001", forHTTPHeaderField: "Cookie")
let (data, _) = try await URLSession.shared.data(for: request)
let decoder = JSONDecoder()
// Debug: Print raw JSON data for inspection
if let jsonString = String(data: data, encoding: .utf8) {
print("Raw JSON response: \(jsonString)")
}
// Decode the response
let response = try decoder.decode(Response.self, from: data)
let players = response.object.listeJoueurs
// Cast the JSON object to [String: Any] dictionary
return players
}
// Function to fetch data for multiple license IDs using TaskGroup
func fetchPlayersDataSequentially(for licenseIDs: inout [FederalPlayer]) async {
for licenseID in licenseIDs.filter({ $0.firstName.isEmpty && $0.lastName.isEmpty }) {
do {
if let playerData = try await fetchPlayerData(for: licenseID.license)?.first {
licenseID.lastName = playerData.nom
licenseID.firstName = playerData.prenom
}
} catch {
print(error)
}
}
}
struct Player: Codable {
let licence: Int
let nom: String
let prenom: String
let sexe: String
}
struct Response: Codable {
let object: PlayerList
}
struct PlayerList: Codable {
let listeJoueurs: [Player]
}

@ -86,7 +86,7 @@ struct RoundSettingsView: View {
if previewAvailable {
NavigationLink {
PreviewBracketPositionView(seeds: tournament.seeds(), drawLogs: tournament.drawLogs())
PreviewBracketPositionView(seeds: tournament.seeds(), drawLogs: tournament.drawLogs().filter({ $0.drawType == .seed }))
} label: {
Text("Aperçu du repositionnement")
}

@ -76,6 +76,10 @@ struct TournamentCellView: View {
// .frame(width: 2)
VStack(alignment: .leading, spacing: 0.0) {
if let tournament = tournament as? Tournament {
#if targetEnvironment(simulator)
Text(tournament.id)
#endif
HStack {
Text(tournament.locationLabel(displayStyle))
.lineLimit(1)

@ -378,7 +378,7 @@ final class ServerDataTests: XCTestCase {
return
}
let drawLog = DrawLog(tournament: tournamentId, drawSeed: 1, drawMatchIndex: 1, drawTeamPosition: .two)
let drawLog = DrawLog(tournament: tournamentId, drawSeed: 1, drawMatchIndex: 1, drawTeamPosition: .two, drawType: .court)
let d: DrawLog = try await StoreCenter.main.service().post(drawLog)
assert(d.tournament == drawLog.tournament)
@ -386,6 +386,7 @@ final class ServerDataTests: XCTestCase {
assert(d.drawSeed == drawLog.drawSeed)
assert(d.drawTeamPosition == drawLog.drawTeamPosition)
assert(d.drawMatchIndex == drawLog.drawMatchIndex)
assert(d.drawType == drawLog.drawType)
}
}

Loading…
Cancel
Save