diff --git a/internal/api/handler.go b/internal/api/handler.go index 8a3ece9..92d5c96 100644 --- a/internal/api/handler.go +++ b/internal/api/handler.go @@ -123,7 +123,7 @@ func (h Handler) EditGame(c echo.Context) error { return slices.Index(form.Players, i.Name) - slices.Index(form.Players, j.Name) }) - updatedGame, err := h.service.Edit(*game) + updatedGame, err := h.service.EditGame(*game) if err != nil { return err } @@ -144,7 +144,7 @@ func (h Handler) DeleteGame(c echo.Context) error { return err } - err = h.service.Delete(int32(parsedId)) + err = h.service.DeleteGame(int32(parsedId)) if err != nil { c.Logger().Error(err) return err @@ -167,12 +167,107 @@ func (h Handler) AddRound(c echo.Context) error { return err } + round, err := parseRound(*game, c) + round.CreatedAt = time.Now() + if err != nil { + return err + } + + round, err = h.service.AddRound(round) + if err != nil { + return err + } + + game.Rounds = append(game.Rounds, round) + gameDetails := template.GameDetails(*game) + return render(c, http.StatusCreated, gameDetails) +} + +func (h Handler) GetEditRoundForm(c echo.Context) error { + game, err := h.findGame(c.Param("gameid")) + if err != nil { + return err + } + + roundId, err := strconv.Atoi(c.Param("roundid")) + if err != nil { + return err + } + + var round skat.Round + var roundIdx int + for i, r := range game.Rounds { + if r.ID == int32(roundId) { + round = r + roundIdx = i + } + } + + form := components.EditRoundForm(*game, round, roundIdx) + return render(c, http.StatusOK, form) +} + +func (h Handler) EditRound(c echo.Context) error { + game, err := h.findGame(c.Param("gameid")) + if err != nil { + c.Logger().Error(err) + return err + } + + parsedRoundId, err := strconv.Atoi(c.Param("roundid")) + if err != nil { + c.Logger().Error(err) + return err + } + + round, err := parseRound(*game, c) + if err != nil { + c.Logger().Error(err) + return err + } + round.ID = int32(parsedRoundId) + + updatedRound, err := h.service.EditRound(round) + if err != nil { + c.Logger().Error(err) + return err + } + + for i, round := range game.Rounds { + if updatedRound.ID == round.ID { + game.Rounds[i] = updatedRound + break + } + } + + gameDetails := template.GameDetails(*game) + return render(c, http.StatusCreated, gameDetails) +} + +func (h Handler) DeleteRound(c echo.Context) error { + parsedRoundId, err := strconv.Atoi(c.Param("roundid")) + if err != nil { + c.Logger().Error(err) + return err + } + + h.service.DeleteRound(int32(parsedRoundId)) + + game, err := h.findGame(c.Param("gameid")) + if err != nil { + return err + } + + gameDetails := template.GameDetails(*game) + return render(c, http.StatusCreated, gameDetails) +} + +func parseRound(game skat.Game, c echo.Context) (skat.Round, error) { var params map[string]string = make(map[string]string) c.Bind(¶ms) round := skat.Round{} round.GameID = game.ID - round.CreatedAt = time.Now() for _, player := range game.Players { role, exists := params[player.Name] if !exists { @@ -185,16 +280,16 @@ func (h Handler) AddRound(c echo.Context) error { case "opponent": round.Opponents = append(round.Opponents, player.ID) case "dealer": - round.Dealer = &player.ID + dealer := player.ID + round.Dealer = &dealer } } - wonStr, exists := params["won"] if exists { won, err := strconv.ParseBool(wonStr) if err != nil { c.Logger().Error(err) - return err + return skat.Round{}, err } round.Won = won } @@ -204,19 +299,12 @@ func (h Handler) AddRound(c echo.Context) error { gameValue, err := strconv.Atoi(gameValueStr) if err != nil { c.Logger().Error(err) - return err + return skat.Round{}, err } round.Value = int32(gameValue) } - round, err = h.service.AddRound(game.ID, round) - if err != nil { - return err - } - - game.Rounds = append(game.Rounds, round) - gameDetails := template.GameDetails(*game) - return render(c, http.StatusCreated, gameDetails) + return round, nil } func render(ctx echo.Context, status int, t templ.Component) error { diff --git a/internal/skat/service.go b/internal/skat/service.go index 3aceb41..89f9288 100644 --- a/internal/skat/service.go +++ b/internal/skat/service.go @@ -145,7 +145,7 @@ func (s Service) Create(g Game) (Game, error) { return g, nil } -func (s Service) Edit(g Game) (Game, error) { +func (s Service) EditGame(g Game) (Game, error) { tx, err := s.db.Begin() if err != nil { return Game{}, err @@ -184,7 +184,7 @@ func (s Service) Edit(g Game) (Game, error) { return g, nil } -func (s Service) AddRound(gameId int32, round Round) (Round, error) { +func (s Service) AddRound(round Round) (Round, error) { opponents := round.Opponents tx, err := s.db.Begin() @@ -228,7 +228,83 @@ func (s Service) AddRound(gameId int32, round Round) (Round, error) { return round, nil } -func (s Service) Delete(gameId int32) error { +func (s Service) EditRound(round Round) (Round, error) { + tx, err := s.db.Begin() + if err != nil { + return Round{}, err + } + defer tx.Rollback() + + // Delete old opponents + deleteOpponents := table.RoundOpponent.DELETE(). + WHERE(table.RoundOpponent.RoundID.EQ(sqlite.Int32(round.ID))) + _, err = deleteOpponents.Exec(tx) + if err != nil { + return Round{}, err + } + + // Update round + updateRound := table.Round.UPDATE( + table.Round.AllColumns.Except(table.Round.ID), + ).WHERE(table.Round.ID.EQ(sqlite.Int32(round.ID))). + MODEL(round) + _, err = updateRound.Exec(tx) + if err != nil { + return Round{}, err + } + + // Insert new round opponents + roundOpponents := make([]model.RoundOpponent, 0) + for _, opponentId := range round.Opponents { + roundOpponents = append(roundOpponents, model.RoundOpponent{ + RoundID: round.ID, + PlayerID: opponentId, + }) + } + insertOpponents := table.RoundOpponent.INSERT( + table.RoundOpponent.AllColumns, + ).MODELS(roundOpponents) + + _, err = insertOpponents.Exec(tx) + if err != nil { + return Round{}, err + } + + err = tx.Commit() + if err != nil { + return Round{}, err + } + + return round, nil +} + +func (s Service) DeleteRound(roundId int32) error { + tx, err := s.db.Begin() + if err != nil { + return err + } + defer tx.Rollback() + + // Delete opponents + deleteOpponents := table.RoundOpponent.DELETE(). + WHERE(table.RoundOpponent.RoundID.EQ(sqlite.Int32(roundId))) + _, err = deleteOpponents.Exec(tx) + if err != nil { + return err + } + + // Delete round + deleteRound := table.Round.DELETE(). + WHERE(table.Round.ID.EQ(sqlite.Int32(roundId))) + _, err = deleteRound.Exec(tx) + if err != nil { + return err + } + + return tx.Commit() +} + +func (s Service) DeleteGame(gameId int32) error { tx, err := s.db.Begin() if err != nil { return err diff --git a/main.go b/main.go index edce60e..2215331 100644 --- a/main.go +++ b/main.go @@ -49,8 +49,11 @@ func registerRoutes(e *echo.Echo, handler api.Handler) { e.PUT("/games/:id/edit", handler.EditGame) e.DELETE("/games/:id", handler.DeleteGame) - e.POST("/games/:id/rounds", handler.AddRound) + e.POST("/games/:id/rounds", handler.AddRound) + e.GET("/games/:gameid/rounds/:roundid", handler.GetEditRoundForm) + e.PUT("/games/:gameid/rounds/:roundid", handler.EditRound) + e.DELETE("/games/:gameid/rounds/:roundid", handler.DeleteRound) } func createTables(db *sql.DB) error { _, err := db.Exec(` diff --git a/templates/components/create_game_form.templ b/templates/components/create_game_form.templ index 1cab628..42b5cbd 100644 --- a/templates/components/create_game_form.templ +++ b/templates/components/create_game_form.templ @@ -1,7 +1,7 @@ package components templ CreateGameForm() { -