diff --git a/api/main.proto b/api/main.proto index d70a1e7..bc2e82a 100644 --- a/api/main.proto +++ b/api/main.proto @@ -1774,9 +1774,10 @@ message DeleteGameRsp { } message AddTeamReq { - int32 gameID = 1; - string name = 2; - string captain_email = 3; + int32 gameID = 1; + string name = 2; + string captain_email = 3; + int32 participants_count = 4; } message AddTeamRsp { diff --git a/bin/evening_detective_server b/bin/evening_detective_server index 80952cb..cb2d40f 100755 Binary files a/bin/evening_detective_server and b/bin/evening_detective_server differ diff --git a/cmd/evening_detective_server/main.swagger.json b/cmd/evening_detective_server/main.swagger.json index 86ee02e..a9e22ad 100644 --- a/cmd/evening_detective_server/main.swagger.json +++ b/cmd/evening_detective_server/main.swagger.json @@ -3457,6 +3457,10 @@ }, "captainEmail": { "type": "string" + }, + "participantsCount": { + "type": "integer", + "format": "int32" } } }, diff --git a/internal/app/teams.go b/internal/app/teams.go index e251756..6607f69 100644 --- a/internal/app/teams.go +++ b/internal/app/teams.go @@ -27,6 +27,7 @@ func (s *server) AddTeam(ctx context.Context, req *proto.AddTeamReq) (*proto.Add int(req.GameID), req.Name, req.CaptainEmail, + req.ParticipantsCount, ) if err != nil { return nil, teamErrorStatus(err, "не удалось добавить команду") @@ -85,6 +86,8 @@ func teamErrorStatus(err error, internalMessage string) error { return status.Error(codes.NotFound, err.Error()) case errors.Is(err, team_service.ErrInvalidCaptainEmail): return status.Error(codes.InvalidArgument, err.Error()) + case errors.Is(err, team_service.ErrInvalidParticipantsCount): + return status.Error(codes.InvalidArgument, err.Error()) default: return status.Error(codes.Internal, internalMessage) } diff --git a/internal/repos/teams_repo/registration_test.go b/internal/repos/teams_repo/registration_test.go index 23717d8..1522a81 100644 --- a/internal/repos/teams_repo/registration_test.go +++ b/internal/repos/teams_repo/registration_test.go @@ -119,7 +119,7 @@ func TestRegistrationPostgres(t *testing.T) { t.Fatalf("other game: %d %v", otherID, err) } for _, email := range []string{"", "manual@example.org"} { - manualID, err := repo.AddTeamWithParticipation(ctx, 1, 2, "Manual", "password", email, false) + manualID, err := repo.AddTeamWithParticipation(ctx, 1, 2, "Manual", "password", email, 0, false) if err != nil { t.Fatal(err) } diff --git a/internal/repos/teams_repo/repo.go b/internal/repos/teams_repo/repo.go index ef672ad..5333d12 100644 --- a/internal/repos/teams_repo/repo.go +++ b/internal/repos/teams_repo/repo.go @@ -121,11 +121,11 @@ func (r *TeamsRepo) AddTeam( name string, password string, ) (int, error) { - return r.AddTeamWithParticipation(ctx, creatorID, gameID, name, password, "", false) + return r.AddTeamWithParticipation(ctx, creatorID, gameID, name, password, "", 0, false) } // AddTeamWithParticipation creates a team with participation data. -func (r *TeamsRepo) AddTeamWithParticipation(ctx context.Context, creatorID, gameID int, name, password, captainEmail string, autoConfirm bool) (int, error) { +func (r *TeamsRepo) AddTeamWithParticipation(ctx context.Context, creatorID, gameID int, name, password, captainEmail string, participantsCount int32, autoConfirm bool) (int, error) { id := 0 status, source := "pending", "" if autoConfirm { @@ -133,8 +133,8 @@ func (r *TeamsRepo) AddTeamWithParticipation(ctx context.Context, creatorID, gam } err := r.pool.QueryRow( ctx, - `INSERT INTO teams (name, creator_id, game_id, password, participation_status, participation_source, participation_answered_at, captain_email) - VALUES ($1, $2, $3, $4, $5, $6, CASE WHEN $5 = 'confirmed' THEN NOW() ELSE NULL END, $7) + `INSERT INTO teams (name, creator_id, game_id, password, participation_status, participation_source, participation_answered_at, captain_email, participants_count) + VALUES ($1, $2, $3, $4, $5, $6, CASE WHEN $5 = 'confirmed' THEN NOW() ELSE NULL END, $7, $8) RETURNING id`, name, creatorID, @@ -143,6 +143,7 @@ func (r *TeamsRepo) AddTeamWithParticipation(ctx context.Context, creatorID, gam status, source, captainEmail, + participantsCount, ).Scan(&id) if err != nil { diff --git a/internal/services/team_service/manual_team_test.go b/internal/services/team_service/manual_team_test.go index f9331bf..524ccfa 100644 --- a/internal/services/team_service/manual_team_test.go +++ b/internal/services/team_service/manual_team_test.go @@ -15,8 +15,14 @@ func TestManualTeamEmail(t *testing.T) { } for _, email := range []string{"invalid", "Captain ", "a@example.org\r\nBcc: other@example.org", strings.Repeat("a", 250) + "@example.org"} { service := &TeamService{} - if _, err := service.AddTeam(context.Background(), 1, 1, "Team", email); err == nil { + if _, err := service.AddTeam(context.Background(), 1, 1, "Team", email, 0); err == nil { t.Errorf("accepted invalid email %q", email) } } + for _, count := range []int32{-1, 9} { + service := &TeamService{} + if _, err := service.AddTeam(context.Background(), 1, 1, "Team", "", count); err != ErrInvalidParticipantsCount { + t.Errorf("accepted invalid participants count %d: %v", count, err) + } + } } diff --git a/internal/services/team_service/registration.go b/internal/services/team_service/registration.go index d7298f6..2abc2f9 100644 --- a/internal/services/team_service/registration.go +++ b/internal/services/team_service/registration.go @@ -11,10 +11,11 @@ import ( ) var ( - ErrInvalidCaptainEmail = errors.New("укажите корректную почту капитана") - ErrTeamNotFound = errors.New("команда не найдена") - ErrInvalidRegistration = errors.New("укажите название команды (до 255 символов), почту капитана и положительное количество участников") - ErrRegistrationClosed = errors.New("игра не найдена или регистрация уже закрыта") + ErrInvalidCaptainEmail = errors.New("укажите корректную почту капитана") + ErrInvalidParticipantsCount = errors.New("укажите от 1 до 8 участников") + ErrTeamNotFound = errors.New("команда не найдена") + ErrInvalidRegistration = errors.New("укажите название команды (до 255 символов), почту капитана и положительное количество участников") + ErrRegistrationClosed = errors.New("игра не найдена или регистрация уже закрыта") ) // Registration contains data required to register a team. diff --git a/internal/services/team_service/service.go b/internal/services/team_service/service.go index 2985d73..4ff4fcd 100644 --- a/internal/services/team_service/service.go +++ b/internal/services/team_service/service.go @@ -50,11 +50,15 @@ func (s *TeamService) AddTeam( gameID int, name string, captainEmail string, + participantsCount int32, ) (*game_model.Team, error) { captainEmail = strings.TrimSpace(captainEmail) if captainEmail != "" && !validCaptainEmail(captainEmail) { return nil, ErrInvalidCaptainEmail } + if participantsCount < 0 || participantsCount > 8 { + return nil, ErrInvalidParticipantsCount + } password, err := s.passwordGenerator.Generate() if err != nil { return nil, err @@ -66,7 +70,7 @@ func (s *TeamService) AddTeam( } return nil, err } - id, err := s.teamsRepo.AddTeamWithParticipation(ctx, creatorID, gameID, name, password, captainEmail, !time.Now().Before(game.StartAt.Add(-24*time.Hour))) + id, err := s.teamsRepo.AddTeamWithParticipation(ctx, creatorID, gameID, name, password, captainEmail, participantsCount, !time.Now().Before(game.StartAt.Add(-24*time.Hour))) if err != nil { return nil, err } diff --git a/proto/main.pb.go b/proto/main.pb.go index 5d2e0a4..2c60b4c 100644 --- a/proto/main.pb.go +++ b/proto/main.pb.go @@ -7864,12 +7864,13 @@ func (*DeleteGameRsp) Descriptor() ([]byte, []int) { } type AddTeamReq struct { - state protoimpl.MessageState `protogen:"open.v1"` - GameID int32 `protobuf:"varint,1,opt,name=gameID,proto3" json:"gameID,omitempty"` - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` - CaptainEmail string `protobuf:"bytes,3,opt,name=captain_email,json=captainEmail,proto3" json:"captain_email,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + GameID int32 `protobuf:"varint,1,opt,name=gameID,proto3" json:"gameID,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + CaptainEmail string `protobuf:"bytes,3,opt,name=captain_email,json=captainEmail,proto3" json:"captain_email,omitempty"` + ParticipantsCount int32 `protobuf:"varint,4,opt,name=participants_count,json=participantsCount,proto3" json:"participants_count,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *AddTeamReq) Reset() { @@ -7923,6 +7924,13 @@ func (x *AddTeamReq) GetCaptainEmail() string { return "" } +func (x *AddTeamReq) GetParticipantsCount() int32 { + if x != nil { + return x.ParticipantsCount + } + return 0 +} + type AddTeamRsp struct { state protoimpl.MessageState `protogen:"open.v1"` ID int32 `protobuf:"varint,1,opt,name=ID,proto3" json:"ID,omitempty"` @@ -9852,12 +9860,13 @@ const file_main_proto_rawDesc = "" + "\fResetGameRsp\"\x1f\n" + "\rDeleteGameReq\x12\x0e\n" + "\x02ID\x18\x01 \x01(\x05R\x02ID\"\x0f\n" + - "\rDeleteGameRsp\"]\n" + + "\rDeleteGameRsp\"\x8c\x01\n" + "\n" + "AddTeamReq\x12\x16\n" + "\x06gameID\x18\x01 \x01(\x05R\x06gameID\x12\x12\n" + "\x04name\x18\x02 \x01(\tR\x04name\x12#\n" + - "\rcaptain_email\x18\x03 \x01(\tR\fcaptainEmail\"8\n" + + "\rcaptain_email\x18\x03 \x01(\tR\fcaptainEmail\x12-\n" + + "\x12participants_count\x18\x04 \x01(\x05R\x11participantsCount\"8\n" + "\n" + "AddTeamRsp\x12\x0e\n" + "\x02ID\x18\x01 \x01(\x05R\x02ID\x12\x1a\n" +