diff --git a/api/main.proto b/api/main.proto index c8274d3..7b6dd82 100644 --- a/api/main.proto +++ b/api/main.proto @@ -749,8 +749,10 @@ message Game { } message Team { - int32 id = 1; - string name = 2; + int32 id = 1; + string name = 2; + string status = 3; + string password = 4; } message GetGameReq { diff --git a/cmd/evening_detective_server/main.go b/cmd/evening_detective_server/main.go index 38bc8ac..3a3cdce 100644 --- a/cmd/evening_detective_server/main.go +++ b/cmd/evening_detective_server/main.go @@ -86,6 +86,7 @@ func main() { teamRepo, scenariosRepo, os.Getenv("FILE_PREFIX_DOMAIN"), + passwordGenerator, ) // Create a listener on TCP port diff --git a/cmd/evening_detective_server/main.swagger.json b/cmd/evening_detective_server/main.swagger.json index f6559d0..611d078 100644 --- a/cmd/evening_detective_server/main.swagger.json +++ b/cmd/evening_detective_server/main.swagger.json @@ -1996,6 +1996,12 @@ }, "name": { "type": "string" + }, + "status": { + "type": "string" + }, + "password": { + "type": "string" } } }, diff --git a/internal/app/server.go b/internal/app/server.go index 9890152..0d76865 100644 --- a/internal/app/server.go +++ b/internal/app/server.go @@ -544,8 +544,20 @@ func (s *server) AddTeam(ctx context.Context, req *proto.AddTeamReq) (*proto.Add if !roles.HasRole(claims, roles.Organizer) { return nil, status.Errorf(codes.PermissionDenied, "permission denied") } - - panic("unimplemented") + + err := s.gameService.AddTeam( + ctx, + claims.UserID, + int(req.GameId), + req.Name, + ) + if err != nil { + return &proto.AddTeamRsp{ + Error: err.Error(), + }, nil + } + + return &proto.AddTeamRsp{}, nil } func (s *server) UpdateTeam(ctx context.Context, req *proto.UpdateTeamReq) (*proto.UpdateTeamRsp, error) { @@ -553,8 +565,19 @@ func (s *server) UpdateTeam(ctx context.Context, req *proto.UpdateTeamReq) (*pro if !roles.HasRole(claims, roles.Organizer) { return nil, status.Errorf(codes.PermissionDenied, "permission denied") } - - panic("unimplemented") + + err := s.gameService.UpdateTeam( + ctx, + int(req.Id), + req.Name, + ) + if err != nil { + return &proto.UpdateTeamRsp{ + Error: err.Error(), + }, nil + } + + return &proto.UpdateTeamRsp{}, nil } func (s *server) DeleteTeam(ctx context.Context, req *proto.DeleteTeamReq) (*proto.DeleteTeamRsp, error) { @@ -562,8 +585,18 @@ func (s *server) DeleteTeam(ctx context.Context, req *proto.DeleteTeamReq) (*pro if !roles.HasRole(claims, roles.Organizer) { return nil, status.Errorf(codes.PermissionDenied, "permission denied") } - - panic("unimplemented") + + err := s.gameService.DeleteTeam( + ctx, + int(req.Id), + ) + if err != nil { + return &proto.DeleteTeamRsp{ + Error: err.Error(), + }, nil + } + + return &proto.DeleteTeamRsp{}, nil } func (s *server) GiveTeamApplications(ctx context.Context, req *proto.GiveTeamApplicationsReq) (*proto.GiveTeamApplicationsRsp, error) { @@ -571,7 +604,7 @@ func (s *server) GiveTeamApplications(ctx context.Context, req *proto.GiveTeamAp if !roles.HasRole(claims, roles.Organizer) { return nil, status.Errorf(codes.PermissionDenied, "permission denied") } - + panic("unimplemented") } @@ -582,3 +615,12 @@ func (s *server) GetTeamActions(ctx context.Context, req *proto.GetTeamActionsRe func (s *server) AddTeamAction(ctx context.Context, req *proto.AddTeamActionReq) (*proto.AddTeamActionRsp, error) { panic("unimplemented") } + +func (s *server) DeleteLastTeamAction(ctx context.Context, req *proto.DeleteLastTeamActionReq) (*proto.DeleteLastTeamActionRsp, error) { + claims := ctx.Value("claims").(*processor_jwt.JWTClaims) + if !roles.HasRole(claims, roles.Author) { + return nil, status.Errorf(codes.PermissionDenied, "permission denied") + } + + panic("unimplemented") +} diff --git a/internal/app/team_mapper.go b/internal/app/team_mapper.go index 00295ec..c507570 100644 --- a/internal/app/team_mapper.go +++ b/internal/app/team_mapper.go @@ -9,8 +9,10 @@ func mapTeam( o *game_service.Team, ) *proto.Team { return &proto.Team{ - Id: int32(o.ID), - Name: o.Name, + Id: int32(o.ID), + Name: o.Name, + Status: o.Status, + Password: o.Password, } } diff --git a/internal/repos/team.go b/internal/repos/team.go index 8f601b2..8a4fc74 100644 --- a/internal/repos/team.go +++ b/internal/repos/team.go @@ -3,5 +3,6 @@ package repos type Team struct { ID int Name string + Status string Password string } diff --git a/internal/repos/teams_repo/repo.go b/internal/repos/teams_repo/repo.go index c4de284..0013123 100644 --- a/internal/repos/teams_repo/repo.go +++ b/internal/repos/teams_repo/repo.go @@ -2,11 +2,16 @@ package teams_repo import ( "context" + "errors" "evening_detective_server/internal/repos" "github.com/jackc/pgx/v5/pgxpool" ) +var ( + ErrTeamNotFound = errors.New("Команда не найдена") +) + type TeamsRepo struct { pool *pgxpool.Pool } @@ -24,20 +29,12 @@ func (r *TeamsRepo) GetTeamsByGameID( rows, err := r.pool.Query( ctx, `SELECT - scenarios.id, - scenarios.name, - scenarios.description, - scenarios.image, - scenarios.scenario, - users.id, - users.username, - scenarios.status, - scenarios.updated_at, - scenarios.created_at, - scenarios.published_at - FROM scenarios - LEFT JOIN users on scenarios.author_id = users.id - WHERE scenarios.author_id = $1 and is_deleted = FALSE + id, + name, + status, + password + FROM teams + WHERE game_id = $1 ORDER BY created_at DESC`, gameId, ) @@ -52,6 +49,7 @@ func (r *TeamsRepo) GetTeamsByGameID( err := rows.Scan( &team.ID, &team.Name, + &team.Status, &team.Password, ) if err != nil { @@ -65,3 +63,65 @@ func (r *TeamsRepo) GetTeamsByGameID( return teams, nil } + +func (r *TeamsRepo) AddTeam( + ctx context.Context, + creatorId int, + gameId int, + name string, + scenarioId int, + password string, +) (int, error) { + id := 0 + err := r.pool.QueryRow( + ctx, + `INSERT INTO teams (name, creator_id, game_id, scenario_id, password) + VALUES ($1, $2, $3, $4, $5) + RETURNING id`, + name, + creatorId, + gameId, + scenarioId, + password, + ).Scan(&id) + + if err != nil { + return 0, err + } + return id, nil +} + +func (r *TeamsRepo) UpdateTeam(ctx context.Context, teamId int, name string) error { + tag, err := r.pool.Exec( + ctx, + `UPDATE teams + SET + name = $1 + WHERE id = $2`, + name, + teamId, + ) + if err != nil { + return err + } + if tag.RowsAffected() == 0 { + return ErrTeamNotFound + } + return nil +} + +func (r *TeamsRepo) DeleteTeam(ctx context.Context, teamId int) error { + tag, err := r.pool.Exec( + ctx, + `DELETE FROM teams + WHERE id = $1`, + teamId, + ) + if err != nil { + return err + } + if tag.RowsAffected() == 0 { + return ErrTeamNotFound + } + return nil +} diff --git a/internal/services/game_service/service.go b/internal/services/game_service/service.go index 45e9cfd..d7abc3b 100644 --- a/internal/services/game_service/service.go +++ b/internal/services/game_service/service.go @@ -2,6 +2,7 @@ package game_service import ( "context" + "evening_detective_server/internal/modules/password_generator" "evening_detective_server/internal/repos/games_repo" "evening_detective_server/internal/repos/scenarios_repo" "evening_detective_server/internal/repos/teams_repo" @@ -9,10 +10,11 @@ import ( ) type GameService struct { - gamesRepo *games_repo.GamesRepo - teamsRepo *teams_repo.TeamsRepo - scenariosRepo *scenarios_repo.ScenariosRepo - domain string + gamesRepo *games_repo.GamesRepo + teamsRepo *teams_repo.TeamsRepo + scenariosRepo *scenarios_repo.ScenariosRepo + domain string + passwordGenerator password_generator.IPasswordGenerator } func NewGameService( @@ -20,12 +22,14 @@ func NewGameService( teamsRepo *teams_repo.TeamsRepo, scenariosRepo *scenarios_repo.ScenariosRepo, domain string, + passwordGenerator password_generator.IPasswordGenerator, ) *GameService { return &GameService{ - gamesRepo: gamesRepo, - teamsRepo: teamsRepo, - scenariosRepo: scenariosRepo, - domain: domain, + gamesRepo: gamesRepo, + teamsRepo: teamsRepo, + scenariosRepo: scenariosRepo, + domain: domain, + passwordGenerator: passwordGenerator, } } @@ -91,3 +95,29 @@ func (s *GameService) UpdateGame( ) error { return s.gamesRepo.UpdateGame(ctx, id, name, description, startAt, scenarioId) } + +func (s *GameService) AddTeam( + ctx context.Context, + creatorId int, + gameId int, + name string, +) error { + game, err := s.gamesRepo.GetGameByID(ctx, gameId) + if err != nil { + return err + } + password, err := s.passwordGenerator.Generate() + if err != nil { + return err + } + _, err = s.teamsRepo.AddTeam(ctx, creatorId, gameId, name, game.ScenarioId, password) + return err +} + +func (s *GameService) UpdateTeam(ctx context.Context, teamId int, name string) error { + return s.teamsRepo.UpdateTeam(ctx, teamId, name) +} + +func (s *GameService) DeleteTeam(ctx context.Context, teamId int) error { + return s.teamsRepo.DeleteTeam(ctx, teamId) +} diff --git a/internal/services/game_service/team.go b/internal/services/game_service/team.go index da0daed..17cd4c3 100644 --- a/internal/services/game_service/team.go +++ b/internal/services/game_service/team.go @@ -3,5 +3,6 @@ package game_service type Team struct { ID int Name string + Status string Password string } diff --git a/internal/services/game_service/team_mapper.go b/internal/services/game_service/team_mapper.go index f97a1ea..0cb9500 100644 --- a/internal/services/game_service/team_mapper.go +++ b/internal/services/game_service/team_mapper.go @@ -8,6 +8,7 @@ func mapTeam( return &Team{ ID: o.ID, Name: o.Name, + Status: o.Status, Password: o.Password, } } diff --git a/proto/main.pb.go b/proto/main.pb.go index cc4ea9a..5b539c8 100644 --- a/proto/main.pb.go +++ b/proto/main.pb.go @@ -3129,6 +3129,8 @@ type Team struct { state protoimpl.MessageState `protogen:"open.v1"` Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Status string `protobuf:"bytes,3,opt,name=status,proto3" json:"status,omitempty"` + Password string `protobuf:"bytes,4,opt,name=password,proto3" json:"password,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -3177,6 +3179,20 @@ func (x *Team) GetName() string { return "" } +func (x *Team) GetStatus() string { + if x != nil { + return x.Status + } + return "" +} + +func (x *Team) GetPassword() string { + if x != nil { + return x.Password + } + return "" +} + type GetGameReq struct { state protoimpl.MessageState `protogen:"open.v1"` Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` @@ -4344,10 +4360,12 @@ const file_main_proto_rawDesc = "" + "\bstart_at\x18\x04 \x01(\v2\x1a.google.protobuf.TimestampR\astartAt\x12\x16\n" + "\x06status\x18\x05 \x01(\tR\x06status\x12D\n" + "\bscenario\x18\x06 \x01(\v2(.crabs.evening_detective_server.ScenarioR\bscenario\x12:\n" + - "\x05teams\x18\a \x03(\v2$.crabs.evening_detective_server.TeamR\x05teams\"*\n" + + "\x05teams\x18\a \x03(\v2$.crabs.evening_detective_server.TeamR\x05teams\"^\n" + "\x04Team\x12\x0e\n" + "\x02id\x18\x01 \x01(\x05R\x02id\x12\x12\n" + - "\x04name\x18\x02 \x01(\tR\x04name\"\x1c\n" + + "\x04name\x18\x02 \x01(\tR\x04name\x12\x16\n" + + "\x06status\x18\x03 \x01(\tR\x06status\x12\x1a\n" + + "\bpassword\x18\x04 \x01(\tR\bpassword\"\x1c\n" + "\n" + "GetGameReq\x12\x0e\n" + "\x02id\x18\x01 \x01(\x05R\x02id\"\\\n" +