ms-auth/internal/users/delivery/grpc/handlers.go
Vyacheslav1557 3b03447d2f feat(user):
2024-12-30 20:04:26 +05:00

256 lines
6.1 KiB
Go

package grpc
import (
"context"
"errors"
"git.sch9.ru/new_gate/ms-auth/internal/models"
"git.sch9.ru/new_gate/ms-auth/internal/users"
"git.sch9.ru/new_gate/ms-auth/pkg"
userv1 "git.sch9.ru/new_gate/ms-auth/proto/user/v1"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
"google.golang.org/protobuf/types/known/emptypb"
"google.golang.org/protobuf/types/known/timestamppb"
"strings"
)
type UserHandlers struct {
userv1.UnimplementedUserServiceServer
userUC users.UseCase
}
func NewUserHandlers(gserver *grpc.Server, userUC users.UseCase) {
handlers := &UserHandlers{
userUC: userUC,
}
userv1.RegisterUserServiceServer(gserver, handlers)
}
const (
SessionHeaderName = "x-session-id"
AuthUserHeaderName = "x-auth-user-id"
)
func (h *UserHandlers) Login(ctx context.Context, req *userv1.LoginRequest) (*emptypb.Empty, error) {
const op = "UserHandlers.Login"
var (
err error
user *models.User
)
username := req.GetUsername()
password := req.GetPassword()
user, err = h.userUC.ReadUserByUsername(ctx, username)
if err != nil {
return nil, pkg.ToGRPC(err)
}
err = user.ComparePassword(password)
if err != nil {
return nil, pkg.ToGRPC(pkg.Wrap(pkg.ErrNotFound, err, op, "bad username or password"))
}
sessionId, err := h.userUC.CreateSession(ctx, user.Id, user.Role)
if err != nil {
return nil, pkg.ToGRPC(err)
}
header := metadata.New(map[string]string{
SessionHeaderName: sessionId,
})
err = grpc.SendHeader(ctx, header)
if err != nil {
return nil, err
}
return &emptypb.Empty{}, nil
}
func AuthSessionIdFromContext(ctx context.Context) (string, error) {
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
return "", errors.New("failed to get metadata")
}
tokens := md.Get(SessionHeaderName)
sessionId := strings.Join(tokens, "")
if len(sessionId) == 0 {
return "", errors.New("no session id in context")
}
return sessionId, nil
}
func (h *UserHandlers) Refresh(ctx context.Context, _ *emptypb.Empty) (*emptypb.Empty, error) {
const op = "UserHandlers.Refresh"
sessionId, err := AuthSessionIdFromContext(ctx)
if err != nil {
return nil, pkg.ToGRPC(pkg.Wrap(err, pkg.ErrUnauthenticated, op, "no session id in context"))
}
err = h.userUC.UpdateSession(ctx, sessionId)
if err != nil {
return nil, pkg.ToGRPC(err)
}
return &emptypb.Empty{}, nil
}
func (h *UserHandlers) Logout(ctx context.Context, _ *emptypb.Empty) (*emptypb.Empty, error) {
const op = "UserHandlers.Logout"
sessionId, err := AuthSessionIdFromContext(ctx)
if err != nil {
return nil, pkg.ToGRPC(pkg.Wrap(err, pkg.ErrUnauthenticated, op, "no session id in context"))
}
err = h.userUC.DeleteSession(ctx, sessionId)
if err != nil {
return nil, pkg.ToGRPC(err)
}
return &emptypb.Empty{}, nil
}
func (h *UserHandlers) CompleteLogout(ctx context.Context, _ *emptypb.Empty) (*emptypb.Empty, error) {
const op = "UserHandlers.CompleteLogout"
sessionId, err := AuthSessionIdFromContext(ctx)
if err != nil {
return nil, pkg.ToGRPC(pkg.Wrap(err, pkg.ErrUnauthenticated, op, "no session id in context"))
}
session, err := h.userUC.ReadSession(ctx, sessionId)
if err != nil {
return nil, pkg.ToGRPC(err)
}
err = h.userUC.DeleteAllSessions(ctx, session.UserId)
if err != nil {
return nil, pkg.ToGRPC(err)
}
return &emptypb.Empty{}, nil
}
func (h *UserHandlers) Verify(ctx context.Context, _ *emptypb.Empty) (*emptypb.Empty, error) {
const op = "UserHandlers.Verify"
sessionId, err := AuthSessionIdFromContext(ctx)
if err != nil {
return nil, pkg.ToGRPC(pkg.Wrap(err, pkg.ErrUnauthenticated, op, "no session id in context"))
}
token, err := h.userUC.Verify(ctx, sessionId)
if err != nil {
return nil, pkg.ToGRPC(err)
}
header := metadata.New(map[string]string{
AuthUserHeaderName: token,
})
err = grpc.SendHeader(ctx, header)
if err != nil {
return nil, err
}
return &emptypb.Empty{}, nil
}
func (h *UserHandlers) CreateUser(ctx context.Context, req *userv1.CreateUserRequest) (*userv1.CreateUserResponse, error) {
const op = "UserHandlers.CreateUser"
sessionId, err := AuthSessionIdFromContext(ctx)
if err != nil {
return nil, pkg.ToGRPC(pkg.Wrap(err, pkg.ErrUnauthenticated, op, "no session id in context"))
}
ctx = context.WithValue(ctx, "userId", sessionId)
id, err := h.userUC.CreateUser(
ctx,
req.GetUsername(),
req.GetPassword(),
models.RoleParticipant,
)
if err != nil {
return nil, pkg.ToGRPC(err)
}
return &userv1.CreateUserResponse{
Id: id,
}, nil
}
func (h *UserHandlers) GetUser(ctx context.Context, req *userv1.GetUserRequest) (*userv1.GetUserResponse, error) {
user, err := h.userUC.ReadUserById(
ctx,
req.GetId(),
)
if err != nil {
return nil, pkg.ToGRPC(err)
}
return &userv1.GetUserResponse{
User: &userv1.User{
Id: user.Id,
Username: user.Username,
CreatedAt: timestamppb.New(user.CreatedAt),
ModifiedAt: timestamppb.New(user.ModifiedAt),
Role: userv1.Role(user.Role),
},
}, nil
}
func (h *UserHandlers) UpdateUser(ctx context.Context, req *userv1.UpdateUserRequest) (*emptypb.Empty, error) {
const op = "UserHandlers.UpdateUser"
sessionId, err := AuthSessionIdFromContext(ctx)
if err != nil {
return nil, pkg.ToGRPC(pkg.Wrap(err, pkg.ErrUnauthenticated, op, "no session id in context"))
}
ctx = context.WithValue(ctx, "userId", sessionId)
err = h.userUC.UpdateUser(
ctx,
req.GetId(),
AsStringP(req.Username),
AsMRoleP(req.Role),
)
if err != nil {
return nil, pkg.ToGRPC(err)
}
return &emptypb.Empty{}, nil
}
func (h *UserHandlers) DeleteUser(ctx context.Context, req *userv1.DeleteUserRequest) (*emptypb.Empty, error) {
const op = "UserHandlers.DeleteUser"
sessionId, err := AuthSessionIdFromContext(ctx)
if err != nil {
return nil, pkg.ToGRPC(pkg.Wrap(err, pkg.ErrUnauthenticated, op, "no session id in context"))
}
ctx = context.WithValue(ctx, "userId", sessionId)
err = h.userUC.DeleteUser(
ctx,
req.GetId(),
)
if err != nil {
return nil, pkg.ToGRPC(err)
}
return &emptypb.Empty{}, nil
}
func AsMRoleP(v userv1.Role) *models.Role {
vv := models.Role(v.Number())
return &vv
}
func AsRoleP(v models.Role) *models.Role {
return &v
}
func AsStringP(str string) *string {
return &str
}