I am batman
This commit is contained in:
210
services/auth-service/internal/server/server.go
Normal file
210
services/auth-service/internal/server/server.go
Normal file
@@ -0,0 +1,210 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
pb "go-microservices/proto/auth"
|
||||
"go-microservices/services/auth-service/internal/models"
|
||||
"go-microservices/services/auth-service/internal/repository"
|
||||
"go-microservices/services/auth-service/internal/utils"
|
||||
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
type AuthServer struct {
|
||||
pb.UnimplementedAuthServiceServer
|
||||
repo *repository.Repository
|
||||
}
|
||||
|
||||
func NewAuthServer(repo *repository.Repository) *AuthServer {
|
||||
return &AuthServer{repo: repo}
|
||||
}
|
||||
|
||||
func (s *AuthServer) SignUp(ctx context.Context, req *pb.SignUpRequest) (*pb.SignUpResponse, error) {
|
||||
hashed, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to hash password: %v", err)
|
||||
}
|
||||
|
||||
auth := &models.Auth{
|
||||
Username: req.Username,
|
||||
Email: req.Email,
|
||||
Password: string(hashed),
|
||||
Role: "user", // default role (proto SignUpRequest doesn't include role)
|
||||
}
|
||||
|
||||
if err := s.repo.CreateAuth(auth); err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to create user: %v", err)
|
||||
}
|
||||
|
||||
userID := fmt.Sprintf("%d", auth.ID)
|
||||
return &pb.SignUpResponse{UserId: userID, Message: "registered"}, nil
|
||||
}
|
||||
|
||||
func (s *AuthServer) SignIn(ctx context.Context, req *pb.SignInRequest) (*pb.SignInResponse, error) {
|
||||
auth, err := s.repo.GetAuthByEmail(req.Email)
|
||||
if err != nil || auth == nil {
|
||||
return nil, status.Errorf(codes.Unauthenticated, "invalid credentials")
|
||||
}
|
||||
|
||||
if err := bcrypt.CompareHashAndPassword([]byte(auth.Password), []byte(req.Password)); err != nil {
|
||||
return nil, status.Errorf(codes.Unauthenticated, "invalid credentials")
|
||||
}
|
||||
|
||||
accessToken, refreshToken, err := utils.GenerateJWT(*auth)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to generate tokens: %v", err)
|
||||
}
|
||||
|
||||
userID := fmt.Sprintf("%d", auth.ID)
|
||||
return &pb.SignInResponse{
|
||||
AccessToken: accessToken,
|
||||
RefreshToken: refreshToken,
|
||||
UserId: userID,
|
||||
Message: "logged in",
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *AuthServer) ValidateToken(ctx context.Context, req *pb.ValidateTokenRequest) (*pb.ValidateTokenResponse, error) {
|
||||
claims, err := utils.ValidateJWT(req.Token, false)
|
||||
if err != nil {
|
||||
return &pb.ValidateTokenResponse{Valid: false, UserId: "", Message: "invalid token"}, nil
|
||||
}
|
||||
|
||||
var userID string
|
||||
if sub, ok := claims["sub"]; ok {
|
||||
switch v := sub.(type) {
|
||||
case string:
|
||||
userID = v
|
||||
case float64:
|
||||
userID = strconv.FormatFloat(v, 'f', 0, 64)
|
||||
default:
|
||||
userID = fmt.Sprintf("%v", v)
|
||||
}
|
||||
}
|
||||
|
||||
if userID == "" {
|
||||
return &pb.ValidateTokenResponse{Valid: false, UserId: "", Message: "invalid token"}, nil
|
||||
}
|
||||
|
||||
return &pb.ValidateTokenResponse{Valid: true, UserId: userID, Message: "valid"}, nil
|
||||
}
|
||||
|
||||
func (s *AuthServer) GetUserInfo(ctx context.Context, req *pb.GetUserInfoRequest) (*pb.GetUserInfoResponse, error) {
|
||||
// expect req.UserId (proto field user_id)
|
||||
if req.UserId == "" {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "user id required")
|
||||
}
|
||||
u64, err := strconv.ParseUint(req.UserId, 10, 64)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "invalid user id: %v", err)
|
||||
}
|
||||
user, err := s.repo.GetAuthByID(uint(u64))
|
||||
if err != nil || user == nil {
|
||||
return nil, status.Errorf(codes.NotFound, "user not found")
|
||||
}
|
||||
|
||||
return &pb.GetUserInfoResponse{
|
||||
UserId: fmt.Sprintf("%d", user.ID),
|
||||
Username: user.Username,
|
||||
Email: user.Email,
|
||||
Roles: []string{user.Role},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CreateTest creates a simple Test record in the database
|
||||
func (s *AuthServer) CreateTest(ctx context.Context, req *pb.CreateTestRequest) (*pb.CreateTestResponse, error) {
|
||||
if req.Content == "" {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "content required")
|
||||
}
|
||||
t := &models.Test{Content: req.Content}
|
||||
if err := s.repo.CreateTest(t); err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to create test: %v", err)
|
||||
}
|
||||
return &pb.CreateTestResponse{
|
||||
Test: &pb.Test{
|
||||
Id: uint64(t.ID),
|
||||
Content: t.Content,
|
||||
CreatedAt: t.CreatedAt.Format(time.RFC3339),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ListTests returns recent test records
|
||||
func (s *AuthServer) ListTests(ctx context.Context, req *pb.ListTestsRequest) (*pb.ListTestsResponse, error) {
|
||||
tests, err := s.repo.ListTests()
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to list tests: %v", err)
|
||||
}
|
||||
resp := &pb.ListTestsResponse{Tests: make([]*pb.Test, 0, len(tests))}
|
||||
for _, t := range tests {
|
||||
resp.Tests = append(resp.Tests, &pb.Test{
|
||||
Id: uint64(t.ID),
|
||||
Content: t.Content,
|
||||
CreatedAt: t.CreatedAt.Format(time.RFC3339),
|
||||
})
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// GetTest retrieves a single test by ID
|
||||
func (s *AuthServer) GetTest(ctx context.Context, req *pb.GetTestRequest) (*pb.GetTestResponse, error) {
|
||||
if req.Id == 0 {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "test id required")
|
||||
}
|
||||
t, err := s.repo.GetTestByID(uint(req.Id))
|
||||
if err != nil || t == nil {
|
||||
return nil, status.Errorf(codes.NotFound, "test not found")
|
||||
}
|
||||
return &pb.GetTestResponse{
|
||||
Test: &pb.Test{
|
||||
Id: uint64(t.ID),
|
||||
Content: t.Content,
|
||||
CreatedAt: t.CreatedAt.Format(time.RFC3339),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateTest updates an existing test
|
||||
func (s *AuthServer) UpdateTest(ctx context.Context, req *pb.UpdateTestRequest) (*pb.UpdateTestResponse, error) {
|
||||
if req.Id == 0 {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "test id required")
|
||||
}
|
||||
if req.Content == "" {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "content required")
|
||||
}
|
||||
t, err := s.repo.GetTestByID(uint(req.Id))
|
||||
if err != nil || t == nil {
|
||||
return nil, status.Errorf(codes.NotFound, "test not found")
|
||||
}
|
||||
t.Content = req.Content
|
||||
if err := s.repo.UpdateTest(t); err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to update test: %v", err)
|
||||
}
|
||||
return &pb.UpdateTestResponse{
|
||||
Test: &pb.Test{
|
||||
Id: uint64(t.ID),
|
||||
Content: t.Content,
|
||||
CreatedAt: t.CreatedAt.Format(time.RFC3339),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteTest deletes a test by ID
|
||||
func (s *AuthServer) DeleteTest(ctx context.Context, req *pb.DeleteTestRequest) (*pb.DeleteTestResponse, error) {
|
||||
if req.Id == 0 {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "test id required")
|
||||
}
|
||||
if err := s.repo.DeleteTest(uint(req.Id)); err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to delete test: %v", err)
|
||||
}
|
||||
return &pb.DeleteTestResponse{
|
||||
Success: true,
|
||||
Message: "test deleted",
|
||||
}, nil
|
||||
}
|
||||
Reference in New Issue
Block a user