diff --git a/cmd/evening_detective_server/main.go b/cmd/evening_detective_server/main.go index 0d11b54..401a42a 100644 --- a/cmd/evening_detective_server/main.go +++ b/cmd/evening_detective_server/main.go @@ -3,13 +3,15 @@ package main import ( "context" _ "embed" + "evening_detective_server/internal/app" + "evening_detective_server/internal/repos/users_repo" + "evening_detective_server/internal/services/users_service" + proto "evening_detective_server/proto" "log" "net" "net/http" "os" - "evening_detective_server/internal/app" - proto "evening_detective_server/proto" - + "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" "github.com/jackc/pgx/v5/pgxpool" "github.com/joho/godotenv" @@ -38,6 +40,9 @@ func main() { log.Fatalf("QueryRow failed: %v\n", err) } + usersRepo := users_repo.NewUserRepo(dbpool) + usersService := users_service.NewUsersService(usersRepo) + // Create a listener on TCP port lis, err := net.Listen("tcp", ":8080") if err != nil { @@ -47,7 +52,12 @@ func main() { // Create a gRPC server object s := grpc.NewServer() // Attach the Greeter service to the server - proto.RegisterEveningDetectiveServerServer(s, app.NewServer()) + proto.RegisterEveningDetectiveServerServer( + s, + app.NewServer( + usersService, + ), + ) // Serve gRPC server log.Println("Serving gRPC on 0.0.0.0:8080") go func() { diff --git a/internal/app/server.go b/internal/app/server.go index 68efc62..e99198c 100644 --- a/internal/app/server.go +++ b/internal/app/server.go @@ -2,15 +2,22 @@ package app import ( "context" + "evening_detective_server/internal/services/users_service" proto "evening_detective_server/proto" ) type server struct { proto.UnsafeEveningDetectiveServerServer + + usersService *users_service.UsersService } -func NewServer() proto.EveningDetectiveServerServer { - return &server{} +func NewServer( + usersService *users_service.UsersService, +) proto.EveningDetectiveServerServer { + return &server{ + usersService: usersService, + } } func (s *server) Ping(_ context.Context, _ *proto.PingReq) (*proto.PingRsp, error) { @@ -21,6 +28,12 @@ func (s *server) Echo(_ context.Context, req *proto.EchoReq) (*proto.EchoRsp, er return &proto.EchoRsp{Text: req.Text}, nil } -func (s *server) Signup(context.Context, *proto.SignupReq) (*proto.SignupRsp, error) { - panic("unimplemented") +func (s *server) Signup(ctx context.Context, signupReq *proto.SignupReq) (*proto.SignupRsp, error) { + err := s.usersService.AddUser(ctx, signupReq.Username, signupReq.Email) + if err != nil { + return &proto.SignupRsp{ + Error: err.Error(), + }, nil + } + return &proto.SignupRsp{}, nil } diff --git a/internal/repos/users_repo/repo.go b/internal/repos/users_repo/repo.go new file mode 100644 index 0000000..8711896 --- /dev/null +++ b/internal/repos/users_repo/repo.go @@ -0,0 +1,50 @@ +package users_repo + +import ( + "context" + "errors" + + "github.com/jackc/pgx/v5/pgxpool" +) + +type UsersRepo struct { + pool *pgxpool.Pool +} + +func NewUserRepo(pool *pgxpool.Pool) *UsersRepo { + return &UsersRepo{ + pool: pool, + } +} + +func (s *UsersRepo) AddUser( + ctx context.Context, + username string, + email string, + passwoedHash string, + role string, +) error { + tag, err := s.pool.Exec( + ctx, + `INSERT INTO users (username, email, password_hash, role) + SELECT $1, $2, $3, $4 + WHERE NOT EXISTS ( + SELECT 1 FROM users + WHERE username = $5 OR email = $6 + )`, + username, + email, + passwoedHash, + role, + + username, + email, + ) + if err != nil { + return err + } + if tag.RowsAffected() == 0 { + return errors.New("username или email уже используется") + } + return nil +} diff --git a/internal/services/users_service/service.go b/internal/services/users_service/service.go new file mode 100644 index 0000000..d6fb76b --- /dev/null +++ b/internal/services/users_service/service.go @@ -0,0 +1,31 @@ +package users_service + +import ( + "context" + "evening_detective_server/internal/repos/users_repo" +) + +type UsersService struct { + usersRepo *users_repo.UsersRepo +} + +func NewUsersService(usersRepo *users_repo.UsersRepo) *UsersService { + return &UsersService{ + usersRepo: usersRepo, + } +} + +func (s *UsersService) AddUser( + ctx context.Context, + username string, + email string, +) error { + err := s.usersRepo.AddUser( + ctx, + username, + email, + "hello", // TODO: generate password and send email + "user", + ) + return err +} diff --git a/migrations/20260628175120_create_users_table.sql b/migrations/20260628175120_create_users_table.sql index ae29455..485f0dd 100644 --- a/migrations/20260628175120_create_users_table.sql +++ b/migrations/20260628175120_create_users_table.sql @@ -4,7 +4,7 @@ CREATE TABLE IF NOT EXISTS users ( username VARCHAR(50) NOT NULL UNIQUE, email VARCHAR(100) NOT NULL UNIQUE, password_hash VARCHAR(255) NOT NULL, - role VARCHAR(20) DEFAULT 'user' CHECK (role IN ('admin', 'author', 'organizer', 'user')), + role VARCHAR(20) CHECK (role IN ('admin', 'author', 'organizer', 'user')), is_active BOOLEAN DEFAULT TRUE, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP );