Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
15 changes: 11 additions & 4 deletions internal/api/createparse.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,12 +109,19 @@ func ParseClientsPerIPLimit(cfg *config.Config, value string) (int, error) {
// ParseCustomWordsPerTurn checks whether the given value is an integer between
// 0 and 100. All other invalid input, including empty strings, will return an
// error.
func ParseCustomWordsPerTurn(value string) (int, error) {
return parseIntValue(value, 1, 3, "custom words per turn")
func ParseCustomWordsPerTurn(cfg *config.Config, value string) (int, error) {
return parseIntValue(value, 1, cfg.LobbySettingBounds.MaxWordsPerTurn, "custom words per turn")
}

func ParseWordsPerTurn(cfg *config.Config, value string) (int, error) {
return parseIntValue(value, 1, cfg.LobbySettingBounds.MaxWordsPerTurn, "words per turn")
}

func newIntOutOfBounds(value, valueName string, lower, upper int) error {
return fmt.Errorf("the value '%s' must be an integer between %d and %d, but was: '%s'", valueName, lower, upper, value)
if upper != -1 {
return fmt.Errorf("the value '%s' must be an integer between %d and %d, but was: '%s'", valueName, lower, upper, value)
}
return fmt.Errorf("the value '%s' must be an integer larger than %d, but was: '%s'", valueName, lower, value)
}

func parseIntValue(toParse string, lower, upper int, valueName string) (int, error) {
Expand All @@ -125,7 +132,7 @@ func parseIntValue(toParse string, lower, upper int, valueName string) (int, err
value = int(parsed)
}

if value < lower || value > upper {
if value < lower || (upper > -1 && value > upper) {
return 0, newIntOutOfBounds(toParse, valueName, lower, upper)
}

Expand Down
51 changes: 49 additions & 2 deletions internal/api/createparse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"testing"

"github.com/scribble-rs/scribble.rs/internal/config"
"github.com/scribble-rs/scribble.rs/internal/game"
"golang.org/x/text/cases"
"golang.org/x/text/language"
)
Expand Down Expand Up @@ -177,6 +178,13 @@ func Test_parseCustomWords(t *testing.T) {
func Test_parseCustomWordsPerTurn(t *testing.T) {
t.Parallel()

cfg := &config.Config{
LobbySettingBounds: game.SettingBounds{
MinCustomWordsPerTurn: 1,
MinWordsPerTurn: 1,
MaxWordsPerTurn: 3,
},
}
tests := []struct {
name string
value string
Expand All @@ -185,7 +193,7 @@ func Test_parseCustomWordsPerTurn(t *testing.T) {
}{
{"empty value", "", 0, true},
{"space", " ", 0, true},
{"lesss than minimum, zero", "0", 0, true},
{"less than minimum, zero", "0", 0, true},
{"less than minimum, negative", "-1", 0, true},
{"more than maximum", "4", 0, true},
{"minimum", "1", 1, false},
Expand All @@ -196,7 +204,7 @@ func Test_parseCustomWordsPerTurn(t *testing.T) {
t.Run(testCase.name, func(t *testing.T) {
t.Parallel()

got, err := ParseCustomWordsPerTurn(testCase.value)
got, err := ParseCustomWordsPerTurn(cfg, testCase.value)
if (err != nil) != testCase.wantErr {
t.Errorf("parseCustomWordsPerTurn() error = %v, wantErr %v", err, testCase.wantErr)
return
Expand All @@ -208,6 +216,45 @@ func Test_parseCustomWordsPerTurn(t *testing.T) {
}
}

func Test_parseWordsPerTurn(t *testing.T) {
t.Parallel()

cfg := &config.Config{
LobbySettingBounds: game.SettingBounds{
MinCustomWordsPerTurn: 1,
MinWordsPerTurn: 1,
MaxWordsPerTurn: 3,
},
}
tests := []struct {
name string
value string
want int
wantErr bool
}{
{"empty value", "", 0, true},
{"space", " ", 0, true},
{"less than minimum, zero", "0", 0, true},
{"less than minimum, negative", "-1", 0, true},
{"minimum", "1", 1, false},
{"something valid", "10", 10, false},
}
for _, testCase := range tests {
t.Run(testCase.name, func(t *testing.T) {
t.Parallel()

got, err := ParseWordsPerTurn(cfg, testCase.value)
if (err != nil) != testCase.wantErr {
t.Errorf("ParseWordsPerTurn() error = %v, wantErr %v", err, testCase.wantErr)
return
}
if got != testCase.want {
t.Errorf("ParseWordsPerTurn() = %v, want %v", got, testCase.want)
}
})
}
}

func Test_parseBoolean(t *testing.T) {
t.Parallel()

Expand Down
33 changes: 29 additions & 4 deletions internal/api/v1.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,14 @@ func (handler *V1Handler) postLobby(writer http.ResponseWriter, request *http.Re
drawingTime, drawingTimeInvalid := ParseDrawingTime(handler.cfg, request.Form.Get("drawing_time"))
rounds, roundsInvalid := ParseRounds(handler.cfg, request.Form.Get("rounds"))
maxPlayers, maxPlayersInvalid := ParseMaxPlayers(handler.cfg, request.Form.Get("max_players"))
customWordsPerTurn, customWordsPerTurnInvalid := ParseCustomWordsPerTurn(request.Form.Get("custom_words_per_turn"))
customWordsPerTurn, customWordsPerTurnInvalid := ParseCustomWordsPerTurn(handler.cfg, request.Form.Get("custom_words_per_turn"))
clientsPerIPLimit, clientsPerIPLimitInvalid := ParseClientsPerIPLimit(handler.cfg, request.Form.Get("clients_per_ip_limit"))
publicLobby, publicLobbyInvalid := ParseBoolean("public", request.Form.Get("public"))
wordsPerTurn, wordsPerTurnInvalid := ParseWordsPerTurn(handler.cfg, request.Form.Get("words_per_turn"))

if wordsPerTurn < customWordsPerTurn {
wordsPerTurnInvalid = errors.New("words per turn must be greater than or equal to custom words per turn")
}

var lowercaser cases.Caser
if languageInvalid != nil {
Expand Down Expand Up @@ -157,16 +162,27 @@ func (handler *V1Handler) postLobby(writer http.ResponseWriter, request *http.Re
if publicLobbyInvalid != nil {
requestErrors = append(requestErrors, publicLobbyInvalid.Error())
}
if wordsPerTurnInvalid != nil {
requestErrors = append(requestErrors, wordsPerTurnInvalid.Error())
}

if len(requestErrors) != 0 {
http.Error(writer, strings.Join(requestErrors, ";"), http.StatusBadRequest)
return
}

playerName := GetPlayername(request)
lobbySettings := &game.EditableLobbySettings{
Rounds: rounds,
DrawingTime: drawingTime,
MaxPlayers: maxPlayers,
CustomWordsPerTurn: customWordsPerTurn,
ClientsPerIPLimit: clientsPerIPLimit,
Public: publicLobby,
WordsPerTurn: wordsPerTurn,
}
player, lobby, err := game.CreateLobby(lobbyId, playerName,
languageKey, publicLobby, drawingTime, rounds, maxPlayers,
customWordsPerTurn, clientsPerIPLimit, customWords, scoreCalculation)
languageKey, lobbySettings, customWords, scoreCalculation)
if err != nil {
http.Error(writer, err.Error(), http.StatusBadRequest)
return
Expand Down Expand Up @@ -359,9 +375,14 @@ func (handler *V1Handler) patchLobby(writer http.ResponseWriter, request *http.R
maxPlayers, maxPlayersInvalid := ParseMaxPlayers(handler.cfg, request.Form.Get("max_players"))
drawingTime, drawingTimeInvalid := ParseDrawingTime(handler.cfg, request.Form.Get("drawing_time"))
rounds, roundsInvalid := ParseRounds(handler.cfg, request.Form.Get("rounds"))
customWordsPerTurn, customWordsPerTurnInvalid := ParseCustomWordsPerTurn(request.Form.Get("custom_words_per_turn"))
customWordsPerTurn, customWordsPerTurnInvalid := ParseCustomWordsPerTurn(handler.cfg, request.Form.Get("custom_words_per_turn"))
clientsPerIPLimit, clientsPerIPLimitInvalid := ParseClientsPerIPLimit(handler.cfg, request.Form.Get("clients_per_ip_limit"))
publicLobby, publicLobbyInvalid := ParseBoolean("public", request.Form.Get("public"))
wordsPerTurn, wordsPerTurnInvalid := ParseWordsPerTurn(handler.cfg, request.Form.Get("words_per_turn"))

if wordsPerTurn < customWordsPerTurn {
wordsPerTurnInvalid = errors.New("words per turn must be greater than or equal to custom words per turn")
}

owner := lobby.GetOwner()
if owner == nil || owner.GetUserSession() != userSession {
Expand Down Expand Up @@ -392,6 +413,9 @@ func (handler *V1Handler) patchLobby(writer http.ResponseWriter, request *http.R
if publicLobbyInvalid != nil {
requestErrors = append(requestErrors, publicLobbyInvalid.Error())
}
if wordsPerTurnInvalid != nil {
requestErrors = append(requestErrors, wordsPerTurnInvalid.Error())
}

if len(requestErrors) != 0 {
http.Error(writer, strings.Join(requestErrors, ";"), http.StatusBadRequest)
Expand All @@ -410,6 +434,7 @@ func (handler *V1Handler) patchLobby(writer http.ResponseWriter, request *http.R
lobby.ClientsPerIPLimit = clientsPerIPLimit
lobby.Public = publicLobby
lobby.Rounds = rounds
lobby.WordsPerTurn = wordsPerTurn

if lobby.State == game.Ongoing {
lobby.DrawingTimeNew = drawingTime
Expand Down
5 changes: 4 additions & 1 deletion internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ type LobbySettingDefaults struct {
ClientsPerIPLimit string `env:"CLIENTS_PER_IP_LIMIT"`
Language string `env:"LANGUAGE"`
ScoreCalculation string `env:"SCORE_CALCULATION"`
WordsPerTurn string `env:"WORDS_PER_TURN"`
}

type CORS struct {
Expand Down Expand Up @@ -86,6 +87,7 @@ var Default = Config{
ClientsPerIPLimit: "2",
Language: "english",
ScoreCalculation: "chill",
WordsPerTurn: "3",
},
LobbySettingBounds: game.SettingBounds{
MinDrawingTime: 60,
Expand All @@ -97,7 +99,8 @@ var Default = Config{
MinClientsPerIPLimit: 1,
MaxClientsPerIPLimit: 24,
MinCustomWordsPerTurn: 1,
MaxCustomWordsPerTurn: 3,
MaxWordsPerTurn: 6,
MinWordsPerTurn: 1,
},
CORS: CORS{
AllowedOrigins: []string{"*"},
Expand Down
27 changes: 23 additions & 4 deletions internal/frontend/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
//nolint:gosec //We just use this for cache busting, so it's secure enough

"crypto/md5"
"errors"
"fmt"
"log"
"net/http"
Expand Down Expand Up @@ -188,9 +189,14 @@ func (handler *SSRHandler) ssrCreateLobby(writer http.ResponseWriter, request *h
drawingTime, drawingTimeInvalid := api.ParseDrawingTime(handler.cfg, request.Form.Get("drawing_time"))
rounds, roundsInvalid := api.ParseRounds(handler.cfg, request.Form.Get("rounds"))
maxPlayers, maxPlayersInvalid := api.ParseMaxPlayers(handler.cfg, request.Form.Get("max_players"))
customWordsPerTurn, customWordsPerTurnInvalid := api.ParseCustomWordsPerTurn(request.Form.Get("custom_words_per_turn"))
customWordsPerTurn, customWordsPerTurnInvalid := api.ParseCustomWordsPerTurn(handler.cfg, request.Form.Get("custom_words_per_turn"))
clientsPerIPLimit, clientsPerIPLimitInvalid := api.ParseClientsPerIPLimit(handler.cfg, request.Form.Get("clients_per_ip_limit"))
publicLobby, publicLobbyInvalid := api.ParseBoolean("public", request.Form.Get("public"))
wordsPerTurn, wordsPerTurnInvalid := api.ParseWordsPerTurn(handler.cfg, request.Form.Get("words_per_turn"))

if wordsPerTurn < customWordsPerTurn {
wordsPerTurnInvalid = errors.New("words per turn must be greater than or equal to custom words per turn")
}

var lowercaser cases.Caser
if languageInvalid != nil {
Expand All @@ -215,8 +221,10 @@ func (handler *SSRHandler) ssrCreateLobby(writer http.ResponseWriter, request *h
ClientsPerIPLimit: request.Form.Get("clients_per_ip_limit"),
Language: request.Form.Get("language"),
ScoreCalculation: request.Form.Get("score_calculation"),
WordsPerTurn: request.Form.Get("words_per_turn"),
},
Languages: game.SupportedLanguages,
Languages: game.SupportedLanguages,
ScoreCalculations: game.SupportedScoreCalculations,
}

if scoreCalculationInvalid != nil {
Expand Down Expand Up @@ -246,6 +254,9 @@ func (handler *SSRHandler) ssrCreateLobby(writer http.ResponseWriter, request *h
if publicLobbyInvalid != nil {
pageData.Errors = append(pageData.Errors, publicLobbyInvalid.Error())
}
if wordsPerTurnInvalid != nil {
pageData.Errors = append(pageData.Errors, wordsPerTurnInvalid.Error())
}

translation, locale := determineTranslation(request)
pageData.Translation = translation
Expand All @@ -270,9 +281,17 @@ func (handler *SSRHandler) ssrCreateLobby(writer http.ResponseWriter, request *h
clientsPerIPLimit = maxPlayers
}

lobbySettings := &game.EditableLobbySettings{
Rounds: rounds,
DrawingTime: drawingTime,
MaxPlayers: maxPlayers,
CustomWordsPerTurn: customWordsPerTurn,
ClientsPerIPLimit: clientsPerIPLimit,
Public: publicLobby,
WordsPerTurn: wordsPerTurn,
}
player, lobby, err := game.CreateLobby(lobbyId, playerName, languageKey,
publicLobby, drawingTime, rounds, maxPlayers, customWordsPerTurn,
clientsPerIPLimit, customWords, scoreCalculation)
lobbySettings, customWords, scoreCalculation)
if err != nil {
pageData.Errors = append(pageData.Errors, err.Error())
if err := pageTemplates.ExecuteTemplate(writer, "index", pageData); err != nil {
Expand Down
17 changes: 11 additions & 6 deletions internal/frontend/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,17 +100,18 @@ const set_lobbies = (lobbies, visible) => {
const lobby_list_item = document.createElement("div");
lobby_list_item.className = "lobby-list-item";

const language_flag = document.createElement("span");
language_flag.className = "language-flag";
language_flag.setAttribute("title", lobby.wordpack);
language_flag.setAttribute("english", lobby.wordpack);
language_flag.innerText = language_to_flag(lobby.wordpack);

const lobby_list_rows = document.createElement("div");
lobby_list_rows.className = "lobby-list-rows";

const lobby_list_row_a = document.createElement("div");
lobby_list_row_a.className = "lobby-list-row";

const language_flag = document.createElement("span");
language_flag.className = "language-flag";
language_flag.innerText = language_to_flag(lobby.wordpack);
lobby_list_row_a.appendChild(language_flag);

const new_custom_tag = (text) => {
const tag = document.createElement("span");
tag.className = "custom-tag";
Expand Down Expand Up @@ -188,7 +189,11 @@ const set_lobbies = (lobbies, visible) => {
window.location.href = `{{.RootPath}}/lobby/${lobby.lobbyId}`;
});

lobby_list_item.replaceChildren(lobby_list_rows, join_button);
lobby_list_item.replaceChildren(
language_flag,
lobby_list_rows,
join_button,
);

return lobby_list_item;
});
Expand Down
Loading
Loading