generated from VLADIMIR/template
fix
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"evening_detective_server/internal/services/answer_service"
|
||||
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
func answerErrorStatus(err error, internalMessage string) error {
|
||||
switch {
|
||||
case errors.Is(err, answer_service.ErrTeamNotFound), errors.Is(err, answer_service.ErrGameNotFound):
|
||||
return status.Error(codes.NotFound, err.Error())
|
||||
case errors.Is(err, answer_service.ErrQuestionNotFound), errors.Is(err, answer_service.ErrOfflineAnswers):
|
||||
return status.Error(codes.InvalidArgument, err.Error())
|
||||
case errors.Is(err, answer_service.ErrGameFinished), errors.Is(err, answer_service.ErrGameNotStarted), errors.Is(err, answer_service.ErrGameNotFinished):
|
||||
return status.Error(codes.FailedPrecondition, err.Error())
|
||||
default:
|
||||
return status.Error(codes.Internal, internalMessage)
|
||||
}
|
||||
}
|
||||
@@ -17,9 +17,7 @@ func (s *server) GetTeamAnswers(ctx context.Context, req *proto.GetTeamAnswersRe
|
||||
req.Password,
|
||||
)
|
||||
if err != nil {
|
||||
return &proto.GetTeamAnswersRsp{
|
||||
Error: err.Error(),
|
||||
}, nil
|
||||
return nil, answerErrorStatus(err, "не удалось получить ответы команды")
|
||||
}
|
||||
|
||||
return &proto.GetTeamAnswersRsp{
|
||||
@@ -35,9 +33,7 @@ func (s *server) SubmitTeamAnswers(ctx context.Context, req *proto.SubmitTeamAns
|
||||
convertAnswers(req.Answers),
|
||||
)
|
||||
if err != nil {
|
||||
return &proto.SubmitTeamAnswersRsp{
|
||||
Error: err.Error(),
|
||||
}, nil
|
||||
return nil, answerErrorStatus(err, "не удалось сохранить ответы команды")
|
||||
}
|
||||
|
||||
return &proto.SubmitTeamAnswersRsp{}, nil
|
||||
@@ -65,9 +61,7 @@ func (s *server) SetTeamAnswerScore(ctx context.Context, req *proto.SetTeamAnswe
|
||||
score,
|
||||
)
|
||||
if err != nil {
|
||||
return &proto.SetTeamAnswerScoreRsp{
|
||||
Error: err.Error(),
|
||||
}, nil
|
||||
return nil, answerErrorStatus(err, "не удалось сохранить оценку ответа")
|
||||
}
|
||||
|
||||
return &proto.SetTeamAnswerScoreRsp{}, nil
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"evening_detective_server/internal/services/answer_service"
|
||||
"evening_detective_server/internal/services/game_service"
|
||||
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
func TestGameErrorStatus(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
name, message string
|
||||
err error
|
||||
code codes.Code
|
||||
}{
|
||||
{"not found", "Игра не найдена", game_service.ErrGameNotFound, codes.NotFound},
|
||||
{"invalid format", "Формат игры должен быть online или offline", game_service.ErrInvalidGameFormat, codes.InvalidArgument},
|
||||
{"internal", "не удалось получить игру", errors.New("private database detail"), codes.Internal},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
err := gameErrorStatus(tc.err, "не удалось получить игру")
|
||||
if status.Code(err) != tc.code || status.Convert(err).Message() != tc.message {
|
||||
t.Fatalf("status=%v, want %v %q", err, tc.code, tc.message)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAnswerErrorStatus(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
name, message string
|
||||
err error
|
||||
code codes.Code
|
||||
}{
|
||||
{"team not found", "Команда не найдена", answer_service.ErrTeamNotFound, codes.NotFound},
|
||||
{"question not found", "Вопрос не найден", answer_service.ErrQuestionNotFound, codes.InvalidArgument},
|
||||
{"game not started", "Игра не начата, отвечать на вопросы нельзя", answer_service.ErrGameNotStarted, codes.FailedPrecondition},
|
||||
{"internal", "не удалось получить ответы игры", errors.New("private database detail"), codes.Internal},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
err := answerErrorStatus(tc.err, "не удалось получить ответы игры")
|
||||
if status.Code(err) != tc.code || status.Convert(err).Message() != tc.message {
|
||||
t.Fatalf("status=%v, want %v %q", err, tc.code, tc.message)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"evening_detective_server/internal/services/game_service"
|
||||
"evening_detective_server/internal/services/scenarios_service"
|
||||
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
func gameErrorStatus(err error, internalMessage string) error {
|
||||
switch {
|
||||
case errors.Is(err, game_service.ErrGameNotFound), errors.Is(err, scenarios_service.ErrScenarioNotFound):
|
||||
return status.Error(codes.NotFound, err.Error())
|
||||
case errors.Is(err, game_service.ErrInvalidGameFormat):
|
||||
return status.Error(codes.InvalidArgument, err.Error())
|
||||
default:
|
||||
return status.Error(codes.Internal, internalMessage)
|
||||
}
|
||||
}
|
||||
+12
-36
@@ -40,9 +40,7 @@ func (s *server) AddGame(ctx context.Context, req *proto.AddGameReq) (*proto.Add
|
||||
req.Format,
|
||||
)
|
||||
if err != nil {
|
||||
return &proto.AddGameRsp{
|
||||
Error: err.Error(),
|
||||
}, nil
|
||||
return nil, gameErrorStatus(err, "не удалось создать игру")
|
||||
}
|
||||
|
||||
return &proto.AddGameRsp{
|
||||
@@ -64,9 +62,7 @@ func (s *server) DeleteGame(ctx context.Context, req *proto.DeleteGameReq) (*pro
|
||||
int(req.ID),
|
||||
)
|
||||
if err != nil {
|
||||
return &proto.DeleteGameRsp{
|
||||
Error: err.Error(),
|
||||
}, nil
|
||||
return nil, gameErrorStatus(err, "не удалось удалить игру")
|
||||
}
|
||||
|
||||
return &proto.DeleteGameRsp{}, nil
|
||||
@@ -83,9 +79,7 @@ func (s *server) GetGame(ctx context.Context, req *proto.GetGameReq) (*proto.Get
|
||||
|
||||
game, err := s.gameService.GetFullGame(ctx, int(req.ID))
|
||||
if err != nil {
|
||||
return &proto.GetGameRsp{
|
||||
Error: err.Error(),
|
||||
}, nil
|
||||
return nil, gameErrorStatus(err, "не удалось получить игру")
|
||||
}
|
||||
|
||||
return &proto.GetGameRsp{
|
||||
@@ -104,9 +98,7 @@ func (s *server) GetGameAnswers(ctx context.Context, req *proto.GetGameAnswersRe
|
||||
|
||||
gameAnswers, err := s.answerService.GetGameAnswers(ctx, int(req.GameID))
|
||||
if err != nil {
|
||||
return &proto.GetGameAnswersRsp{
|
||||
Error: err.Error(),
|
||||
}, nil
|
||||
return nil, answerErrorStatus(err, "не удалось получить ответы игры")
|
||||
}
|
||||
|
||||
return &proto.GetGameAnswersRsp{
|
||||
@@ -126,9 +118,7 @@ func (s *server) GetGameResults(ctx context.Context, req *proto.GetGameResultsRe
|
||||
|
||||
results, err := s.answerService.GetGameResults(ctx, int(req.GameID))
|
||||
if err != nil {
|
||||
return &proto.GetGameResultsRsp{
|
||||
Error: err.Error(),
|
||||
}, nil
|
||||
return nil, answerErrorStatus(err, "не удалось получить результаты игры")
|
||||
}
|
||||
|
||||
return &proto.GetGameResultsRsp{
|
||||
@@ -148,9 +138,7 @@ func (s *server) GetGames(ctx context.Context, req *proto.GetGamesReq) (*proto.G
|
||||
|
||||
games, err := s.gameService.GetGames(ctx)
|
||||
if err != nil {
|
||||
return &proto.GetGamesRsp{
|
||||
Error: err.Error(),
|
||||
}, nil
|
||||
return nil, gameErrorStatus(err, "не удалось получить игры")
|
||||
}
|
||||
|
||||
return &proto.GetGamesRsp{
|
||||
@@ -182,9 +170,7 @@ func (s *server) UpdateGame(ctx context.Context, req *proto.UpdateGameReq) (*pro
|
||||
req.Format,
|
||||
)
|
||||
if err != nil {
|
||||
return &proto.UpdateGameRsp{
|
||||
Error: err.Error(),
|
||||
}, nil
|
||||
return nil, gameErrorStatus(err, "не удалось изменить игру")
|
||||
}
|
||||
|
||||
return &proto.UpdateGameRsp{}, nil
|
||||
@@ -201,9 +187,7 @@ func (s *server) StartGame(ctx context.Context, req *proto.StartGameReq) (*proto
|
||||
|
||||
err := s.gameService.StartGame(ctx, int(req.ID))
|
||||
if err != nil {
|
||||
return &proto.StartGameRsp{
|
||||
Error: err.Error(),
|
||||
}, nil
|
||||
return nil, gameErrorStatus(err, "не удалось запустить игру")
|
||||
}
|
||||
|
||||
return &proto.StartGameRsp{}, nil
|
||||
@@ -220,9 +204,7 @@ func (s *server) PauseGame(ctx context.Context, req *proto.PauseGameReq) (*proto
|
||||
|
||||
err := s.gameService.PauseGame(ctx, int(req.ID))
|
||||
if err != nil {
|
||||
return &proto.PauseGameRsp{
|
||||
Error: err.Error(),
|
||||
}, nil
|
||||
return nil, gameErrorStatus(err, "не удалось приостановить игру")
|
||||
}
|
||||
|
||||
return &proto.PauseGameRsp{}, nil
|
||||
@@ -239,9 +221,7 @@ func (s *server) PlayGame(ctx context.Context, req *proto.PlayGameReq) (*proto.P
|
||||
|
||||
err := s.gameService.PlayGame(ctx, int(req.ID))
|
||||
if err != nil {
|
||||
return &proto.PlayGameRsp{
|
||||
Error: err.Error(),
|
||||
}, nil
|
||||
return nil, gameErrorStatus(err, "не удалось продолжить игру")
|
||||
}
|
||||
|
||||
return &proto.PlayGameRsp{}, nil
|
||||
@@ -258,9 +238,7 @@ func (s *server) FinishGame(ctx context.Context, req *proto.FinishGameReq) (*pro
|
||||
|
||||
err := s.gameService.FinishGame(ctx, int(req.ID))
|
||||
if err != nil {
|
||||
return &proto.FinishGameRsp{
|
||||
Error: err.Error(),
|
||||
}, nil
|
||||
return nil, gameErrorStatus(err, "не удалось завершить игру")
|
||||
}
|
||||
|
||||
return &proto.FinishGameRsp{}, nil
|
||||
@@ -277,9 +255,7 @@ func (s *server) ResetGame(ctx context.Context, req *proto.ResetGameReq) (*proto
|
||||
|
||||
err := s.gameService.ResetGame(ctx, int(req.ID))
|
||||
if err != nil {
|
||||
return &proto.ResetGameRsp{
|
||||
Error: err.Error(),
|
||||
}, nil
|
||||
return nil, gameErrorStatus(err, "не удалось сбросить игру")
|
||||
}
|
||||
|
||||
return &proto.ResetGameRsp{}, nil
|
||||
|
||||
@@ -38,6 +38,10 @@ func NewAnswerService(
|
||||
}
|
||||
|
||||
var (
|
||||
// ErrTeamNotFound — команда не найдена или пароль неверен.
|
||||
ErrTeamNotFound = errors.New("Команда не найдена")
|
||||
// ErrGameNotFound — игра не найдена.
|
||||
ErrGameNotFound = errors.New("Игра не найдена")
|
||||
// ErrGameFinished — после завершения игры ответы команд больше нельзя
|
||||
// изменять: организатор оценивает их в панели игры.
|
||||
ErrGameFinished = errors.New("Игра завершена, ответы больше нельзя изменять")
|
||||
@@ -47,19 +51,27 @@ var (
|
||||
ErrQuestionNotFound = errors.New("Вопрос не найден")
|
||||
// ErrGameNotFinished — итоги игры доступны только после её завершения.
|
||||
ErrGameNotFinished = errors.New("Итоги доступны после завершения игры")
|
||||
// ErrOfflineAnswers — ответы для offline-игры недоступны через сайт.
|
||||
ErrOfflineAnswers = errors.New("В offline-игре ответы через сайт недоступны")
|
||||
)
|
||||
|
||||
// getTeamAndGame проверяет команду по паролю и возвращает её вместе с игрой.
|
||||
func (s *AnswerService) getTeamAndGame(ctx context.Context, teamID int, password string) (*repos.Team, *repos.Game, error) {
|
||||
team, err := s.teamsRepo.GetTeamByID(ctx, teamID)
|
||||
if err != nil {
|
||||
if errors.Is(err, teams_repo.ErrTeamNotFound) {
|
||||
return nil, nil, ErrTeamNotFound
|
||||
}
|
||||
return nil, nil, err
|
||||
}
|
||||
if team.Password != password || team.ParticipationStatus == "cancelled" {
|
||||
return nil, nil, teams_repo.ErrTeamNotFound
|
||||
return nil, nil, ErrTeamNotFound
|
||||
}
|
||||
game, err := s.gamesRepo.GetGameByID(ctx, team.GameID)
|
||||
if err != nil {
|
||||
if errors.Is(err, games_repo.ErrGameNotFound) {
|
||||
return nil, nil, ErrGameNotFound
|
||||
}
|
||||
return nil, nil, err
|
||||
}
|
||||
return team, game, nil
|
||||
@@ -120,7 +132,7 @@ func (s *AnswerService) SubmitTeamAnswers(ctx context.Context, teamID int, passw
|
||||
return err
|
||||
}
|
||||
if game.Format == "offline" {
|
||||
return errors.New("В offline-игре ответы через сайт недоступны")
|
||||
return ErrOfflineAnswers
|
||||
}
|
||||
switch game.Status {
|
||||
case "run", "pause":
|
||||
@@ -157,7 +169,7 @@ func (s *AnswerService) SubmitTeamAnswers(ctx context.Context, teamID int, passw
|
||||
func (s *AnswerService) GetGameAnswers(ctx context.Context, gameID int) (*GameAnswers, error) {
|
||||
game, err := s.gamesRepo.GetGameByID(ctx, gameID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, mapAnswerError(err)
|
||||
}
|
||||
questions, byCode, err := s.getScenarioQuestionsByCode(ctx, game.ScenarioID)
|
||||
if err != nil {
|
||||
@@ -227,11 +239,11 @@ func (s *AnswerService) GetGameAnswers(ctx context.Context, gameID int) (*GameAn
|
||||
func (s *AnswerService) SetTeamAnswerScore(ctx context.Context, teamID int, questionCode string, score *int) error {
|
||||
team, err := s.teamsRepo.GetTeamByID(ctx, teamID)
|
||||
if err != nil {
|
||||
return err
|
||||
return mapAnswerError(err)
|
||||
}
|
||||
game, err := s.gamesRepo.GetGameByID(ctx, team.GameID)
|
||||
if err != nil {
|
||||
return err
|
||||
return mapAnswerError(err)
|
||||
}
|
||||
_, byCode, err := s.getScenarioQuestionsByCode(ctx, game.ScenarioID)
|
||||
if err != nil {
|
||||
@@ -251,7 +263,7 @@ func (s *AnswerService) SetTeamAnswerScore(ctx context.Context, teamID int, ques
|
||||
func (s *AnswerService) GetGameResults(ctx context.Context, gameID int) (*GameResults, error) {
|
||||
game, err := s.gamesRepo.GetGameByID(ctx, gameID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, mapAnswerError(err)
|
||||
}
|
||||
if game.Status != "finish" {
|
||||
return nil, ErrGameNotFinished
|
||||
@@ -301,3 +313,13 @@ func (s *AnswerService) GetGameResults(ctx context.Context, gameID int) (*GameRe
|
||||
Teams: rankTeams(buildTeamResults(questions, mappedTeams, answerByTeamAndCode)),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func mapAnswerError(err error) error {
|
||||
if errors.Is(err, teams_repo.ErrTeamNotFound) {
|
||||
return ErrTeamNotFound
|
||||
}
|
||||
if errors.Is(err, games_repo.ErrGameNotFound) {
|
||||
return ErrGameNotFound
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -23,6 +23,13 @@ type GameService struct {
|
||||
applicationsRepo *applications_repo.ApplicationsRepo
|
||||
}
|
||||
|
||||
var (
|
||||
// ErrGameNotFound — игра не найдена.
|
||||
ErrGameNotFound = errors.New("Игра не найдена")
|
||||
// ErrInvalidGameFormat — формат игры не поддерживается.
|
||||
ErrInvalidGameFormat = errors.New("Формат игры должен быть online или offline")
|
||||
)
|
||||
|
||||
func NewGameService(
|
||||
gamesRepo *games_repo.GamesRepo,
|
||||
teamsRepo *teams_repo.TeamsRepo,
|
||||
@@ -56,7 +63,7 @@ func (s *GameService) AddGame(
|
||||
format = "online"
|
||||
}
|
||||
if format != "online" && format != "offline" {
|
||||
return 0, errors.New("Формат игры должен быть online или offline")
|
||||
return 0, ErrInvalidGameFormat
|
||||
}
|
||||
id, err := s.gamesRepo.AddGame(ctx, name, description, location, startAt, scenarioID, format)
|
||||
if err != nil {
|
||||
@@ -68,7 +75,7 @@ func (s *GameService) AddGame(
|
||||
func (s *GameService) GetGame(ctx context.Context, id int) (*game_model.Game, error) {
|
||||
game, err := s.gamesRepo.GetGameByID(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, mapGameError(err)
|
||||
}
|
||||
res := game_model.MapGame(game, s.domain)
|
||||
return res, nil
|
||||
@@ -77,7 +84,7 @@ func (s *GameService) GetGame(ctx context.Context, id int) (*game_model.Game, er
|
||||
func (s *GameService) GetGameMedia(ctx context.Context, id int) (*game_model.Game, error) {
|
||||
game, err := s.gamesRepo.GetGameByID(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, mapGameError(err)
|
||||
}
|
||||
gameResult := game_model.MapGame(game, s.domain)
|
||||
gameResult.Scenario, err = s.scenarioService.GetFullScenarioByID(ctx, game.ScenarioID)
|
||||
@@ -93,10 +100,13 @@ func (s *GameService) GetFullGame(
|
||||
) (*game_model.Game, error) {
|
||||
game, err := s.gamesRepo.GetGameByID(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, mapGameError(err)
|
||||
}
|
||||
scenario, err := s.scenariosRepo.GetScenarioByID(ctx, game.ScenarioID)
|
||||
if err != nil {
|
||||
if errors.Is(err, scenarios_repo.ErrScenarioNotFound) {
|
||||
return nil, scenarios_service.ErrScenarioNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
game.Scenario = scenario
|
||||
@@ -135,7 +145,7 @@ func (s *GameService) DeleteGame(
|
||||
ctx context.Context,
|
||||
id int,
|
||||
) error {
|
||||
return s.gamesRepo.DeleteGameByID(ctx, id)
|
||||
return mapGameError(s.gamesRepo.DeleteGameByID(ctx, id))
|
||||
}
|
||||
|
||||
func (s *GameService) GetGames(
|
||||
@@ -161,32 +171,39 @@ func (s *GameService) UpdateGame(
|
||||
if format == "" {
|
||||
game, err := s.gamesRepo.GetGameByID(ctx, id)
|
||||
if err != nil {
|
||||
return err
|
||||
return mapGameError(err)
|
||||
}
|
||||
format = game.Format
|
||||
}
|
||||
if format != "online" && format != "offline" {
|
||||
return errors.New("Формат игры должен быть online или offline")
|
||||
return ErrInvalidGameFormat
|
||||
}
|
||||
return s.gamesRepo.UpdateGame(ctx, id, name, description, location, startAt, scenarioID, format)
|
||||
return mapGameError(s.gamesRepo.UpdateGame(ctx, id, name, description, location, startAt, scenarioID, format))
|
||||
}
|
||||
|
||||
func (s *GameService) StartGame(ctx context.Context, id int) error {
|
||||
return s.gamesRepo.StartGame(ctx, id)
|
||||
return mapGameError(s.gamesRepo.StartGame(ctx, id))
|
||||
}
|
||||
|
||||
func (s *GameService) PauseGame(ctx context.Context, id int) error {
|
||||
return s.gamesRepo.PauseGame(ctx, id)
|
||||
return mapGameError(s.gamesRepo.PauseGame(ctx, id))
|
||||
}
|
||||
|
||||
func (s *GameService) PlayGame(ctx context.Context, id int) error {
|
||||
return s.gamesRepo.PlayGame(ctx, id)
|
||||
return mapGameError(s.gamesRepo.PlayGame(ctx, id))
|
||||
}
|
||||
|
||||
func (s *GameService) FinishGame(ctx context.Context, id int) error {
|
||||
return s.gamesRepo.FinishGame(ctx, id)
|
||||
return mapGameError(s.gamesRepo.FinishGame(ctx, id))
|
||||
}
|
||||
|
||||
func (s *GameService) ResetGame(ctx context.Context, id int) error {
|
||||
return s.gamesRepo.ResetGame(ctx, id)
|
||||
return mapGameError(s.gamesRepo.ResetGame(ctx, id))
|
||||
}
|
||||
|
||||
func mapGameError(err error) error {
|
||||
if errors.Is(err, games_repo.ErrGameNotFound) {
|
||||
return ErrGameNotFound
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user