handle inscription list updates

multistore
Razmig Sarkissian 2 years ago
parent c31062fc70
commit 9cf95398f8
  1. 6051
      PadelClub/CSV/CLASSEMENT PADEL DAMES-07-2023.csv
  2. 6219
      PadelClub/CSV/CLASSEMENT PADEL DAMES-08-2023.csv
  3. 13166
      PadelClub/CSV/CLASSEMENT PADEL MESSIEURS_1-07-2023.csv
  4. 13166
      PadelClub/CSV/CLASSEMENT PADEL MESSIEURS_1-08-2023.csv
  5. 13888
      PadelClub/CSV/CLASSEMENT PADEL MESSIEURS_2-07-2023.csv
  6. 13889
      PadelClub/CSV/CLASSEMENT PADEL MESSIEURS_2-08-2023.csv
  7. 11668
      PadelClub/CSV/CLASSEMENT PADEL MESSIEURS_3-07-2023.csv
  8. 13193
      PadelClub/CSV/CLASSEMENT PADEL MESSIEURS_3-08-2023.csv
  9. 4421
      PadelClub/CSV/CLASSEMENT-PADEL-DAMES-01-2023.csv
  10. 4636
      PadelClub/CSV/CLASSEMENT-PADEL-DAMES-02-2023.csv
  11. 4903
      PadelClub/CSV/CLASSEMENT-PADEL-DAMES-03-2023.csv
  12. 5163
      PadelClub/CSV/CLASSEMENT-PADEL-DAMES-04-2023.csv
  13. 5496
      PadelClub/CSV/CLASSEMENT-PADEL-DAMES-05-2023.csv
  14. 5800
      PadelClub/CSV/CLASSEMENT-PADEL-DAMES-06-2023.csv
  15. 3521
      PadelClub/CSV/CLASSEMENT-PADEL-DAMES-08-2022.csv
  16. 3582
      PadelClub/CSV/CLASSEMENT-PADEL-DAMES-09-2022.csv
  17. 3709
      PadelClub/CSV/CLASSEMENT-PADEL-DAMES-10-2022.csv
  18. 3961
      PadelClub/CSV/CLASSEMENT-PADEL-DAMES-11-2022.csv
  19. 4219
      PadelClub/CSV/CLASSEMENT-PADEL-DAMES-12-2022.csv
  20. 13500
      PadelClub/CSV/CLASSEMENT-PADEL-MESSIEURS-01-2023.csv
  21. 14730
      PadelClub/CSV/CLASSEMENT-PADEL-MESSIEURS-02-2023.csv
  22. 16589
      PadelClub/CSV/CLASSEMENT-PADEL-MESSIEURS-03-2023.csv
  23. 13264
      PadelClub/CSV/CLASSEMENT-PADEL-MESSIEURS-04-2023.csv
  24. 13264
      PadelClub/CSV/CLASSEMENT-PADEL-MESSIEURS-05-2023.csv
  25. 13167
      PadelClub/CSV/CLASSEMENT-PADEL-MESSIEURS-06-2023.csv
  26. 21347
      PadelClub/CSV/CLASSEMENT-PADEL-MESSIEURS-08-2022.csv
  27. 12275
      PadelClub/CSV/CLASSEMENT-PADEL-MESSIEURS-09-2022.csv
  28. 12270
      PadelClub/CSV/CLASSEMENT-PADEL-MESSIEURS-10-2022.csv
  29. 12270
      PadelClub/CSV/CLASSEMENT-PADEL-MESSIEURS-11-2022.csv
  30. 12270
      PadelClub/CSV/CLASSEMENT-PADEL-MESSIEURS-12-2022.csv
  31. 14819
      PadelClub/CSV/CLASSEMENT-PADEL-MESSIEURS-2-01-2023.csv
  32. 15074
      PadelClub/CSV/CLASSEMENT-PADEL-MESSIEURS-2-02-2023.csv
  33. 14771
      PadelClub/CSV/CLASSEMENT-PADEL-MESSIEURS-2-03-2023.csv
  34. 19650
      PadelClub/CSV/CLASSEMENT-PADEL-MESSIEURS-2-04-2023.csv
  35. 13264
      PadelClub/CSV/CLASSEMENT-PADEL-MESSIEURS-2-05-2023.csv
  36. 13888
      PadelClub/CSV/CLASSEMENT-PADEL-MESSIEURS-2-06-2023.csv
  37. 9677
      PadelClub/CSV/CLASSEMENT-PADEL-MESSIEURS-2-09-2022.csv
  38. 11122
      PadelClub/CSV/CLASSEMENT-PADEL-MESSIEURS-2-10-2022.csv
  39. 13050
      PadelClub/CSV/CLASSEMENT-PADEL-MESSIEURS-2-11-2022.csv
  40. 14673
      PadelClub/CSV/CLASSEMENT-PADEL-MESSIEURS-2-12-2022.csv
  41. 7774
      PadelClub/CSV/CLASSEMENT-PADEL-MESSIEURS-3-05-2023.csv
  42. 9844
      PadelClub/CSV/CLASSEMENT-PADEL-MESSIEURS-3-06-2023.csv
  43. 224
      PadelClub/Manager/CloudConvert.swift
  44. 160
      PadelClub/Manager/SwiftParser.swift
  45. 18
      PadelClub/Views/Tournament/FileImportView.swift
  46. 18
      PadelClub/Views/Tournament/Screen/Components/UpdateSourceRankDateView.swift

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,224 @@
//
// CloudConvert.swift
// Padel Tournament
//
// Created by Razmig Sarkissian on 14/09/2023.
//
import Foundation
class CloudConvert {
enum CloudConvertionError: LocalizedError {
case unknownError
case serviceError(ErrorResponse)
case urlNotFound(String)
var errorDescription: String? {
switch self {
case .unknownError:
return "Erreur"
case .serviceError(let errorResponse):
return errorResponse.error
case .urlNotFound(let url):
return "L'URL [\(url)] n'est pas valide"
}
}
}
static let manager = CloudConvert()
func uploadFile(_ url: URL) async throws -> String {
let taskResponse = try await createJob(url)
let uploadResponse = try await uploadFile(taskResponse, url: url)
var fileReady = false
while fileReady == false {
try await Task.sleep(nanoseconds: 3_000_000_000)
let progressResponse = try await checkFile(id: uploadResponse.data.id)
if progressResponse.data.step == "finish" && progressResponse.data.stepPercent == 100 {
fileReady = true
print("progressResponse.data.minutes", progressResponse.data.minutes)
}
}
let convertedFile = try await downloadConvertedFile(id: uploadResponse.data.id)
return convertedFile
}
func createJob(_ url: URL) async throws -> TaskResponse {
guard let taskURL = URL(string: "https://api.convertio.co/convert") else {
throw CloudConvertionError.urlNotFound("https://api.convertio.co/convert")
}
var request: URLRequest = URLRequest(url: taskURL)
let parameters = """
{"apikey":"d97cf13ef6d163e5e386c381fc8d256f","input":"upload","file":"","filename":"","outputformat":"csv","options":""}
"""
let postData = parameters.data(using: .utf8)
request.httpMethod = "POST"
request.httpBody = postData
let task = try await URLSession.shared.data(for: request)
print("tried: \(request.url)")
if let errorResponse = try? JSONDecoder().decode(ErrorResponse.self, from: task.0) {
print("errorResponse.error", errorResponse.error)
throw CloudConvertionError.serviceError(errorResponse)
}
return try JSONDecoder().decode(TaskResponse.self, from: task.0)
}
func uploadFile(_ response: TaskResponse, url: URL) async throws -> UploadResponse {
guard let uploadTaskURL = URL(string: "https://api.convertio.co/convert/\(response.data.id)/\(url.encodedLastPathComponent)") else {
throw CloudConvertionError.urlNotFound("https://api.convertio.co/convert/\(response.data.id)/\(url.encodedLastPathComponent)")
}
var uploadRequest: URLRequest = URLRequest(url: uploadTaskURL)
uploadRequest.httpMethod = "PUT"
let uploadTask = try await URLSession.shared.upload(for: uploadRequest, fromFile: url)
print("tried: \(uploadRequest.url)")
if let errorResponse = try? JSONDecoder().decode(ErrorResponse.self, from: uploadTask.0) {
print("errorResponse.error", errorResponse.error)
throw CloudConvertionError.serviceError(errorResponse)
}
return try JSONDecoder().decode(UploadResponse.self, from: uploadTask.0)
}
func checkFile(id: String) async throws -> ProgressResponse {
guard let taskURL = URL(string: "https://api.convertio.co/convert/\(id)/status") else {
throw CloudConvertionError.urlNotFound("https://api.convertio.co/convert/\(id)/status")
}
var request: URLRequest = URLRequest(url: taskURL)
request.httpMethod = "GET"
let task = try await URLSession.shared.data(for: request)
print("tried: \(request.url)")
if let errorResponse = try? JSONDecoder().decode(ErrorResponse.self, from: task.0) {
print("errorResponse.error", errorResponse.error)
throw CloudConvertionError.serviceError(errorResponse)
}
return try JSONDecoder().decode(ProgressResponse.self, from: task.0)
}
func downloadConvertedFile(id: String) async throws -> String {
// try await Task.sleep(nanoseconds: 3_000_000_000)
guard let downloadTaskURL = URL(string: "https://api.convertio.co/convert/\(id)/dl/base64") else {
throw CloudConvertionError.urlNotFound("https://api.convertio.co/convert/\(id)/dl/base64")
}
var downloadRequest: URLRequest = URLRequest(url: downloadTaskURL)
downloadRequest.httpMethod = "GET"
let downloadTask = try await URLSession.shared.data(for: downloadRequest)
if let errorResponse = try? JSONDecoder().decode(ErrorResponse.self, from: downloadTask.0) {
print("errorResponse.error", errorResponse.error)
throw CloudConvertionError.serviceError(errorResponse)
}
print("tried: \(downloadRequest.url)")
let dataResponse = try JSONDecoder().decode(DataResponse.self, from: downloadTask.0)
if let decodedData = Data(base64Encoded: dataResponse.data.content), let string = String(data: decodedData, encoding: .utf8) {
return string
}
throw CloudConvertionError.unknownError
}
}
// MARK: - DataResponse
struct DataResponse: Decodable {
let code: Int
let status: String
let data: DataDownloadClass
}
// MARK: - DataClass
struct DataDownloadClass: Decodable {
let id, encode, content: String
}
// MARK: - ErrorResponse
struct ErrorResponse: Decodable {
let code: Int
let status, error: String
}
// MARK: - TaskResponse
struct TaskResponse: Decodable {
let code: Int
let status: String
let data: DataClass
}
// MARK: - DataClass
struct DataClass: Decodable {
let id: String
}
// MARK: - ProgressResponse
struct ProgressResponse: Decodable {
let code: Int
let status: String
let data: ProgressDataClass
}
// MARK: - DataClass
struct ProgressDataClass: Decodable {
let id, step: String
let stepPercent: Int
let minutes: String
enum CodingKeys: String, CodingKey {
case id, step
case stepPercent = "step_percent"
case minutes
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(String.self, forKey: .id)
step = try container.decode(String.self, forKey: .step)
minutes = try container.decode(String.self, forKey: .minutes)
if let value = try? container.decode(String.self, forKey: .stepPercent) {
print(value)
stepPercent = Int(value) ?? 0
} else {
stepPercent = try container.decode(Int.self, forKey: .stepPercent)
}
}
}
// MARK: - Output
struct Output: Decodable {
let url: String
let size: String
}
// MARK: - UploadResponse
struct UploadResponse: Decodable {
let code: Int
let status: String
let data: UploadDataClass
}
// MARK: - DataClass
struct UploadDataClass: Decodable {
let id, file: String
let size: Int
}
extension URL {
var encodedLastPathComponent: String {
if #available(iOS 17.0, *) {
lastPathComponent
} else {
lastPathComponent.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? lastPathComponent
}
}
}

