fix more stuff

multistore
Razmig Sarkissian 2 years ago
parent 4253ba2c31
commit 860eab9b76
  1. 2
      PadelClub/Data/GroupStage.swift
  2. 9
      PadelClub/Data/Match.swift
  3. 30
      PadelClub/Data/MatchScheduler.swift
  4. 6
      PadelClub/Data/Round.swift
  5. 65
      PadelClub/Data/Tournament.swift
  6. 2
      PadelClub/Utils/URLs.swift
  7. 42
      PadelClub/Views/Club/ClubDetailView.swift
  8. 1
      PadelClub/Views/Club/CourtView.swift
  9. 21
      PadelClub/Views/Planning/PlanningSettingsView.swift
  10. 2
      PadelClub/Views/Round/RoundSettingsView.swift
  11. 28
      PadelClub/Views/Round/RoundView.swift
  12. 132
      PadelClub/Views/Tournament/Screen/BroadcastView.swift
  13. 8
      PadelClubTests/ServerDataTests.swift

@ -79,7 +79,7 @@ class GroupStage: ModelObject, Storable {
var _matches = [Match]()
for i in 0..<_numberOfMatchesToBuild() {
let newMatch = Match(groupStage: id, index: i, matchFormat: matchFormat)
let newMatch = Match(groupStage: id, index: i, matchFormat: matchFormat, name: localizedMatchUpLabel(for: i))
_matches.append(newMatch)
}

@ -12,7 +12,12 @@ import LeStorage
class Match: ModelObject, Storable {
static func resourceName() -> String { "matches" }
static func tokenExemptedMethods() -> [HTTPMethod] { return [] }
static func setServerTitle(upperRound: Round, matchIndex: Int) -> String {
if upperRound.index == 0 { return upperRound.roundTitle() }
return upperRound.roundTitle() + " #" + (matchIndex + 1).formatted()
}
var byeState: Bool = false
var id: String = Store.randomId()
@ -27,7 +32,7 @@ class Match: ModelObject, Storable {
var winningTeamId: String?
var losingTeamId: String?
//var broadcasted: Bool
private var name: String?
var name: String?
//var order: Int
var disabled: Bool = false
private(set) var courtIndex: Int?

@ -88,7 +88,35 @@ class MatchScheduler : ModelObject, Storable {
})
var lastDate : Date = tournament.startDate
groupStages.chunked(into: groupStageCourtCount).forEach { groups in
let times = Set(groupStages.compactMap { $0.startDate }).sorted()
if let first = times.first {
if first.isEarlierThan(tournament.startDate) {
tournament.startDate = first
try? DataStore.shared.tournaments.addOrUpdate(instance: tournament)
}
}
times.forEach({ time in
lastDate = time
let groups = groupStages.filter({ $0.startDate == time })
let dispatch = groupStageDispatcher(numberOfCourtsAvailablePerRotation: numberOfCourtsAvailablePerRotation, groupStages: groups, startingDate: lastDate)
dispatch.timedMatches.forEach { matchSchedule in
if let match = matches.first(where: { $0.id == matchSchedule.matchID }) {
let estimatedDuration = match.matchFormat.getEstimatedDuration(tournament.additionalEstimationDuration)
let timeIntervalToAdd = (Double(matchSchedule.rotationIndex)) * Double(estimatedDuration) * 60
if let startDate = match.groupStageObject?.startDate {
let matchStartDate = startDate.addingTimeInterval(timeIntervalToAdd)
match.startDate = matchStartDate
lastDate = matchStartDate.addingTimeInterval(Double(estimatedDuration) * 60)
}
match.setCourt(matchSchedule.courtIndex)
}
}
})
groupStages.filter({ $0.startDate == nil || times.contains($0.startDate!) == false }).chunked(into: groupStageCourtCount).forEach { groups in
groups.forEach({ $0.startDate = lastDate })
try? DataStore.shared.groupStages.addOrUpdate(contentOfs: groups)

@ -431,12 +431,8 @@ class Round: ModelObject, Storable {
let matches = (0..<matchCount).map { //0 is final match
let roundIndex = RoundRule.roundIndex(fromMatchIndex: $0)
let round = rounds[roundIndex]
return Match(round: round.id, index: $0, matchFormat: loserBracketMatchFormat)
return Match(round: round.id, index: $0, matchFormat: loserBracketMatchFormat, name: round.roundTitle())
}
print(matches.map {
(RoundRule.roundName(fromMatchIndex: $0.index), RoundRule.matchIndexWithinRound(fromMatchIndex: $0.index))
})
try? DataStore.shared.matches.addOrUpdate(contentOfs: matches)

@ -44,9 +44,8 @@ class Tournament : ModelObject, Storable {
var additionalEstimationDuration: Int = 0
var isDeleted: Bool = false
var isCanceled: Bool = false
var publishManually: Bool = false
var publishTeams: Bool = false
var publishWaitingList: Bool = false
//var publishWaitingList: Bool = false
var publishSummons: Bool = false
var publishGroupStages: Bool = false
var publishBrackets: Bool = false
@ -88,15 +87,14 @@ class Tournament : ModelObject, Storable {
case _isDeleted = "isDeleted"
case _isCanceled = "localId"
case _payment = "globalId"
case _publishManually = "publishManually"
case _publishTeams = "publishTeams"
case _publishWaitingList = "publishWaitingList"
//case _publishWaitingList = "publishWaitingList"
case _publishSummons = "publishSummons"
case _publishGroupStages = "publishGroupStages"
case _publishBrackets = "publishBrackets"
}
internal init(event: String? = nil, name: String? = nil, startDate: Date = Date(), endDate: Date? = nil, creationDate: Date = Date(), isPrivate: Bool = false, 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, closedRegistrationDate: Date? = nil, groupStageAdditionalQualified: Int = 0, courtCount: Int = 2, prioritizeClubMembers: Bool = false, qualifiedPerGroupStage: Int = 1, teamsPerGroupStage: Int = 4, entryFee: Double? = nil, additionalEstimationDuration: Int = 0, isDeleted: Bool = false, publishManually: Bool = false, publishTeams: Bool = false, publishWaitingList: Bool = false, publishSummons: Bool = false, publishGroupStages: Bool = false, publishBrackets: Bool = false) {
internal init(event: String? = nil, name: String? = nil, startDate: Date = Date(), endDate: Date? = nil, creationDate: Date = Date(), isPrivate: Bool = false, 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, closedRegistrationDate: Date? = nil, groupStageAdditionalQualified: Int = 0, courtCount: Int = 2, prioritizeClubMembers: Bool = false, qualifiedPerGroupStage: Int = 1, teamsPerGroupStage: Int = 4, entryFee: Double? = nil, additionalEstimationDuration: Int = 0, isDeleted: Bool = false, publishTeams: Bool = false, publishSummons: Bool = false, publishGroupStages: Bool = false, publishBrackets: Bool = false) {
self.event = event
self.name = name
self.startDate = startDate
@ -125,6 +123,10 @@ class Tournament : ModelObject, Storable {
self.entryFee = entryFee
self.additionalEstimationDuration = additionalEstimationDuration
self.isDeleted = isDeleted
self.publishTeams = publishTeams
self.publishSummons = publishSummons
self.publishBrackets = publishBrackets
self.publishGroupStages = publishGroupStages
}
required init(from decoder: Decoder) throws {
@ -160,9 +162,7 @@ class Tournament : ModelObject, Storable {
additionalEstimationDuration = try container.decode(Int.self, forKey: ._additionalEstimationDuration)
isDeleted = try container.decode(Bool.self, forKey: ._isDeleted)
isCanceled = try Tournament._decodeCanceled(container: container)
publishManually = try container.decodeIfPresent(Bool.self, forKey: ._publishManually) ?? false
publishTeams = try container.decodeIfPresent(Bool.self, forKey: ._publishTeams) ?? false
publishWaitingList = try container.decodeIfPresent(Bool.self, forKey: ._publishWaitingList) ?? false
publishSummons = try container.decodeIfPresent(Bool.self, forKey: ._publishSummons) ?? false
publishGroupStages = try container.decodeIfPresent(Bool.self, forKey: ._publishGroupStages) ?? false
publishBrackets = try container.decodeIfPresent(Bool.self, forKey: ._publishBrackets) ?? false
@ -295,6 +295,55 @@ class Tournament : ModelObject, Storable {
case canceled
}
func publishedTeamsDate() -> Date {
startDate
}
func areTeamsPublished() -> Bool {
Date() >= startDate
}
func publishedGroupStagesDate() -> Date? {
if let first = groupStages().flatMap({ $0.playedMatches() }).compactMap({ $0.startDate }).sorted().first?.atNine() {
if first.isEarlierThan(startDate) {
return startDate
} else {
return first
}
} else {
return nil
}
}
func areGroupStagesPublished() -> Bool {
if let publishedGroupStagesDate = publishedGroupStagesDate() {
return Date() >= publishedGroupStagesDate
} else {
return false
}
}
func publishedBracketsDate() -> Date? {
if let first = rounds().flatMap({ $0.playedMatches() }).compactMap({ $0.startDate }).sorted().first?.atNine() {
if first.isEarlierThan(startDate) {
return startDate
} else {
return first
}
} else {
return nil
}
}
func areBracketsPublished() -> Bool {
if let publishedBracketsDate = publishedBracketsDate() {
return Date() >= publishedBracketsDate
} else {
return false
}
}
func shareURL() -> URL? {
return URLs.main.url.appending(path: "tournament/\(id)")
}
@ -1096,7 +1145,7 @@ class Tournament : ModelObject, Storable {
let matches = (0..<matchCount).map { //0 is final match
let roundIndex = RoundRule.roundIndex(fromMatchIndex: $0)
let round = rounds[roundIndex]
return Match(round: round.id, index: $0, matchFormat: matchFormat)
return Match(round: round.id, index: $0, matchFormat: matchFormat, name: Match.setServerTitle(upperRound: round, matchIndex: RoundRule.matchIndexWithinRound(fromMatchIndex: $0)))
}
print(matches.map {

@ -11,7 +11,7 @@ enum URLs: String, Identifiable {
case subscriptions = "https://apple.co/2Th4vqI"
case main = "https://xlr.alwaysdata.net/"
case beachPadel = "https://beach-padel.app.fft.fr/beachja/index/"
case padelClub = "https://padelclub.app"
//case padelClub = "https://padelclub.app"
var id: String { return self.rawValue }

@ -27,21 +27,37 @@ struct ClubDetailView: View {
var body: some View {
Form {
Section {
NavigationLink {
ClubSearchView(displayContext: .edition, club: club)
} label: {
Label("Chercher dans la base fédérale", systemImage: "magnifyingglass")
}
} footer: {
Text("Vous pouvez chercher un club dans la base fédérale et importer les informations directement.")
}
Section {
VStack(alignment: .leading, spacing: 0) {
Text("Nom du club").foregroundStyle(.secondary).font(.caption)
LabeledContent {
TextField("Nom du club", text: $club.name)
.fixedSize()
.autocorrectionDisabled()
.keyboardType(.alphabet)
.multilineTextAlignment(.trailing)
.frame(maxWidth: .infinity)
.focused($focusedField, equals: ._name)
.submitLabel( displayContext == .addition ? .next : .done)
.onSubmit {
if club.acronym.isEmpty {
club.acronym = club.name.canonicalVersion.replaceCharactersFromSet(characterSet: .whitespacesAndNewlines)
focusedField = ._city
}
if displayContext == .addition {
focusedField = ._acronym
}
}
} label: {
Text("Nom du club")
}
.onTapGesture {
focusedField = ._name
@ -92,10 +108,12 @@ struct ClubDetailView: View {
}
if club.code == nil {
VStack(alignment: .leading, spacing: 0) {
Text("Ville").foregroundStyle(.secondary).font(.caption)
LabeledContent {
TextField("Ville", text: $city)
.fixedSize()
.autocorrectionDisabled()
.keyboardType(.alphabet)
.multilineTextAlignment(.trailing)
.frame(maxWidth: .infinity)
.focused($focusedField, equals: ._city)
.submitLabel( displayContext == .addition ? .next : .done)
.onSubmit {
@ -104,20 +122,26 @@ struct ClubDetailView: View {
}
club.city = city
}
} label: {
Text("Ville")
}
.onTapGesture {
focusedField = ._city
}
VStack(alignment: .leading, spacing: 0) {
Text("Code Postal").foregroundStyle(.secondary).font(.caption)
LabeledContent {
TextField("Code Postal", text: $zipCode)
.fixedSize()
.autocorrectionDisabled()
.keyboardType(.alphabet)
.multilineTextAlignment(.trailing)
.frame(maxWidth: .infinity)
.focused($focusedField, equals: ._zipCode)
.submitLabel( displayContext == .addition ? .next : .done)
.onSubmit {
club.zipCode = zipCode
}
} label: {
Text("Code Postal")
}
.onTapGesture {
focusedField = ._zipCode

@ -22,6 +22,7 @@ struct CourtView: View {
Section {
LabeledContent {
TextField("Nom", text: $name)
.autocorrectionDisabled()
.keyboardType(.alphabet)
.multilineTextAlignment(.trailing)
.frame(maxWidth: .infinity)

@ -59,6 +59,14 @@ struct PlanningSettingsView: View {
Text("Préciser la disponibilité des terrains")
}
}
} footer: {
FooterButtonView((showOptions ? "masquer" : "voir") + " les réglages avancées") {
showOptions.toggle()
}
}
if showOptions {
_optionsView()
}
Section {
@ -68,19 +76,9 @@ struct PlanningSettingsView: View {
schedulingDone = true
}
} footer: {
Button {
showOptions.toggle()
} label: {
Text((showOptions ? "masquer" : "voir") + " les réglages avancées")
.underline()
}
.buttonStyle(.borderless)
Text("Padel Club programmera tous les matchs de votre tournoi en fonction de différents paramètres, ") + Text("tout en tenant compte des horaires que vous avez fixé.").underline()
}
if showOptions {
_optionsView()
}
Section {
RowButtonView("Supprimer tous les horaires", role: .destructive) {
do {
@ -101,6 +99,7 @@ struct PlanningSettingsView: View {
}
}
}
.headerProminence(.increased)
.onAppear {
do {
try dataStore.matchSchedulers.addOrUpdate(instance: matchScheduler)

@ -42,7 +42,7 @@ struct RoundSettingsView: View {
let matchCount = RoundRule.numberOfMatches(forRoundIndex: roundIndex)
let matchStartIndex = RoundRule.matchIndex(fromRoundIndex: roundIndex)
let matches = (0..<matchCount).map { //0 is final match
return Match(round: round.id, index: $0 + matchStartIndex, matchFormat: round.matchFormat)
return Match(round: round.id, index: $0 + matchStartIndex, matchFormat: round.matchFormat, name: Match.setServerTitle(upperRound: round, matchIndex: $0))
}
try? dataStore.rounds.addOrUpdate(instance: round)
try? dataStore.matches.addOrUpdate(contentOfs: matches)

@ -52,9 +52,10 @@ struct RoundView: View {
print(spaceLeft[drawResult.drawIndex].matchTitle())
availableQualifiedTeams[drawResult.drawee].setSeedPosition(inSpot: spaceLeft[drawResult.drawIndex], slot: nil, opposingSeeding: true)
}
try? dataStore.matches.addOrUpdate(contentOfs: spaceLeft)
try? dataStore.teamRegistrations.addOrUpdate(contentOfs: availableQualifiedTeams)
isEditingTournamentSeed.wrappedValue.toggle()
_save()
if tournament.availableSeeds().isEmpty && tournament.availableQualifiedTeams().isEmpty {
self.isEditingTournamentSeed.wrappedValue = false
}
}
}
} else if let availableSeedGroup = tournament.seedGroupAvailable(atRoundIndex: round.index) {
@ -62,8 +63,8 @@ struct RoundView: View {
Section {
RowButtonView("Placer \(availableSeedGroup.localizedLabel())" + ((availableSeedGroup.isFixed() == false) ? " au hasard" : "")) {
tournament.setSeeds(inRoundIndex: round.index, inSeedGroup: availableSeedGroup)
if tournament.availableSeeds().isEmpty {
_save()
_save()
if tournament.availableSeeds().isEmpty && tournament.availableQualifiedTeams().isEmpty {
self.isEditingTournamentSeed.wrappedValue = false
}
}
@ -109,8 +110,10 @@ struct RoundView: View {
print(availableSeedSpot[drawResult.drawIndex].matchTitle())
seeds[drawResult.drawee].setSeedPosition(inSpot: availableSeedSpot[drawResult.drawIndex], slot: nil, opposingSeeding: false)
}
try? dataStore.matches.addOrUpdate(contentOfs: availableSeedSpot)
try? dataStore.teamRegistrations.addOrUpdate(contentOfs: seeds)
_save()
if tournament.availableSeeds().isEmpty && tournament.availableQualifiedTeams().isEmpty {
self.isEditingTournamentSeed.wrappedValue = false
}
}
}
}
@ -129,7 +132,16 @@ struct RoundView: View {
}
private func _save() {
try? dataStore.teamRegistrations.addOrUpdate(contentOfs: tournament.seeds())
try? dataStore.teamRegistrations.addOrUpdate(contentOfs: tournament.unsortedTeams())
//todo should be done server side
let rounds = tournament.rounds()
rounds.forEach { round in
let matches = round.playedMatches()
matches.forEach { match in
match.name = Match.setServerTitle(upperRound: round, matchIndex: match.indexInRound())
}
}
let allRoundMatches = tournament.allRoundMatches()
try? DataStore.shared.matches.addOrUpdate(contentOfs: allRoundMatches)
}

@ -30,7 +30,7 @@ struct BroadcastView: View {
List {
Section {
TipView(tournamentPublishingTip) { action in
UIApplication.shared.open(URLs.padelClub.url)
UIApplication.shared.open(URLs.main.url)
}
.tipStyle(tint: nil)
}
@ -39,67 +39,132 @@ struct BroadcastView: View {
.tipStyle(tint: nil)
}
if tournament.publishManually == false {
Section {
Text("En mode automatique, Padel Club détermine le meilleur moment pour publier les informations du tournoi.\n\n• La liste des équipes sera visible au maximum 2 jours après la clôture des inscriptions. À partir des p500, la liste d'attente à la clôture sera également publiée.\n\n• Les convocations ne seront visibles qu'à partir du premier jour du tournoi.\n\n• Les poules ne seront visibles qu'au premier jour des poules.\n\n• Le tableau ne sera visible qu'au premier jour du tableau.")
} header: {
Text("Mode Automatique")
} footer: {
FooterButtonView("désactiver le mode automatique") {
tournament.publishManually.toggle()
Section {
LabeledContent {
if tournament.areTeamsPublished() {
Image(systemName:"checkmark").foregroundStyle(.green)
} else {
Text(tournament.publishedTeamsDate().formatted())
}
} label: {
if tournament.areTeamsPublished() {
Text("Publiée")
} else {
Text("Publication prévue")
}
Text("Les horaires de convocations ne seront pas publiés")
}
} header: {
Text("Liste des équipes")
} footer: {
if tournament.publishedTeamsDate() < Date() {
FooterButtonView(tournament.publishTeams ? "masquer sur le site" : "publier maintenant") {
tournament.publishTeams.toggle()
}
}
}
if tournament.publishManually == true {
Section {
Text("En mode manuel, vous devez indiquer à Padel Club le moment où vous souhaitez publier les informations du tournoi")
Toggle(isOn: $tournament.publishTeams) {
Text("Publier la liste des équipes")
Text("Les horaires de convocations ne seront pas publiés")
Section {
LabeledContent {
if tournament.areTeamsPublished() {
Image(systemName:"checkmark").foregroundStyle(.green)
} else {
Text(tournament.publishedTeamsDate().formatted())
}
} label: {
if tournament.areTeamsPublished() {
Text("Publiée")
} else {
Text("Publication prévue")
}
Toggle(isOn: $tournament.publishWaitingList) {
Text("Inclure les équipes en liste d'attente")
}
} header: {
Text("Convocations")
} footer: {
if tournament.publishedTeamsDate() < Date() {
FooterButtonView(tournament.publishSummons ? "masquer sur le site" : "publier maintenant") {
tournament.publishSummons.toggle()
}
Toggle(isOn: $tournament.publishSummons) {
Text("Publier les convocations")
}
}
if let publishedGroupStagesDate = tournament.publishedGroupStagesDate() {
Section {
let areGroupStagesPublished = tournament.areGroupStagesPublished()
LabeledContent {
if areGroupStagesPublished {
Image(systemName:"checkmark").foregroundStyle(.green)
} else {
Text(publishedGroupStagesDate.formatted())
}
} label: {
if areGroupStagesPublished {
Text("Publiée")
} else {
Text("Publication prévue")
}
}
Toggle(isOn: $tournament.publishGroupStages) {
Text("Publier les poules")
} header: {
Text("Poules")
} footer: {
if publishedGroupStagesDate < Date() {
FooterButtonView(tournament.publishGroupStages ? "masquer sur le site" : "publier maintenant") {
tournament.publishGroupStages.toggle()
}
}
Toggle(isOn: $tournament.publishBrackets) {
Text("Publier le tableau")
}
}
if let publishedBracketsDate = tournament.publishedBracketsDate() {
Section {
let areBracketsPublished = tournament.areBracketsPublished()
LabeledContent {
if areBracketsPublished {
Image(systemName:"checkmark").foregroundStyle(.green)
} else {
Text(publishedBracketsDate.formatted())
}
} label: {
if areBracketsPublished {
Text("Publiée")
} else {
Text("Publication prévue")
}
}
} header: {
Text("Mode Manuel")
Text("Tableau")
} footer: {
FooterButtonView("activer le mode automatique") {
tournament.publishManually.toggle()
if publishedBracketsDate < Date() {
FooterButtonView(tournament.publishBrackets ? "masquer sur le site" : "publier maintenant") {
tournament.publishBrackets.toggle()
}
}
}
}
//todo waitinglist & info
Section {
Toggle(isOn: $tournament.isPrivate) {
Text("Tournoi privé")
}
} footer: {
Text("Le tournoi sera masqué sur le site \(URLs.main.rawValue)")
let footerString = "Le tournoi sera masqué sur le site [Padel Club]\(URLs.main.rawValue)"
Text(.init(footerString))
}
Section {
LabeledContent {
actionForURL(URLs.main.url)
} label: {
Text("Lien Padel Club")
Text("Padel Club")
}
if let club = tournament.club(), let clubURL = club.shareURL() {
LabeledContent {
actionForURL(clubURL)
} label: {
Text("Lien du club")
Text("Club")
}
}
@ -107,7 +172,7 @@ struct BroadcastView: View {
LabeledContent {
actionForURL(url)
} label: {
Text("Lien du tournoi")
Text("Tournoi")
}
}
@ -115,7 +180,7 @@ struct BroadcastView: View {
LabeledContent {
actionForURL(url)
} label: {
Text("Lien TV")
Text("TV")
}
}
@ -185,8 +250,7 @@ struct BroadcastView: View {
} label: {
HStack {
Spacer()
Text("lien")
.underline()
Image(systemName: "square.and.arrow.up")
}
}
.frame(maxWidth: .infinity)

@ -96,7 +96,7 @@ final class ServerDataTests: XCTestCase {
return
}
let tournament = Tournament(event: eventId, name: "RG Homme", startDate: Date(), endDate: nil, creationDate: Date(), isPrivate: false, groupStageFormat: MatchFormat.megaTie, roundFormat: MatchFormat.nineGames, loserRoundFormat: MatchFormat.nineGamesDecisivePoint, groupStageSortMode: GroupStageOrderingMode.snake, groupStageCount: 2, rankSourceDate: Date(), dayDuration: 5, teamCount: 3, teamSorting: TeamSortingType.rank, federalCategory: TournamentCategory.mix, federalLevelCategory: TournamentLevel.p1000, federalAgeCategory: FederalTournamentAge.a45, groupStageCourtCount: 6, closedRegistrationDate: Date(), groupStageAdditionalQualified: 4, courtCount: 9, prioritizeClubMembers: true, qualifiedPerGroupStage: 1, teamsPerGroupStage: 2, entryFee: 30.0, additionalEstimationDuration: 5, isDeleted: true)
let tournament = Tournament(event: eventId, name: "RG Homme", startDate: Date(), endDate: nil, creationDate: Date(), isPrivate: false, groupStageFormat: MatchFormat.megaTie, roundFormat: MatchFormat.nineGames, loserRoundFormat: MatchFormat.nineGamesDecisivePoint, groupStageSortMode: GroupStageOrderingMode.snake, groupStageCount: 2, rankSourceDate: Date(), dayDuration: 5, teamCount: 3, teamSorting: TeamSortingType.rank, federalCategory: TournamentCategory.mix, federalLevelCategory: TournamentLevel.p1000, federalAgeCategory: FederalTournamentAge.a45, groupStageCourtCount: 6, closedRegistrationDate: Date(), groupStageAdditionalQualified: 4, courtCount: 9, prioritizeClubMembers: true, qualifiedPerGroupStage: 1, teamsPerGroupStage: 2, entryFee: 30.0, additionalEstimationDuration: 5, isDeleted: true, publishTeams: true, publishSummons: true, publishGroupStages: true, publishBrackets: true)
let t = try await Store.main.service().post(tournament)
assert(t.event == tournament.event)
@ -127,7 +127,11 @@ final class ServerDataTests: XCTestCase {
assert(t.entryFee == tournament.entryFee)
assert(t.additionalEstimationDuration == tournament.additionalEstimationDuration)
assert(t.isDeleted == tournament.isDeleted)
assert(t.publishTeams == tournament.publishTeams)
assert(t.publishSummons == tournament.publishSummons)
assert(t.publishGroupStages == tournament.publishGroupStages)
assert(t.publishBrackets == tournament.publishBrackets)
}
func testGroupStage() async throws {

Loading…
Cancel
Save