From 45c3d252995904319efd4af4447c44eca0e8eceb Mon Sep 17 00:00:00 2001 From: Laurent Date: Fri, 3 May 2024 10:36:55 +0200 Subject: [PATCH] Fix issues with crypting --- PadelClub/Data/Tournament.swift | 386 ++++++++++++------ PadelClub/Views/Subscription/Guard.swift | 6 +- .../Components/TournamentStatusView.swift | 6 +- .../Views/Tournament/TournamentView.swift | 2 +- 4 files changed, 270 insertions(+), 130 deletions(-) diff --git a/PadelClub/Data/Tournament.swift b/PadelClub/Data/Tournament.swift index fdcffe6..d70ae9c 100644 --- a/PadelClub/Data/Tournament.swift +++ b/PadelClub/Data/Tournament.swift @@ -41,14 +41,50 @@ class Tournament : ModelObject, Storable { var qualifiedPerGroupStage: Int var teamsPerGroupStage: Int var entryFee: Double? - var payment: Data? = nil + var payment: TournamentPayment? = nil var additionalEstimationDuration: Int = 0 var isDeleted: Bool = false - var isCanceled: Data? = nil + var isCanceled: Bool = false @ObservationIgnored var navigationPath: [Screen] = [] + enum CodingKeys: String, CodingKey { + case _id = "id" + case _event = "event" + case _creator = "creator" + case _name = "name" + case _startDate = "startDate" + case _endDate = "endDate" + case _creationDate = "creationDate" + case _isPrivate = "isPrivate" + case _groupStageFormat = "groupStageFormat" + case _roundFormat = "roundFormat" + case _loserRoundFormat = "loserRoundFormat" + case _groupStageSortMode = "groupStageSortMode" + case _groupStageCount = "groupStageCount" + case _rankSourceDate = "rankSourceDate" + case _dayDuration = "dayDuration" + case _teamCount = "teamCount" + case _teamSorting = "teamSorting" + case _federalCategory = "federalCategory" + case _federalLevelCategory = "federalLevelCategory" + case _federalAgeCategory = "federalAgeCategory" + case _groupStageCourtCount = "groupStageCourtCount" + case _seedCount = "seedCount" + case _closedRegistrationDate = "closedRegistrationDate" + case _groupStageAdditionalQualified = "groupStageAdditionalQualified" + case _courtCount = "courtCount" + case _prioritizeClubMembers = "prioritizeClubMembers" + case _qualifiedPerGroupStage = "qualifiedPerGroupStage" + case _teamsPerGroupStage = "teamsPerGroupStage" + case _entryFee = "entryFee" + case _additionalEstimationDuration = "additionalEstimationDuration" + case _isDeleted = "isDeleted" + case _isCanceled = "localId" + case _payment = "globalId" + } + internal init(event: String? = nil, creator: String? = nil, name: String? = nil, startDate: Date = Date(), endDate: Date? = nil, creationDate: Date = Date(), isPrivate: Bool = true, groupStageFormat: MatchFormat? = nil, roundFormat: MatchFormat? = nil, loserRoundFormat: MatchFormat? = nil, groupStageSortMode: GroupStageOrderingMode, groupStageCount: Int = 4, rankSourceDate: Date? = nil, dayDuration: Int = 1, teamCount: Int = 24, teamSorting: TeamSortingType? = nil, federalCategory: TournamentCategory, federalLevelCategory: TournamentLevel, federalAgeCategory: FederalTournamentAge, groupStageCourtCount: Int? = nil, seedCount: Int = 8, closedRegistrationDate: Date? = nil, groupStageAdditionalQualified: Int = 0, courtCount: Int = 2, prioritizeClubMembers: Bool = false, qualifiedPerGroupStage: Int = 1, teamsPerGroupStage: Int = 4, entryFee: Double? = nil) { self.event = event self.creator = creator @@ -80,6 +116,150 @@ class Tournament : ModelObject, Storable { self.entryFee = entryFee } + required init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + id = try container.decode(String.self, forKey: ._id) + event = try container.decodeIfPresent(String.self, forKey: ._event) + creator = try container.decodeIfPresent(String.self, forKey: ._creator) + name = try container.decodeIfPresent(String.self, forKey: ._name) + startDate = try container.decode(Date.self, forKey: ._startDate) + endDate = try container.decodeIfPresent(Date.self, forKey: ._endDate) + creationDate = try container.decode(Date.self, forKey: ._creationDate) + isPrivate = try container.decode(Bool.self, forKey: ._isPrivate) + groupStageFormat = try container.decodeIfPresent(MatchFormat.self, forKey: ._groupStageFormat) + roundFormat = try container.decodeIfPresent(MatchFormat.self, forKey: ._roundFormat) + loserRoundFormat = try container.decodeIfPresent(MatchFormat.self, forKey: ._loserRoundFormat) + groupStageSortMode = try container.decode(GroupStageOrderingMode.self, forKey: ._groupStageSortMode) + groupStageCount = try container.decode(Int.self, forKey: ._groupStageCount) + rankSourceDate = try container.decodeIfPresent(Date.self, forKey: ._rankSourceDate) + dayDuration = try container.decode(Int.self, forKey: ._dayDuration) + teamCount = try container.decode(Int.self, forKey: ._teamCount) + teamSorting = try container.decode(TeamSortingType.self, forKey: ._teamSorting) + federalCategory = try container.decode(TournamentCategory.self, forKey: ._federalCategory) + federalLevelCategory = try container.decode(TournamentLevel.self, forKey: ._federalLevelCategory) + federalAgeCategory = try container.decode(FederalTournamentAge.self, forKey: ._federalAgeCategory) + groupStageCourtCount = try container.decodeIfPresent(Int.self, forKey: ._groupStageCourtCount) + seedCount = try container.decode(Int.self, forKey: ._seedCount) + closedRegistrationDate = try container.decodeIfPresent(Date.self, forKey: ._closedRegistrationDate) + groupStageAdditionalQualified = try container.decode(Int.self, forKey: ._groupStageAdditionalQualified) + courtCount = try container.decode(Int.self, forKey: ._courtCount) + prioritizeClubMembers = try container.decode(Bool.self, forKey: ._prioritizeClubMembers) + qualifiedPerGroupStage = try container.decode(Int.self, forKey: ._qualifiedPerGroupStage) + teamsPerGroupStage = try container.decode(Int.self, forKey: ._teamsPerGroupStage) + entryFee = try container.decodeIfPresent(Double.self, forKey: ._entryFee) + payment = try Tournament._decodePayment(container: container) + additionalEstimationDuration = try container.decode(Int.self, forKey: ._additionalEstimationDuration) + isDeleted = try container.decode(Bool.self, forKey: ._isDeleted) + isCanceled = try Tournament._decodeCanceled(container: container) + } + + fileprivate static let _numberFormatter: NumberFormatter = NumberFormatter() + + fileprivate static func _decodePayment(container: KeyedDecodingContainer) throws -> TournamentPayment? { + let data = try container.decodeIfPresent(Data.self, forKey: ._payment) + + if let data { + do { + let decoded: String = try data.decryptData(pass: Key.pass.rawValue) + let sequence = decoded.compactMap { _numberFormatter.number(from: String($0))?.intValue } + return TournamentPayment(rawValue: sequence[18]) + } catch { + Logger.error(error) + } + } + return nil + } + + fileprivate static func _decodeCanceled(container: KeyedDecodingContainer) throws -> Bool { + let data = try container.decodeIfPresent(Data.self, forKey: ._isCanceled) + if let data { + do { + let decoded: String = try data.decryptData(pass: Key.pass.rawValue) + let sequence = decoded.compactMap { _numberFormatter.number(from: String($0))?.intValue } + return Bool.decodeInt(sequence[18]) + } catch { + Logger.error(error) + } + } + return false + } + + func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + + try container.encode(id, forKey: ._id) + try container.encodeIfPresent(event, forKey: ._event) + try container.encodeIfPresent(creator, forKey: ._creator) + try container.encodeIfPresent(name, forKey: ._name) + try container.encode(startDate, forKey: ._startDate) + try container.encodeIfPresent(endDate, forKey: ._endDate) + try container.encode(creationDate, forKey: ._creationDate) + try container.encode(isPrivate, forKey: ._isPrivate) + try container.encodeIfPresent(groupStageFormat, forKey: ._groupStageFormat) + try container.encodeIfPresent(roundFormat, forKey: ._roundFormat) + try container.encodeIfPresent(loserRoundFormat, forKey: ._loserRoundFormat) + try container.encode(groupStageSortMode, forKey: ._groupStageSortMode) + try container.encode(groupStageCount, forKey: ._groupStageCount) + try container.encodeIfPresent(rankSourceDate, forKey: ._rankSourceDate) + try container.encode(dayDuration, forKey: ._dayDuration) + try container.encode(teamCount, forKey: ._teamCount) + try container.encode(teamSorting, forKey: ._teamSorting) + try container.encode(federalCategory, forKey: ._federalCategory) + try container.encode(federalLevelCategory, forKey: ._federalLevelCategory) + try container.encode(federalAgeCategory, forKey: ._federalAgeCategory) + try container.encodeIfPresent(groupStageCourtCount, forKey: ._groupStageCourtCount) + try container.encode(seedCount, forKey: ._seedCount) + try container.encodeIfPresent(closedRegistrationDate, forKey: ._closedRegistrationDate) + try container.encode(groupStageAdditionalQualified, forKey: ._groupStageAdditionalQualified) + try container.encode(courtCount, forKey: ._courtCount) + try container.encode(prioritizeClubMembers, forKey: ._prioritizeClubMembers) + try container.encode(qualifiedPerGroupStage, forKey: ._qualifiedPerGroupStage) + try container.encode(teamsPerGroupStage, forKey: ._teamsPerGroupStage) + try container.encodeIfPresent(entryFee, forKey: ._entryFee) + try self._encodePayment(container: &container) + try container.encode(additionalEstimationDuration, forKey: ._additionalEstimationDuration) + try container.encode(isDeleted, forKey: ._isDeleted) + try self._encodeIsCanceled(container: &container) + + } + + fileprivate func _encodePayment(container: inout KeyedEncodingContainer) throws { + + guard let payment else { + try container.encodeNil(forKey: ._payment) + return + } + + let max: Int = TournamentPayment.allCases.count + var sequence = (1...18).map { _ in Int.random(in: (0..) throws { + + let max: Int = 9 + var sequence = (1...18).map { _ in Int.random(in: (0.. Tournament.State { -// if currentCanceled == true { -// return .canceled -// } + if self.isCanceled == true { + return .canceled + } if (groupStageCount > 0 && groupStages().isEmpty == false) || rounds().isEmpty == false { return .build @@ -1150,96 +1330,94 @@ class Tournament : ModelObject, Storable { fileprivate var _currentPayment: TournamentPayment? = nil fileprivate var _currentCanceled: Bool? = nil - fileprivate let _numberFormatter: NumberFormatter = NumberFormatter() - - func setPayment(_ payment: TournamentPayment) { - - let max: Int = TournamentPayment.allCases.count - self._currentPayment = payment - var sequence = (1...18).map { _ in Int.random(in: (0.. TournamentPayment? { - if let payment { - do { - let decoded: String = try payment.decryptData(pass: Key.pass.rawValue) - let sequence = decoded.compactMap { _numberFormatter.number(from: String($0))?.intValue } - return TournamentPayment(rawValue: sequence[18]) - } catch { - Logger.error(error) - } - } - return nil - } - func setCanceled(_ canceled: Bool) { - - let max: Int = 9 - self._currentCanceled = canceled - var sequence = (1...18).map { _ in Int.random(in: (0.. TournamentPayment? { +// if let payment { +// do { +// let decoded: String = try payment.decryptData(pass: Key.pass.rawValue) +// let sequence = decoded.compactMap { _numberFormatter.number(from: String($0))?.intValue } +// return TournamentPayment(rawValue: sequence[18]) +// } catch { +// Logger.error(error) +// } +// } +// return nil +// } + +// func setCanceled(_ canceled: Bool) { +// +// let max: Int = 9 +// self._currentCanceled = canceled +// var sequence = (1...18).map { _ in Int.random(in: (0.. Bool? { - if let isCanceled { - do { - let decoded: String = try isCanceled.decryptData(pass: Key.pass.rawValue) - let sequence = decoded.compactMap { _numberFormatter.number(from: String($0))?.intValue } - return Bool.decodeInt(sequence[18]) - } catch { - Logger.error(error) - } - } - return nil - } +// var currentCanceled: Bool? { +// if let current = self._currentCanceled { +// return current +// } +// self._currentCanceled = self.decryptCanceled() +// return self._currentCanceled +// } + +// func decryptCanceled() -> Bool? { +// if let isCanceled { +// do { +// let decoded: String = try isCanceled.decryptData(pass: Key.pass.rawValue) +// let sequence = decoded.compactMap { _numberFormatter.number(from: String($0))?.intValue } +// return Bool.decodeInt(sequence[18]) +// } catch { +// Logger.error(error) +// } +// } +// return nil +// } enum PaymentError: Error { case cantPayTournament } func payIfNecessary() throws { - if self.currentPayment != nil { return } if let payment = Guard.main.paymentForNewTournament() { - self.setPayment(payment) + self.payment = payment try DataStore.shared.tournaments.addOrUpdate(instance: self) return } @@ -1267,44 +1445,6 @@ fileprivate extension Bool { } } -extension Tournament { - enum CodingKeys: String, CodingKey { - case _id = "id" - case _event = "event" - case _creator = "creator" - case _name = "name" - case _startDate = "startDate" - case _endDate = "endDate" - case _creationDate = "creationDate" - case _isPrivate = "isPrivate" - case _groupStageFormat = "groupStageFormat" - case _roundFormat = "roundFormat" - case _loserRoundFormat = "loserRoundFormat" - case _groupStageSortMode = "groupStageSortMode" - case _groupStageCount = "groupStageCount" - case _rankSourceDate = "rankSourceDate" - case _dayDuration = "dayDuration" - case _teamCount = "teamCount" - case _teamSorting = "teamSorting" - case _federalCategory = "federalCategory" - case _federalLevelCategory = "federalLevelCategory" - case _federalAgeCategory = "federalAgeCategory" - case _groupStageCourtCount = "groupStageCourtCount" - case _seedCount = "seedCount" - case _closedRegistrationDate = "closedRegistrationDate" - case _groupStageAdditionalQualified = "groupStageAdditionalQualified" - case _courtCount = "courtCount" - case _prioritizeClubMembers = "prioritizeClubMembers" - case _qualifiedPerGroupStage = "qualifiedPerGroupStage" - case _teamsPerGroupStage = "teamsPerGroupStage" - case _entryFee = "entryFee" - case _additionalEstimationDuration = "additionalEstimationDuration" - case _isDeleted = "isDeleted" - case _isCanceled = "localId" - case _payment = "globalId" - } -} - extension Tournament: Hashable { static func == (lhs: Tournament, rhs: Tournament) -> Bool { lhs.id == rhs.id diff --git a/PadelClub/Views/Subscription/Guard.swift b/PadelClub/Views/Subscription/Guard.swift index 1950f4d..cd3ad60 100644 --- a/PadelClub/Views/Subscription/Guard.swift +++ b/PadelClub/Views/Subscription/Guard.swift @@ -178,7 +178,7 @@ import LeStorage return Tournament.TournamentPayment.unlimited case .fivePerMonth: if let purchaseDate = self.currentBestPlan?.originalPurchaseDate { - let tournaments = DataStore.shared.tournaments.filter { $0.creationDate > purchaseDate && $0.currentCanceled == false } + let tournaments = DataStore.shared.tournaments.filter { $0.creationDate > purchaseDate && $0.isCanceled == false } if tournaments.count < StoreItem.five { return Tournament.TournamentPayment.subscriptionUnit } @@ -187,7 +187,7 @@ import LeStorage default: // let subscriptionPayed = DataStore.shared.tournaments.filter { $0.payment?.isSubscription == true } - let unitlyPayed = DataStore.shared.tournaments.filter { $0.currentPayment == .unit && $0.currentCanceled == false }.count + let unitlyPayed = DataStore.shared.tournaments.filter { $0.payment == .unit && $0.isCanceled == false }.count if unitlyPayed == 0 { return Tournament.TournamentPayment.free } @@ -201,7 +201,7 @@ import LeStorage } var remainingTournaments: Int { - let unitlyPayed = DataStore.shared.tournaments.filter { $0.currentPayment == Tournament.TournamentPayment.unit }.count + let unitlyPayed = DataStore.shared.tournaments.filter { $0.payment == Tournament.TournamentPayment.unit }.count let tournamentCreditCount = self._purchasedTournamentCount() Logger.log("total count = \(DataStore.shared.tournaments.count), unitlyPayed = \(unitlyPayed), purchased = \(tournamentCreditCount) ") return tournamentCreditCount - unitlyPayed diff --git a/PadelClub/Views/Tournament/Screen/Components/TournamentStatusView.swift b/PadelClub/Views/Tournament/Screen/Components/TournamentStatusView.swift index 20e9bdc..2c89d0d 100644 --- a/PadelClub/Views/Tournament/Screen/Components/TournamentStatusView.swift +++ b/PadelClub/Views/Tournament/Screen/Components/TournamentStatusView.swift @@ -38,7 +38,7 @@ struct TournamentStatusView: View { Section { RowButtonView("Supprimer le tournoi", role: .destructive) { - if tournament.currentPayment == nil { + if tournament.payment == nil { do { try dataStore.tournaments.delete(instance: tournament) } catch { @@ -55,10 +55,10 @@ struct TournamentStatusView: View { Text("todo: expliquer ce que ca fait") } - if tournament.hasEnded() == false && tournament.currentCanceled == false { + if tournament.hasEnded() == false && tournament.isCanceled == false { Section { RowButtonView("Annuler le tournoi", role: .destructive) { - tournament.setCanceled(true) + tournament.isCanceled = true dismiss() } } footer: { diff --git a/PadelClub/Views/Tournament/TournamentView.swift b/PadelClub/Views/Tournament/TournamentView.swift index ff7b32c..273fe63 100644 --- a/PadelClub/Views/Tournament/TournamentView.swift +++ b/PadelClub/Views/Tournament/TournamentView.swift @@ -64,7 +64,7 @@ struct TournamentView: View { case .canceled: Section { RowButtonView("Reprendre le tournoi", role: .destructive) { - tournament.setCanceled(false) + tournament.isCanceled = false _save() } } footer: {