diff --git a/.vscode/settings.json b/.vscode/settings.json index 3030d67..4fee38b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,6 @@ { "cSpell.words": [ + "AUTOINCREMENT", "gwmux" ] } \ No newline at end of file diff --git a/api/requests.http b/api/requests.http new file mode 100644 index 0000000..9550e2b --- /dev/null +++ b/api/requests.http @@ -0,0 +1,16 @@ +GET http://localhost:8090/teams + +### + +POST http://localhost:8090/teams + +{ + "teams": [ + { + "name": "Облако" + }, + { + "name": "Кустик" + } + ] +} diff --git a/cmd/evening_detective/main.go b/cmd/evening_detective/main.go index c0f8259..67e4294 100644 --- a/cmd/evening_detective/main.go +++ b/cmd/evening_detective/main.go @@ -24,10 +24,14 @@ func main() { // Create a gRPC server object s := grpc.NewServer() // Attach the Greeter service to the server + repository, err := services.NewRepository() + if err != nil { + panic(err) + } proto.RegisterEveningDetectiveServer( s, app.NewServer( - services.NewServices(), + services.NewServices(repository), ), ) // Serve gRPC server diff --git a/go.mod b/go.mod index 1b15747..1931743 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( ) require ( + github.com/mattn/go-sqlite3 v1.14.28 golang.org/x/net v0.23.0 // indirect golang.org/x/sys v0.18.0 // indirect golang.org/x/text v0.15.0 // indirect diff --git a/internal/models/action.go b/internal/models/action.go new file mode 100644 index 0000000..3084f8f --- /dev/null +++ b/internal/models/action.go @@ -0,0 +1,7 @@ +package models + +type Action struct { + ID string + To string + Time int64 +} diff --git a/internal/models/application.go b/internal/models/application.go new file mode 100644 index 0000000..2ab9acb --- /dev/null +++ b/internal/models/application.go @@ -0,0 +1,7 @@ +package models + +type Application struct { + TeamID int64 + Name string + State string +} diff --git a/internal/models/game.go b/internal/models/game.go new file mode 100644 index 0000000..4c75477 --- /dev/null +++ b/internal/models/game.go @@ -0,0 +1,7 @@ +package models + +type Game struct { + StartTime int64 + EndTime int64 + State string +} diff --git a/internal/models/team.go b/internal/models/team.go new file mode 100644 index 0000000..1d2041d --- /dev/null +++ b/internal/models/team.go @@ -0,0 +1,7 @@ +package models + +type Team struct { + ID int64 + Name string + Password string +} diff --git a/internal/modules/password/password.go b/internal/modules/password/password.go new file mode 100644 index 0000000..96f21f0 --- /dev/null +++ b/internal/modules/password/password.go @@ -0,0 +1,15 @@ +package password + +import "math/rand" + +var ( + letters = []rune("abcdefghijklmnopqrstuvwxyz123456789") +) + +func GenPass(n int) string { + b := make([]rune, n) + for i := range b { + b[i] = letters[rand.Intn(len(letters))] + } + return string(b) +} diff --git a/internal/services/mappers.go b/internal/services/mappers.go new file mode 100644 index 0000000..209d255 --- /dev/null +++ b/internal/services/mappers.go @@ -0,0 +1,27 @@ +package services + +import ( + "evening_detective/internal/models" + "evening_detective/proto" +) + +func mapTeamsToTeamAdvanced(team *models.Team) *proto.TeamAdvanced { + return &proto.TeamAdvanced{ + Id: team.ID, + Name: team.Name, + } +} + +func mapTeamsToTeamFull(team *models.Team) *proto.TeamFull { + return &proto.TeamFull{ + Id: team.ID, + Name: team.Name, + Password: team.Password, + } +} + +func mapProtoTeamsToTeam(team *proto.Team) *models.Team { + return &models.Team{ + Name: team.Name, + } +} diff --git a/internal/services/repository.go b/internal/services/repository.go new file mode 100644 index 0000000..17b7bd6 --- /dev/null +++ b/internal/services/repository.go @@ -0,0 +1,58 @@ +package services + +import ( + "context" + "database/sql" + "evening_detective/internal/models" + + _ "github.com/mattn/go-sqlite3" +) + +type Repository struct { + db *sql.DB +} + +func NewRepository() (*Repository, error) { + db, err := sql.Open("sqlite3", "store.db") + if err != nil { + return nil, err + } + _, err = db.Exec("CREATE TABLE IF NOT EXISTS teams (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, password TEXT);") + if err != nil { + return nil, err + } + return &Repository{db: db}, nil +} + +func (r *Repository) GetTeams(ctx context.Context) ([]*models.Team, error) { + rows, err := r.db.Query("select id, name, password from teams") + if err != nil { + panic(err) + } + defer rows.Close() + teams := []*models.Team{} + + for rows.Next() { + team := &models.Team{} + err := rows.Scan(&team.ID, &team.Name, &team.Password) + if err != nil { + return nil, err + } + teams = append(teams, team) + } + return teams, nil +} + +func (r *Repository) AddTeams(ctx context.Context, teams []*models.Team) ([]*models.Team, error) { + for _, team := range teams { + result, err := r.db.Exec("insert into teams (name, password) values ($1, $2)", team.Name, team.Password) + if err != nil { + return nil, err + } + team.ID, err = result.LastInsertId() + if err != nil { + return nil, err + } + } + return teams, nil +} diff --git a/internal/services/services.go b/internal/services/services.go index 3fbcc98..20ea8af 100644 --- a/internal/services/services.go +++ b/internal/services/services.go @@ -2,13 +2,22 @@ package services import ( "context" + "evening_detective/internal/models" + "evening_detective/internal/modules/password" "evening_detective/proto" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) -type Services struct{} +type Services struct { + repository *Repository +} -func NewServices() *Services { - return &Services{} +func NewServices(repository *Repository) *Services { + return &Services{ + repository: repository, + } } func (s *Services) GiveApplications(ctx context.Context, req *proto.GiveApplicationsReq) (*proto.GiveApplicationsRsp, error) { @@ -39,10 +48,32 @@ func (s *Services) GetTeamsCSV(ctx context.Context, req *proto.GetTeamsCSVReq) ( panic("unimplemented") } -func (s *Services) GetTeams(ctx context.Context, req *proto.GetTeamsReq) (*proto.GetTeamsRsp, error) { - panic("unimplemented") +func (s *Services) GetTeams(ctx context.Context, _ *proto.GetTeamsReq) (*proto.GetTeamsRsp, error) { + teams, err := s.repository.GetTeams(ctx) + if err != nil { + return nil, status.Errorf(codes.Internal, err.Error()) + } + res := make([]*proto.TeamAdvanced, 0, len(teams)) + for _, team := range teams { + res = append(res, mapTeamsToTeamAdvanced(team)) + } + return &proto.GetTeamsRsp{Teams: res}, err } func (s *Services) AddTeams(ctx context.Context, req *proto.AddTeamsReq) (*proto.AddTeamsRsp, error) { - panic("unimplemented") + inTeams := make([]*models.Team, 0, len(req.Teams)) + for _, team := range req.Teams { + t := mapProtoTeamsToTeam(team) + t.Password = password.GenPass(8) + inTeams = append(inTeams, t) + } + teams, err := s.repository.AddTeams(ctx, inTeams) + if err != nil { + return nil, status.Errorf(codes.Internal, err.Error()) + } + res := make([]*proto.TeamFull, 0, len(teams)) + for _, team := range teams { + res = append(res, mapTeamsToTeamFull(team)) + } + return &proto.AddTeamsRsp{Teams: res}, err } diff --git a/store.db b/store.db new file mode 100644 index 0000000..50cc309 Binary files /dev/null and b/store.db differ