package flags import ( "context" "database/sql" "net/http" "strconv" "time" "git.tijl.dev/tijl/tijl.dev-core/internal/queries" "git.tijl.dev/tijl/tijl.dev-core/internal/user" "git.tijl.dev/tijl/tijl.dev-core/internal/utils" "git.tijl.dev/tijl/tijl.dev-core/modules/db" "git.tijl.dev/tijl/tijl.dev-core/modules/i18n" "git.tijl.dev/tijl/tijl.dev-core/modules/web" "github.com/enescakir/emoji" "github.com/gofiber/fiber/v2" "github.com/google/uuid" ) const flagSessionCookie string = "app_flags_game_session" func answerHandler(c *fiber.Ctx) error { gameId, err := uuid.Parse(c.Cookies(flagSessionCookie)) if err != nil { return err } answer := c.FormValue("answer") gameSession, err := db.Queries.AppFlagsGetGame(context.TODO(), gameId) if err != nil { return err } err, countries := filterCountriesByTags(gameSession.Tags) if err != nil { return err } shuffledCountries := shuffleSlice(countries, gameSession.GameSeed.String()) correctAnswer := shuffledCountries[gameSession.QuestionCurrent-1] if answer == correctAnswer { db.Queries.AppFlagsUpdateGame(context.TODO(), queries.AppFlagsUpdateGameParams{ GameID: gameId, QuestionCurrent: gameSession.QuestionCurrent + 1, }) db.Queries.AppFlagsUpsertGameAnswer(context.TODO(), queries.AppFlagsUpsertGameAnswerParams{ GameID: gameId, Question: gameSession.QuestionCurrent, Errors: 0, }) } else { db.Queries.AppFlagsUpsertGameAnswer(context.TODO(), queries.AppFlagsUpsertGameAnswerParams{ GameID: gameId, Question: gameSession.QuestionCurrent, Errors: 1, }) } err = db.Queries.AppFlagsUpdateQuestionCorrect(context.TODO(), gameId) if err != nil { return err } return questionHandler(c, NewGameUUID{}) } type NewGameUUID struct { uuid.UUID used bool } func questionHandler(c *fiber.Ctx, newGame NewGameUUID) error { var gameId uuid.UUID var err error if newGame.used { gameId = newGame.UUID } else { gameId, err = uuid.Parse(c.Cookies(flagSessionCookie)) if err != nil { return err } } gameSession, err := db.Queries.AppFlagsGetGame(context.TODO(), gameId) if err != nil { return err } uid, err := user.GetSession(c) if uid != gameSession.Uid.String { utils.ClearCookie(c, flagSessionCookie) return gameStartHandler(c) } if (gameSession.QuestionAmount != 0) && (gameSession.QuestionAmount+1 == gameSession.QuestionCurrent) { return gameEndHandler(c) } err, countries := filterCountriesByTags(gameSession.Tags) if err != nil { return err } if int(gameSession.QuestionCurrent) == len(countries) { return gameEndHandler(c) } shuffledCountries := shuffleSlice(countries, gameSession.GameSeed.String()) shuffledAnswers := shuffleSlice(countries, gameSession.GameSeed.String()+string(gameSession.QuestionCurrent)) shuffledAnswers = shuffledAnswers[0:4] // 4 random aswers shuffledAnswers = append(shuffledAnswers, shuffledCountries[gameSession.QuestionCurrent-1]) // add correct answer shuffledAnswers = shuffleSlice(shuffledAnswers, gameSession.GameSeed.String()+string(gameSession.QuestionCurrent)) // shuffle again if gameSession.QuestionAmount != 0 && int(gameSession.QuestionAmount) < len(countries) { shuffledCountries = shuffledCountries[0:gameSession.QuestionAmount] } var timeleft = []string{} if gameSession.Seconds != 0 { timeleft = append(timeleft, strconv.Itoa(int(gameSession.Seconds)-int(time.Since(gameSession.CreatedAt).Seconds()))) } flag, err := emoji.CountryFlag(shuffledCountries[gameSession.QuestionCurrent-1]) if err != nil { return err } data := *web.Common(c) data["Title"] = "tmp" data["TimeLeft"] = timeleft data["QuestionsLeft"] = len(shuffledCountries) - int(gameSession.QuestionCurrent) + 1 data["Answers"] = shuffledAnswers data["Flag"] = flag data["Errors"] = gameSession.QuestionsErrors return c.Render("apps/flags/question", data, "layouts/base") } func sharedGameHandler(c *fiber.Ctx) error { shareKey := c.FormValue("sharekey") data, err := db.Queries.AppFlagsGetSharedData(context.TODO(), shareKey) if err != nil { return err } return setupGame(c, data.Tags, int(data.Questions), int(data.Seconds), true, data.GameSeed) } func startNewGameHandler(c *fiber.Ctx) error { values := c.Request().PostArgs().PeekMulti("tags") var selectedTags []string for _, v := range values { selectedTags = append(selectedTags, string(v)) } if len(selectedTags) < 1 { return c.Status(http.StatusBadRequest).SendString(i18n.GetTranslations(i18n.GetLanguage(c))["select_more_countries"]) } err, countries := filterCountriesByTags(selectedTags) if err != nil { return err } if len(countries) < 6 { return c.Status(http.StatusBadRequest).SendString(i18n.GetTranslations(i18n.GetLanguage(c))["select_more_countries"]) } maxQuestions, err := strconv.Atoi(c.FormValue("max_questions")) if err != nil { return err } seconds, err := strconv.Atoi(c.FormValue("seconds")) if err != nil { return err } if c.FormValue("share") != "" { return createSharedGameData(c, selectedTags, maxQuestions, seconds) } return setupGame(c, selectedTags, maxQuestions, seconds, false, uuid.UUID{}) } func createSharedGameData(c *fiber.Ctx, tags []string, maxQuestions int, seconds int) error { shareKey := utils.RandString(4) _, err := db.Queries.AppFlagsNewSharedData(context.TODO(), queries.AppFlagsNewSharedDataParams{ ShareKey: shareKey, Tags: tags, Questions: int32(maxQuestions), Seconds: int32(seconds), }) if err != nil { return err } data := *web.Common(c) data["Title"] = "tmp" data["ShareKey"] = shareKey return c.Render("apps/flags/shared", data, "layouts/base") } func setupGame(c *fiber.Ctx, tags []string, maxQuestions int, seconds int, useGameSeed bool, gameSeed uuid.UUID) error { var Quid = sql.NullString{} uid, err := user.GetSession(c) if err == nil { Quid.Valid = true Quid.String = uid } createGameParams := queries.AppFlagsCreateGameWithSeedParams{ Uid: Quid, Tags: tags, QuestionAmount: int32(maxQuestions), Seconds: int32(seconds), GameSeed: uuid.New(), } if useGameSeed { createGameParams.GameSeed = gameSeed } gameID, err := db.Queries.AppFlagsCreateGameWithSeed(context.TODO(), createGameParams) if err != nil { return err } c.Cookie(&fiber.Cookie{ Name: flagSessionCookie, Value: gameID.String(), //Secure: true, }) return questionHandler(c, NewGameUUID{used: true, UUID: gameID}) } func gameEndHandler(c *fiber.Ctx) error { gameId, err := uuid.Parse(c.Cookies(flagSessionCookie)) if err != nil { return err } gameSession, err := db.Queries.AppFlagsGetGame(context.TODO(), gameId) if err != nil { return err } data := *web.Common(c) data["Title"] = "tmp" data["Errors"] = gameSession.QuestionsErrors return c.Render("apps/flags/end", data, "layouts/base") } func stopGameHandler(c *fiber.Ctx) error { // exit game utils.ClearCookie(c, flagSessionCookie) return gameStartHandler(c) } func gameStartHandler(c *fiber.Ctx) error { data := *web.Common(c) data["Title"] = "tmp" data["SupportedTags"] = supportedTags return c.Render("apps/flags/start", data, "layouts/base") }