@ -0,0 +1,160 @@
//
// SwiftParser.swift
// Padel Tournament
//
// Created by Razmig Sarkissian on 01/09/2023.
//
import Foundation
typealias LineIterator = AsyncLineSequence<URL.AsyncBytes>.AsyncIterator
struct Line: Identifiable {
let id: UUID = UUID()
let date: Date
let source: URL
let lineNumber: Int
let rawValue: String
let data: [String?]
func updatePlayer(player: Player) {
player.clubName = data[11]
player.ligue = data[9]
player.country = data[4]
player.license = data[5]
player.inscriptionRank = rank
player.currentRank = rank
player.tournamentCount = Int16(tournamentCount)
player.points = points ?? 0
player.codeClub = data[10]
player.assimilation = assimilation
}
var points: Double? {
if let pointsValue {
return Double(pointsValue.replacingOccurrences(of: ",", with: "."))
}
return nil
}
var pointsValue: String? {
data[6] ?? nil
}
var tournamentCountValue: String? {
data[8] ?? nil
}
var tournamentCount: Int64 {
if let tournamentCountValue {
return Int64(tournamentCountValue) ?? 0
}
return 0
}
var rankValue: String? {
data[1] ?? nil
}
var rank: Int64 {
if let rankValue {
return Int64(rankValue) ?? 0
}
return 0
}
var assimilation: String? {
data[7]
}
}
struct CSVParser: AsyncSequence, AsyncIteratorProtocol {
typealias Element = Line
private let url: URL
private var lineIterator: LineIterator
private let seperator: Character
private let quoteCharacter: Character = "\""
private var lineNumber = 0
private let date: Date
let maleData: Bool
init(url: URL, seperator: Character = ";") {
self.date = url.dateFromPath
self.url = url
self.seperator = seperator
self.lineIterator = url.lines.makeAsyncIterator()
self.maleData = url.path().contains(PDFSource.messieurs.rawValue)
}
mutating func last() async throws -> Line? {
var lastString: String?
var currentString: String?
var isOver: Bool = false
while isOver == false {
lastString = currentString
currentString = try await lineIterator.next()
if currentString == nil {
isOver = true
}
}
if let lastString {
return Line(
date: date,
source: url,
lineNumber: lineNumber,
rawValue: lastString,
data: split(line: lastString))
}
return nil
}
mutating func next() async throws -> Line? {
if let string = try await lineIterator.next() {
defer { lineNumber += 1 }
return Line(
date: date,
source: url,
lineNumber: lineNumber,
rawValue: string,
data: split(line: string)
)
}
return nil
}
func makeAsyncIterator() -> CSVParser {
return self
}
private func split(line: String) -> [String?] {
var data = [String?]()
var inQuote = false
var currentString = ""
for character in line {
switch character {
case quoteCharacter:
inQuote = !inQuote
continue
case seperator:
if !inQuote {
data.append(currentString.isEmpty ? nil : currentString)
currentString = ""
continue
}
default:
break
}
currentString.append(character)
}
data.append(currentString.isEmpty ? nil : currentString)
return data
}
}

@ -0,0 +1,18 @@
//
// FileImportView.swift
// PadelClub
//
// Created by Razmig Sarkissian on 24/03/2024.
//
import SwiftUI
struct FileImportView: View {
var body: some View {
Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
}
}
#Preview {
FileImportView()
}

@ -0,0 +1,18 @@
//
// UpdateSourceRankDateView.swift
// PadelClub
//
// Created by Razmig Sarkissian on 25/03/2024.
//
import SwiftUI
struct UpdateSourceRankDateView: View {
var body: some View {
Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
}
}
#Preview {
UpdateSourceRankDateView()
}
Loading…
Cancel
Save