add teams operations

This commit is contained in:
2026-07-28 00:51:25 +07:00
parent 5a5b36e44d
commit f6934e9d5b
11 changed files with 199 additions and 35 deletions
+4 -2
View File
@@ -749,8 +749,10 @@ message Game {
} }
message Team { message Team {
int32 id = 1; int32 id = 1;
string name = 2; string name = 2;
string status = 3;
string password = 4;
} }
message GetGameReq { message GetGameReq {
+1
View File
@@ -86,6 +86,7 @@ func main() {
teamRepo, teamRepo,
scenariosRepo, scenariosRepo,
os.Getenv("FILE_PREFIX_DOMAIN"), os.Getenv("FILE_PREFIX_DOMAIN"),
passwordGenerator,
) )
// Create a listener on TCP port // Create a listener on TCP port
@@ -1996,6 +1996,12 @@
}, },
"name": { "name": {
"type": "string" "type": "string"
},
"status": {
"type": "string"
},
"password": {
"type": "string"
} }
} }
}, },
+49 -7
View File
@@ -544,8 +544,20 @@ func (s *server) AddTeam(ctx context.Context, req *proto.AddTeamReq) (*proto.Add
if !roles.HasRole(claims, roles.Organizer) { if !roles.HasRole(claims, roles.Organizer) {
return nil, status.Errorf(codes.PermissionDenied, "permission denied") 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) { 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) { if !roles.HasRole(claims, roles.Organizer) {
return nil, status.Errorf(codes.PermissionDenied, "permission denied") 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) { 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) { if !roles.HasRole(claims, roles.Organizer) {
return nil, status.Errorf(codes.PermissionDenied, "permission denied") 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) { 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) { if !roles.HasRole(claims, roles.Organizer) {
return nil, status.Errorf(codes.PermissionDenied, "permission denied") return nil, status.Errorf(codes.PermissionDenied, "permission denied")
} }
panic("unimplemented") 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) { func (s *server) AddTeamAction(ctx context.Context, req *proto.AddTeamActionReq) (*proto.AddTeamActionRsp, error) {
panic("unimplemented") 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")
}
+4 -2
View File
@@ -9,8 +9,10 @@ func mapTeam(
o *game_service.Team, o *game_service.Team,
) *proto.Team { ) *proto.Team {
return &proto.Team{ return &proto.Team{
Id: int32(o.ID), Id: int32(o.ID),
Name: o.Name, Name: o.Name,
Status: o.Status,
Password: o.Password,
} }
} }
+1
View File
@@ -3,5 +3,6 @@ package repos
type Team struct { type Team struct {
ID int ID int
Name string Name string
Status string
Password string Password string
} }
+74 -14
View File
@@ -2,11 +2,16 @@ package teams_repo
import ( import (
"context" "context"
"errors"
"evening_detective_server/internal/repos" "evening_detective_server/internal/repos"
"github.com/jackc/pgx/v5/pgxpool" "github.com/jackc/pgx/v5/pgxpool"
) )
var (
ErrTeamNotFound = errors.New("Команда не найдена")
)
type TeamsRepo struct { type TeamsRepo struct {
pool *pgxpool.Pool pool *pgxpool.Pool
} }
@@ -24,20 +29,12 @@ func (r *TeamsRepo) GetTeamsByGameID(
rows, err := r.pool.Query( rows, err := r.pool.Query(
ctx, ctx,
`SELECT `SELECT
scenarios.id, id,
scenarios.name, name,
scenarios.description, status,
scenarios.image, password
scenarios.scenario, FROM teams
users.id, WHERE game_id = $1
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
ORDER BY created_at DESC`, ORDER BY created_at DESC`,
gameId, gameId,
) )
@@ -52,6 +49,7 @@ func (r *TeamsRepo) GetTeamsByGameID(
err := rows.Scan( err := rows.Scan(
&team.ID, &team.ID,
&team.Name, &team.Name,
&team.Status,
&team.Password, &team.Password,
) )
if err != nil { if err != nil {
@@ -65,3 +63,65 @@ func (r *TeamsRepo) GetTeamsByGameID(
return teams, nil 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
}
+38 -8
View File
@@ -2,6 +2,7 @@ package game_service
import ( import (
"context" "context"
"evening_detective_server/internal/modules/password_generator"
"evening_detective_server/internal/repos/games_repo" "evening_detective_server/internal/repos/games_repo"
"evening_detective_server/internal/repos/scenarios_repo" "evening_detective_server/internal/repos/scenarios_repo"
"evening_detective_server/internal/repos/teams_repo" "evening_detective_server/internal/repos/teams_repo"
@@ -9,10 +10,11 @@ import (
) )
type GameService struct { type GameService struct {
gamesRepo *games_repo.GamesRepo gamesRepo *games_repo.GamesRepo
teamsRepo *teams_repo.TeamsRepo teamsRepo *teams_repo.TeamsRepo
scenariosRepo *scenarios_repo.ScenariosRepo scenariosRepo *scenarios_repo.ScenariosRepo
domain string domain string
passwordGenerator password_generator.IPasswordGenerator
} }
func NewGameService( func NewGameService(
@@ -20,12 +22,14 @@ func NewGameService(
teamsRepo *teams_repo.TeamsRepo, teamsRepo *teams_repo.TeamsRepo,
scenariosRepo *scenarios_repo.ScenariosRepo, scenariosRepo *scenarios_repo.ScenariosRepo,
domain string, domain string,
passwordGenerator password_generator.IPasswordGenerator,
) *GameService { ) *GameService {
return &GameService{ return &GameService{
gamesRepo: gamesRepo, gamesRepo: gamesRepo,
teamsRepo: teamsRepo, teamsRepo: teamsRepo,
scenariosRepo: scenariosRepo, scenariosRepo: scenariosRepo,
domain: domain, domain: domain,
passwordGenerator: passwordGenerator,
} }
} }
@@ -91,3 +95,29 @@ func (s *GameService) UpdateGame(
) error { ) error {
return s.gamesRepo.UpdateGame(ctx, id, name, description, startAt, scenarioId) 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)
}
+1
View File
@@ -3,5 +3,6 @@ package game_service
type Team struct { type Team struct {
ID int ID int
Name string Name string
Status string
Password string Password string
} }
@@ -8,6 +8,7 @@ func mapTeam(
return &Team{ return &Team{
ID: o.ID, ID: o.ID,
Name: o.Name, Name: o.Name,
Status: o.Status,
Password: o.Password, Password: o.Password,
} }
} }
+20 -2
View File
@@ -3129,6 +3129,8 @@ type Team struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,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 unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
} }
@@ -3177,6 +3179,20 @@ func (x *Team) GetName() string {
return "" 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 { type GetGameReq struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` 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" + "\bstart_at\x18\x04 \x01(\v2\x1a.google.protobuf.TimestampR\astartAt\x12\x16\n" +
"\x06status\x18\x05 \x01(\tR\x06status\x12D\n" + "\x06status\x18\x05 \x01(\tR\x06status\x12D\n" +
"\bscenario\x18\x06 \x01(\v2(.crabs.evening_detective_server.ScenarioR\bscenario\x12:\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" + "\x04Team\x12\x0e\n" +
"\x02id\x18\x01 \x01(\x05R\x02id\x12\x12\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" + "\n" +
"GetGameReq\x12\x0e\n" + "GetGameReq\x12\x0e\n" +
"\x02id\x18\x01 \x01(\x05R\x02id\"\\\n" + "\x02id\x18\x01 \x01(\x05R\x02id\"\\\n" +