Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
98 commits
Select commit Hold shift + click to select a range
2148479
tournament component - 1 attribute, working backend&frontend for it
SzBeni2003 Jan 28, 2025
afb7eda
tournament component - 2nd attribute
SzBeni2003 Jan 28, 2025
050e4d0
tournament: Component Settings fixed, some reformat, new attributes
SzBeni2003 Jan 30, 2025
c1e9a3a
tournament - knockout stage, registration - backend stuff
SzBeni2003 Feb 3, 2025
d3f32ad
tournament match - entity, repository done, controller done
SzBeni2003 Feb 5, 2025
c87d1fc
some test data; still figuring out the schema
SzBeni2003 Feb 10, 2025
908686f
still figuring out the schema
SzBeni2003 Feb 14, 2025
a801397
generate matches for knockoutstage
SzBeni2003 Feb 18, 2025
affbbb3
Api + frontend hook
SzBeni2003 Feb 19, 2025
727f7e1
when did I even touch this file?
SzBeni2003 Feb 23, 2025
e448ffe
rebase onto rebase
SzBeni2003 Jan 28, 2025
4f0aa85
tournament component - 2nd attribute
SzBeni2003 Jan 28, 2025
eab29dc
tournament: Component Settings fixed, some reformat, new attributes
SzBeni2003 Jan 30, 2025
340b1f4
tournament - knockout stage, registration - backend stuff
SzBeni2003 Feb 3, 2025
f1ba65d
tournament match - entity, repository done, controller done
SzBeni2003 Feb 5, 2025
11197f0
some test data; still figuring out the schema
SzBeni2003 Feb 10, 2025
53a3816
still figuring out the schema
SzBeni2003 Feb 14, 2025
2a7ae72
generate matches for knockoutstage
SzBeni2003 Feb 18, 2025
fd200f3
Api + frontend hook
SzBeni2003 Feb 19, 2025
452bc73
when did I even touch this file?
SzBeni2003 Feb 23, 2025
1a46dc5
knockout stage frontend, cannot compile...
SzBeni2003 Feb 24, 2025
bad9a6b
Merge remote-tracking branch 'origin/feature/tournament-component' in…
SzBeni2003 Feb 25, 2025
2de4135
api working, frontend for Detailed Tournament view (not tested yet)
SzBeni2003 Feb 25, 2025
a152ea8
Tournament Detailed View getting some clothes
SzBeni2003 Feb 27, 2025
6d883fd
removed some stuff so the backend runs
SzBeni2003 Mar 3, 2025
99d5e9b
frontend looks better
SzBeni2003 Mar 3, 2025
929ce86
Merge branch 'refs/heads/staging' into feature/tournament-component
SzBeni2003 Apr 9, 2025
8c1709e
bracket connectors
SzBeni2003 Apr 19, 2025
78e30bd
update component to support S3 buckets (and minor stuff)
SzBeni2003 Apr 19, 2025
3420275
small adjustments for Match.tsx
SzBeni2003 Apr 19, 2025
fc6f543
bulk deletion for matches and stages, working bracket generation
SzBeni2003 Jun 9, 2025
9402874
Merge branch 'staging' into feature/tournament-component
SzBeni2003 Jun 13, 2025
2de7f6d
registerTeam WIP
SzBeni2003 Jun 15, 2025
eaa3f12
registerTeam
SzBeni2003 Jun 16, 2025
d0f9826
Merge remote-tracking branch 'origin/staging' into feature/tournament…
SzBeni2003 Jun 18, 2025
60f9df9
inputType, overviewType
SzBeni2003 Jun 19, 2025
aa9fc4c
menu option available for tournaments
SzBeni2003 Jun 19, 2025
5375720
create knockoutstage without memorizing the tournamentId (PLS CHECK t…
SzBeni2003 Jun 20, 2025
2d8f848
WIP joining to tournaments
SzBeni2003 Jun 23, 2025
1f2e177
WIP joining to tournaments - backend support for user/group ownership…
SzBeni2003 Jun 23, 2025
c7f2c8f
tournaments - access control
SzBeni2003 Jun 23, 2025
4560314
tournaments - access control
SzBeni2003 Jun 23, 2025
ab5b340
dependency cycles removed
SzBeni2003 Jun 23, 2025
6cd66a5
frontend support for joining tournaments
SzBeni2003 Jun 23, 2025
2f61ea5
seeds (lots of stuff, wip)
SzBeni2003 Jun 27, 2025
8ce0f77
seedsetter admin page
SzBeni2003 Jun 30, 2025
e11b3ab
initial seed setting api (needs testing and some modifications)
SzBeni2003 Jun 30, 2025
ce526bb
initial seed setting api (needs testing and some modifications)
SzBeni2003 Jun 30, 2025
5f996fc
Merge remote-tracking branch 'origin/feature/tournament-component' in…
SzBeni2003 Jun 30, 2025
646e6b5
Merge branch 'staging' into feature/tournament-component
SzBeni2003 Jun 30, 2025
39a9660
seeds working, updating etc
SzBeni2003 Jul 4, 2025
97e15bb
reordered functions in stageservice
SzBeni2003 Jul 4, 2025
2d3e475
typo
SzBeni2003 Jul 5, 2025
93c2d85
matchAdmin
SzBeni2003 Jul 5, 2025
4211111
seedSettings now include byeGames as well
SzBeni2003 Jul 7, 2025
299db67
admin frontend (new+improvements)
SzBeni2003 Jul 7, 2025
1b1b4ae
fixed winner() for seed continuity
SzBeni2003 Jul 8, 2025
972864d
some small stuff
SzBeni2003 Jul 8, 2025
65e2aaf
thymeleaf my beloved
SzBeni2003 Jul 8, 2025
fa58f06
finalizeBtn fade if seeds modified
SzBeni2003 Jul 9, 2025
5dd4a91
finalizeBtn fade if seeds modified
SzBeni2003 Jul 9, 2025
4c2042d
seeds
SzBeni2003 Jul 10, 2025
a8ae65d
merge staging into feature/tournament-component (#917)
SzBeni2003 Jul 14, 2025
fb13535
syncing java and kotlin target jvm versions
SzBeni2003 Jul 20, 2025
b83d16d
react-router
SzBeni2003 Jul 20, 2025
9c79d1e
seedSettings complete: finalize seeds, finalized seedSettings page sp…
SzBeni2003 Jul 23, 2025
888b473
thymeleaf my beloved
SzBeni2003 Jul 23, 2025
7ba6438
thymeleaf my beloved
SzBeni2003 Jul 23, 2025
07fccb2
UNTESTED - match score input
SzBeni2003 Jul 24, 2025
0895e54
Merge branch 'staging' into feature/tournament-component
SzBeni2003 Jul 24, 2025
44faf19
changes requested pt1
SzBeni2003 Aug 3, 2025
1e96f86
changes requested pt2
SzBeni2003 Aug 4, 2025
44f05e8
changes requested pt3 - joinTournamentMutation
SzBeni2003 Aug 5, 2025
531db8d
configs
SzBeni2003 Aug 5, 2025
f0b3cce
configs
SzBeni2003 Aug 5, 2025
77f5cd4
changes requested - pt4
SzBeni2003 Aug 5, 2025
cc87f02
changes requested - pt5
SzBeni2003 Aug 5, 2025
b43827b
Merge remote-tracking branch 'origin/staging' into feature/tournament…
SzBeni2003 Aug 5, 2025
e00e69f
random deleted file got back with a merge
SzBeni2003 Aug 9, 2025
13562bd
sonar errors
SzBeni2003 Aug 9, 2025
70c9379
sonar codesmell
SzBeni2003 Aug 9, 2025
8914324
sonar codesmell
SzBeni2003 Aug 9, 2025
400480f
sonar codesmell
SzBeni2003 Aug 9, 2025
b753ef3
sonar codesmell
SzBeni2003 Aug 9, 2025
97c1c2e
unused imports, properties
SzBeni2003 Aug 9, 2025
4f109d3
unused imports, properties
SzBeni2003 Aug 9, 2025
d2377e0
sonar
SzBeni2003 Aug 9, 2025
2512650
refactor knockoutStage to tournamentStage - the base for adding Group…
SzBeni2003 Aug 10, 2025
d70ad91
fixed ambiguous mappings; create stage working with group stages as well
SzBeni2003 Aug 10, 2025
fda8702
create stage working with group stages as well
SzBeni2003 Aug 10, 2025
a2365f3
byeGames, match generation fixed
SzBeni2003 Aug 10, 2025
5411370
seed save fixed
SzBeni2003 Aug 10, 2025
e9a409e
seed save fixed
SzBeni2003 Aug 10, 2025
faeb4cc
Merge branch 'staging' into feature/tournament-component
SzBeni2003 Aug 17, 2025
091f2af
byeGame; react hooks
SzBeni2003 Aug 17, 2025
7fba9ae
stageResult comparator
SzBeni2003 Aug 17, 2025
7251d38
matchScore updating IN_PROGRESS Matches
SzBeni2003 Aug 26, 2025
9f24e68
reverted openness of create
SzBeni2003 Aug 26, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package hu.bme.sch.cmsch.component.tournament

import hu.bme.sch.cmsch.admin.GenerateOverview
import hu.bme.sch.cmsch.admin.OverviewType
import hu.bme.sch.cmsch.model.IdentifiableEntity

data class MatchGroupDto(

@property:GenerateOverview(renderer = OverviewType.ID, columnName = "ID", order = -1)
override var id: Int = 0,

@property:GenerateOverview(columnName = "Név", order = 1)
var name: String = "",

@property:GenerateOverview(columnName = "Helyszín", order = 2)
var location: String = "",

@property:GenerateOverview(columnName = "Közeli meccsek száma", order = 3)
var matchCount: Int = 0,

): IdentifiableEntity
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package hu.bme.sch.cmsch.component.tournament

data class ParticipantDto(
var teamId: Int = 0,
var teamName: String = "",
)

data class SeededParticipantDto(
var teamId: Int = 0,
var teamName: String = "",
var seed: Int = 0,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package hu.bme.sch.cmsch.component.tournament

import hu.bme.sch.cmsch.admin.GenerateOverview
import hu.bme.sch.cmsch.admin.OverviewType
import hu.bme.sch.cmsch.model.IdentifiableEntity

data class StageGroupDto(

@property:GenerateOverview(renderer = OverviewType.ID, columnName = "ID", order = -1)
override var id: Int = 0,

@property:GenerateOverview(columnName = "Név", order = 1)
var name: String = "",

@property:GenerateOverview(columnName = "Helyszín", order = 2)
var location: String = "",

@property:GenerateOverview(columnName = "Résztvevők száma", order = 3)
var participantCount: Int = 0,

@property:GenerateOverview(columnName = "Szakaszok száma", order = 4)
var stageCount: Int = 0

): IdentifiableEntity
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package hu.bme.sch.cmsch.component.tournament

import com.fasterxml.jackson.annotation.JsonInclude

@JsonInclude(JsonInclude.Include.NON_EMPTY)
data class StageResultDto(
val teamId: Int,
val teamName: String,
val stageId: Int = 0,
var highlighted: Boolean = false,
var initialSeed: Int = 0,
var highestSeed: Int = 0,
var detailedStats: GroupStageResults? = null,
): Comparable<StageResultDto> {
override fun compareTo(other: StageResultDto): Int {
if (this.stageId != other.stageId) {
return this.stageId.compareTo(other.stageId)
}
if (this.detailedStats == null && other.detailedStats == null) {
return -this.initialSeed.compareTo(other.highestSeed)
}
if (this.detailedStats == null) {
return -1 // null detailed stats are considered better (knockout stages are later)
}
return compareValuesBy(this, other,
{ it.detailedStats?:GroupStageResults()}, {it.initialSeed}, {it.highlighted})
}
}
data class GroupStageResults(
var group: String = "",
var position: UShort = UShort.MAX_VALUE,
var points: UInt = 0u,
var won: UShort = 0u,
var drawn: UShort = 0u,
var lost: UShort = 0u,
var goalsFor: UInt = 0u,
var goalsAgainst: UInt = 0u,
var goalDifference: Int = 0
): Comparable<GroupStageResults> {
override fun compareTo(other: GroupStageResults): Int {
return compareValuesBy(this, other,
{ -it.position.toInt() },
{ it.points },
{ it.won },
{ it.goalDifference },
{ it.goalsFor })
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package hu.bme.sch.cmsch.component.tournament

import com.fasterxml.jackson.annotation.JsonView
import hu.bme.sch.cmsch.config.OwnershipType
import hu.bme.sch.cmsch.dto.Preview
import hu.bme.sch.cmsch.model.RoleType
import hu.bme.sch.cmsch.util.getUserOrNull
import hu.bme.sch.cmsch.util.isAvailableForRole
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.responses.ApiResponse
import io.swagger.v3.oas.annotations.responses.ApiResponses
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.security.core.Authentication
import org.springframework.web.bind.annotation.*

@RestController
@RequestMapping("/api")
@ConditionalOnBean(TournamentComponent::class)
class TournamentApiController(
private val tournamentComponent: TournamentComponent,
private val tournamentService: TournamentService,
) {
@JsonView(Preview::class)
@GetMapping("/tournament")
@Operation(
summary = "List all tournaments.",
)
@ApiResponses(value = [
ApiResponse(responseCode = "200", description = "List of tournaments")
])
fun listTournaments(auth: Authentication?): ResponseEntity<List<TournamentPreviewView>> {
val user = auth?.getUserOrNull()
if (!tournamentComponent.minRole.isAvailableForRole(user?.role ?: RoleType.GUEST))
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(listOf())
if (!tournamentComponent.showTournamentsAtAll) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).build()
}

return ResponseEntity.ok(tournamentService.listAllTournaments())
}


@GetMapping("/tournament/{tournamentId}")
@Operation(
summary = "Get details of a tournament.",
)
@ApiResponses(value = [
ApiResponse(responseCode = "200", description = "Details of the tournament"),
ApiResponse(responseCode = "404", description = "Tournament not found")
])
fun tournamentDetails(
@PathVariable tournamentId: Int,
auth: Authentication?
): ResponseEntity<OptionalTournamentView>{
val user = auth?.getUserOrNull()
if (!tournamentComponent.minRole.isAvailableForRole(user?.role ?: RoleType.GUEST))
return ResponseEntity.status(HttpStatus.FORBIDDEN).build()

return tournamentService.showTournament(tournamentId, user)?.let { ResponseEntity.ok(it) }
?: ResponseEntity.status(HttpStatus.NOT_FOUND).build()
}

@PostMapping("/tournament/register")
fun registerTeam(
@RequestBody tournamentJoinDto: TournamentJoinDto,
auth: Authentication?
): TournamentJoinStatus {
val user = auth?.getUserOrNull()
?: return TournamentJoinStatus.INSUFFICIENT_PERMISSIONS

val tournament = tournamentService.findById(tournamentJoinDto.id)
?: return TournamentJoinStatus.TOURNAMENT_NOT_FOUND
return when (tournament.participantType) {
OwnershipType.GROUP -> tournamentService.teamRegister(tournament, user)
OwnershipType.USER -> tournamentService.userRegister(tournament, user)
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package hu.bme.sch.cmsch.component.tournament

import hu.bme.sch.cmsch.component.ComponentBase
import hu.bme.sch.cmsch.model.RoleType
import hu.bme.sch.cmsch.service.ControlPermissions
import hu.bme.sch.cmsch.setting.*
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.core.env.Environment
import org.springframework.stereotype.Service


@Service
@ConditionalOnProperty(
prefix = "hu.bme.sch.cmsch.component.load",
name = ["tournament"],
havingValue = "true",
matchIfMissing = false
)
class TournamentComponent (
componentSettingService: ComponentSettingService,
env: Environment
) : ComponentBase(
componentSettingService,
"tournament",
"/tournament",
"Tournament",
ControlPermissions.PERMISSION_CONTROL_TOURNAMENT,
listOf(),
env
) {

val tournamentGroup by SettingGroup(fieldName = "Versenyek")
final var title by StringSettingRef(
"Sportversenyek",
fieldName = "Lap címe", description = "Ez jelenik meg a böngésző címsorában"
)
final override var menuDisplayName by StringSettingRef(
"Sportversenyek", serverSideOnly = true,
fieldName = "Menü neve", description = "Ez lesz a neve a menünek"
)
final override var minRole by MinRoleSettingRef(
setOf(), fieldName = "Jogosultságok",
description = "Melyik roleokkal nyitható meg az oldal"
)

var showTournamentsAtAll by BooleanSettingRef(
false, fieldName = "Leküldött",
description = "Ha igaz, akkor leküldésre kerülnek a versenyek"
)

var closeMatchesTimeWindow by NumberSettingRef(
defaultValue = 120, fieldName = "Közelgő mérkőzések időablaka",
description = "Mennyi időn belül közelgő mérkőzések jelenjenek meg a match admin oldalon",
minRoleToEdit = RoleType.ADMIN
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package hu.bme.sch.cmsch.component.tournament

import hu.bme.sch.cmsch.component.ComponentApiBase
import hu.bme.sch.cmsch.component.app.MenuService
import hu.bme.sch.cmsch.service.AdminMenuService
import hu.bme.sch.cmsch.service.AuditLogService
import hu.bme.sch.cmsch.service.ControlPermissions
import hu.bme.sch.cmsch.service.StorageService
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean
import org.springframework.stereotype.Controller
import org.springframework.web.bind.annotation.RequestMapping

@Controller
@RequestMapping("/admin/control/component/tournament")
@ConditionalOnBean(TournamentComponent::class)
class TournamentComponentController(
adminMenuService: AdminMenuService,
component: TournamentComponent,
private val menuService: MenuService,
private val tournamentService: TournamentService,
private val auditLogService: AuditLogService,
private val storageService: StorageService,
service: MenuService
) : ComponentApiBase(
adminMenuService,
TournamentComponent::class.java,
component,
ControlPermissions.PERMISSION_CONTROL_TOURNAMENT,
"Tournament",
"Tournament beállítások",
auditLogService = auditLogService,
menuService = menuService,
storageService = storageService
) {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package hu.bme.sch.cmsch.component.tournament

import org.springframework.boot.autoconfigure.condition.ConditionalOnBean
import org.springframework.boot.autoconfigure.domain.EntityScan
import org.springframework.context.annotation.Configuration


@Configuration
@ConditionalOnBean(TournamentComponent::class)
@EntityScan(basePackageClasses = [TournamentComponent::class])
class TournamentComponentEntityConfiguration
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package hu.bme.sch.cmsch.component.tournament

import com.fasterxml.jackson.databind.ObjectMapper
import hu.bme.sch.cmsch.controller.admin.OneDeepEntityPage
import hu.bme.sch.cmsch.controller.admin.calculateSearchSettings
import hu.bme.sch.cmsch.service.AdminMenuService
import hu.bme.sch.cmsch.service.AuditLogService
import hu.bme.sch.cmsch.service.ImportService
import hu.bme.sch.cmsch.service.StaffPermissions
import hu.bme.sch.cmsch.service.StorageService
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean
import org.springframework.core.env.Environment
import org.springframework.stereotype.Controller
import org.springframework.transaction.PlatformTransactionManager
import org.springframework.web.bind.annotation.RequestMapping

@Controller
@RequestMapping("/admin/control/tournament")
@ConditionalOnBean(TournamentComponent::class)
class TournamentController(
private val tournamentService: TournamentService,
repo: TournamentRepository,
importService: ImportService,
adminMenuService: AdminMenuService,
component: TournamentComponent,
auditLog: AuditLogService,
objectMapper: ObjectMapper,
transactionManager: PlatformTransactionManager,
storageService: StorageService,
env: Environment
) : OneDeepEntityPage<TournamentEntity>(
"tournament",
TournamentEntity::class, ::TournamentEntity,
"Verseny", "Versenyek",
"A rendezvény versenyeinek kezelése.",

transactionManager,
repo,
importService,
adminMenuService,
storageService,
component,
auditLog,
objectMapper,
env,

showPermission = StaffPermissions.PERMISSION_SHOW_TOURNAMENTS,
createPermission = StaffPermissions.PERMISSION_CREATE_TOURNAMENTS,
editPermission = StaffPermissions.PERMISSION_EDIT_TOURNAMENTS,
deletePermission = StaffPermissions.PERMISSION_DELETE_TOURNAMENTS,

createEnabled = true,
editEnabled = true,
deleteEnabled = true,
importEnabled = true,
exportEnabled = true,

adminMenuIcon = "sports_esports",
adminMenuPriority = 1,
searchSettings = calculateSearchSettings<TournamentEntity>(true)
){
override fun onEntityDeleted(entity: TournamentEntity) {
tournamentService.deleteStagesForTournament(entity)
super.onEntityDeleted(entity)
}
}
Loading