refactor:

This commit is contained in:
Vyacheslav1557 2024-08-16 16:05:29 +05:00
parent ad8d145986
commit 3c0f01630f
29 changed files with 360 additions and 1377 deletions

View file

@ -6,15 +6,10 @@ import (
)
type Config struct {
Env string `env:"ENV" env-default:"prod"`
Env string `env:"ENV" env-default:"prod"`
Pandoc string `env:"PANDOC" required:"true"`
PostgresDSN string `env:"POSTGRES_DSN" required:"true"`
RedisDSN string `env:"REDIS_DSN" required:"true"`
Email string `env:"EMAIL" required:"true"`
Password string `env:"PASSWORD" required:"true"`
JWTSecret string `env:"JWT_SECRET" required:"true"`
JWTSecret string `env:"JWT_SECRET" required:"true"`
}
func MustSetupConfig() *Config {

View file

@ -11,12 +11,5 @@ var (
)
var (
ErrBadHandleOrPassword = errors.New("bad handle or password")
ErrBadRole = errors.New("bad role")
ErrTooShortPassword = errors.New("too short password")
ErrTooLongPassword = errors.New("too long password")
ErrBadEmail = errors.New("bad email")
ErrBadUsername = errors.New("bad username")
ErrTooShortUsername = errors.New("too short username")
ErrTooLongUsername = errors.New("too long username")
ErrBadRole = errors.New("bad role")
)

View file

@ -4,29 +4,6 @@ import (
"time"
)
const (
RoleSpectator int32 = 0
RoleParticipant int32 = 1
RoleModerator int32 = 2
RoleAdmin int32 = 3
)
func IsAdmin(role int32) bool {
return role == RoleAdmin
}
func IsModerator(role int32) bool {
return role == RoleModerator
}
func IsParticipant(role int32) bool {
return role == RoleParticipant
}
func IsSpectator(role int32) bool {
return role == RoleSpectator
}
func AsTimeP(t time.Time) *time.Time {
return &t
}

View file

@ -1,19 +0,0 @@
package lib
import (
"fmt"
"net/smtp"
)
func SendMail(cfg Config, to []string, subject, body string) error {
auth := smtp.PlainAuth("", cfg.Email, cfg.Password, "smtp.gmail.com")
msg := fmt.Sprintf("From: %s\nTo: %s\nSubject: %s\n%s", cfg.Email, "", subject, body)
err := smtp.SendMail("smtp.gmail.com:587", auth, cfg.Email, to, []byte(msg))
if err != nil {
return err // FIXME
}
return nil
}

View file

@ -1,44 +0,0 @@
package lib
import (
"net/mail"
)
func ValidPassword(str string) error {
if len(str) < 5 {
return ErrTooShortPassword
}
if len(str) > 70 {
return ErrTooLongPassword
}
return nil
}
func ValidUsername(str string) error {
if len(str) < 5 {
return ErrTooShortUsername
}
if len(str) > 70 {
return ErrTooLongUsername
}
if err := ValidEmail(str); err == nil {
return ErrBadUsername
}
return nil
}
func ValidEmail(str string) error {
emailAddress, err := mail.ParseAddress(str)
if err != nil || emailAddress.Address != str {
return ErrBadEmail
}
return nil
}
func ValidRole(role int32) error {
switch role {
case RoleSpectator, RoleParticipant, RoleModerator, RoleAdmin:
return nil
}
return ErrBadRole
}

View file

@ -0,0 +1,8 @@
package models
type Contest struct {
Id *int `db:"id"`
Name *string `db:"name"`
//CreatedAt time.Time `db:"created_at"` FIXME
//UpdatedAt time.Time `db:"updated_at"` FIXME
}

View file

@ -0,0 +1,12 @@
package models
import "time"
type Language struct {
Id *int32 `db:"id"`
Name *string `db:"name"`
BuildFileHash *string `db:"build_file_hash"`
ExecuteFileHash *string `db:"execute_file_hash"`
CreatedAt *time.Time `db:"created_at"`
UpdatedAt *time.Time `db:"updated_at"`
}

View file

@ -0,0 +1,13 @@
package models
import "time"
type Problem struct {
Id *int32 `db:"id"`
Name *string `db:"name"`
Description *string `db:"description"`
TimeLimit *int32 `db:"time_limit"`
MemoryLimit *int32 `db:"memory_limit"`
CreatedAt *time.Time `db:"created_at"`
UpdatedAt *time.Time `db:"updated_at"`
}

44
internal/models/role.go Normal file
View file

@ -0,0 +1,44 @@
package models
import "git.sch9.ru/new_gate/ms-tester/internal/lib"
type Role int32
const (
RoleSpectator Role = 0
RoleParticipant Role = 1
RoleModerator Role = 2
RoleAdmin Role = 3
)
func (role Role) IsAdmin() bool {
return role == RoleAdmin
}
func (role Role) IsModerator() bool {
return role == RoleModerator
}
func (role Role) IsParticipant() bool {
return role == RoleParticipant
}
func (role Role) IsSpectator() bool {
return role == RoleSpectator
}
func (role Role) AtLeast(other Role) bool {
return role >= other
}
func (role Role) AtMost(other Role) bool {
return role <= other
}
func (role Role) Valid() error {
switch role {
case RoleSpectator, RoleParticipant, RoleModerator, RoleAdmin:
return nil
}
return lib.ErrBadRole
}

View file

@ -0,0 +1,14 @@
package models
import "time"
type Solution struct {
Id *int32 `db:"id"`
ParticipantId *int32 `db:"participant_id"`
ProblemId *int32 `db:"problem_id"`
LanguageId *int32 `db:"language_id"`
ContestId *int32 `db:"contest_id"`
SolutionHash *string `db:"solution_hash"`
Result *int32 `db:"result"`
CreatedAt *time.Time `db:"created_at"`
}

View file

@ -0,0 +1,30 @@
package services
import (
"context"
"git.sch9.ru/new_gate/ms-tester/internal/models"
)
type ProblemStorage interface {
CreateProblem(ctx context.Context, problem *models.Problem) (int32, error)
ReadProblem(ctx context.Context, id int32) (*models.Problem, error)
UpdateProblem(ctx context.Context, problem *models.Problem) error
DeleteProblem(ctx context.Context, id int32) error
}
type ProblemService struct {
problemStorage ProblemStorage
}
func NewProblemService(
problemStorage ProblemStorage,
) *ProblemService {
return &ProblemService{
problemStorage: problemStorage,
}
}
func (service *ProblemService) CreateProblem(ctx context.Context, problem *models.Problem) (int32, error) {
userId := ctx.Value("user_id").(int32)
return service.problemStorage.CreateProblem(ctx, problem)
}

View file

@ -3,11 +3,11 @@ package storage
import (
"context"
"errors"
"git.sch9.ru/new_gate/ms-tester/internal/lib"
"github.com/jackc/pgerrcode"
"github.com/jackc/pgx/v5/pgconn"
"go.uber.org/zap"
"golang.org/x/crypto/bcrypt"
"ms-auth/internal/lib"
"strings"
"time"

View file

@ -1,332 +0,0 @@
package storage
import (
"context"
"encoding/json"
"errors"
"go.uber.org/zap"
"time"
"ms-auth/internal/lib"
"github.com/golang-jwt/jwt"
"github.com/google/uuid"
"github.com/valkey-io/valkey-go"
"github.com/valkey-io/valkey-go/valkeylock"
)
type ValkeyStorage struct {
db valkey.Client
locker valkeylock.Locker
cfg *lib.Config
logger *zap.Logger
}
func NewValkeyStorage(dsn string, cfg *lib.Config, logger *zap.Logger) *ValkeyStorage {
opts, err := valkey.ParseURL(dsn)
if err != nil {
panic(err.Error())
}
db, err := valkey.NewClient(opts)
if err != nil {
panic(err.Error())
}
locker, err := valkeylock.NewLocker(valkeylock.LockerOption{
ClientOption: opts,
KeyMajority: 1,
NoLoopTracking: true,
})
if err != nil {
panic(err.Error())
}
return &ValkeyStorage{
db: db,
locker: locker,
cfg: cfg,
logger: logger,
}
}
func (storage *ValkeyStorage) Stop() error {
storage.db.Close()
storage.locker.Close()
return nil
}
const (
sessionLifetime = time.Minute * 40
confirmationLifetime = time.Hour * 5
)
func (storage *ValkeyStorage) CreateSession(
ctx context.Context,
user_id int32,
) error {
session := NewSession(user_id)
resp := storage.db.Do(ctx, storage.db.
B().Set().
Key(string(*session.UserId)).
Value(*session.Id).
Nx().
Exat(time.Now().Add(sessionLifetime)).
Build(),
)
if err := resp.Error(); err != nil {
storage.logger.Error(err.Error())
return lib.ErrInternal
}
return nil
}
func (storage *ValkeyStorage) ReadSessionByToken(ctx context.Context, token string) (*Session, error) {
session, err := Parse(token, storage.cfg.JWTSecret)
if err != nil {
storage.logger.Error(err.Error())
return nil, err
}
real_session, err := storage.ReadSessionByUserId(ctx, *session.UserId)
if err != nil {
storage.logger.Error(err.Error())
return nil, err
}
if *session.Id != *real_session.Id {
storage.logger.Error(err.Error())
return nil, lib.ErrInternal
}
return session, err
}
func (storage *ValkeyStorage) ReadSessionByUserId(ctx context.Context, user_id int32) (*Session, error) {
resp := storage.db.Do(ctx, storage.db.B().Get().Key(string(user_id)).Build())
if err := resp.Error(); err != nil {
storage.logger.Error(err.Error())
return nil, lib.ErrInternal
}
id, err := resp.ToString()
if err != nil {
storage.logger.Error(err.Error())
return nil, lib.ErrInternal
}
return &Session{
Id: &id,
UserId: &user_id,
}, err
}
func (storage *ValkeyStorage) UpdateSession(ctx context.Context, session *Session) error {
resp := storage.db.Do(ctx, storage.db.
B().Set().
Key(string(*session.UserId)).
Value(*session.Id).
Xx().
Exat(time.Now().Add(sessionLifetime)).
Build(),
)
if err := resp.Error(); err != nil {
storage.logger.Error(err.Error())
return lib.ErrInternal
}
return nil
}
func (storage *ValkeyStorage) DeleteSessionByToken(ctx context.Context, token string) error {
session, err := Parse(token, storage.cfg.JWTSecret)
if err != nil {
storage.logger.Error(err.Error())
return err
}
err = storage.DeleteSessionByUserId(ctx, *session.UserId)
if err != nil {
storage.logger.Error(err.Error())
return err
}
return nil
}
func (storage *ValkeyStorage) DeleteSessionByUserId(ctx context.Context, user_id int32) error {
resp := storage.db.Do(ctx, storage.db.
B().Del().
Key(string(user_id)).
Build(),
)
if err := resp.Error(); err != nil {
storage.logger.Error(err.Error())
return lib.ErrInternal
}
return nil
}
func (storage *ValkeyStorage) CreateConfirmation(ctx context.Context, conf *Confirmation) error {
resp := storage.db.Do(ctx, storage.db.
B().Set().
Key(*conf.Id).
Value(string(conf.JSON())).
Exat(time.Now().Add(confirmationLifetime)).
Build(),
)
if err := resp.Error(); err != nil {
storage.logger.Error(err.Error())
return lib.ErrInternal
}
return nil
}
func (storage *ValkeyStorage) ReadConfirmation(ctx context.Context, conf_id string) (*Confirmation, error) {
resp := storage.db.Do(ctx, storage.db.
B().Get().
Key(conf_id).
Build(),
)
if err := resp.Error(); err != nil {
storage.logger.Error(err.Error())
return nil, lib.ErrInternal
}
b, err := resp.AsBytes()
if err != nil {
storage.logger.Error(err.Error())
return nil, lib.ErrInternal
}
var conf Confirmation
err = json.Unmarshal(b, &conf)
if err != nil {
storage.logger.Error(err.Error())
return nil, lib.ErrInternal
}
return &conf, nil
}
func (storage *ValkeyStorage) DeleteConfirmation(ctx context.Context, conf_id string) error {
resp := storage.db.Do(ctx, storage.db.
B().Del().
Key(conf_id).
Build(),
)
if err := resp.Error(); err != nil {
storage.logger.Error(err.Error())
return lib.ErrInternal
}
return nil
}
var (
ErrBadSession = errors.New("bad session")
ErrBadConfirmation = errors.New("bad confirmation")
)
type Confirmation struct {
Id *string `json:"id"`
UserId *int32 `json:"user_id,omitempty"`
Email *string `json:"email"`
}
func NewConfirmation(userId *int32, email string) (*Confirmation, error) {
c := &Confirmation{
Id: lib.AsStringP(uuid.NewString()),
UserId: userId,
Email: &email,
}
if err := c.Valid(); err != nil {
return nil, err
}
return c, nil
}
func (c *Confirmation) Valid() error {
if c.Id == nil {
return ErrBadConfirmation
}
// FIXME
// if c.userId == nil {
// return ErrBadConfirmation
// }
if c.Email == nil {
return ErrBadConfirmation
}
if err := lib.ValidEmail(*c.Email); err != nil {
return err
}
return nil
}
func (c *Confirmation) JSON() []byte {
b, err := json.Marshal(c)
if err != nil {
panic(err.Error())
}
return b
}
type Session struct {
Id *string
UserId *int32
}
func NewSession(userId int32) *Session {
return &Session{
Id: lib.AsStringP(uuid.NewString()),
UserId: &userId,
}
}
func (s Session) Valid() error {
if s.Id == nil {
return ErrBadSession
}
if s.UserId == nil {
return ErrBadSession
}
return nil
}
func (s Session) Token(secret string) (string, error) {
if err := s.Valid(); err != nil {
return "", err
}
refreshToken := jwt.NewWithClaims(jwt.SigningMethodHS256, s)
str, err := refreshToken.SignedString([]byte(secret))
if err != nil {
return "", ErrBadSession
}
return str, nil
}
func Parse(tkn string, secret string) (*Session, error) {
parsedToken, err := jwt.ParseWithClaims(tkn, &Session{}, func(token *jwt.Token) (interface{}, error) {
return []byte(secret), nil
})
if err != nil {
return nil, ErrBadSession
}
session := parsedToken.Claims.(*Session)
if err := session.Valid(); err != nil {
return nil, err
}
return session, nil
}

View file

@ -1,11 +0,0 @@
package transport
import (
"context"
"google.golang.org/protobuf/types/known/emptypb"
emailv1 "ms-auth/pkg/go/gen/email/v1"
)
func (s *AuthServer) SendEmail(ctx context.Context, req *emailv1.SendEmailRequest) (*emptypb.Empty, error) {
panic("not implemented")
}

View file

@ -1 +1,25 @@
package transport
import (
"context"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
type ReqWithToken interface {
GetToken() string
}
func (s *TesterServer) AuthInterceptor() grpc.UnaryServerInterceptor {
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
reqWithToken, ok := req.(ReqWithToken)
if !ok {
return nil, status.Errorf(codes.Unknown, "") // FIXME
}
token := reqWithToken.GetToken()
return handler(ctx, req)
}
}

View file

@ -2,93 +2,40 @@ package transport
import (
"context"
"git.sch9.ru/new_gate/ms-tester/internal/models"
testerv1 "git.sch9.ru/new_gate/ms-tester/pkg/go/gen/tester/v1"
"go.uber.org/zap"
"google.golang.org/protobuf/types/known/timestamppb"
"ms-auth/internal/storage"
emailv1 "ms-auth/pkg/go/gen/email/v1"
sessionv1 "ms-auth/pkg/go/gen/session/v1"
userv1 "ms-auth/pkg/go/gen/user/v1"
"net"
"time"
"google.golang.org/grpc"
)
type SessionServiceI interface {
Create(ctx context.Context, handle, password string) (*string, error)
Read(ctx context.Context, token string) (*int32, error)
Update(ctx context.Context, token string) error
Delete(ctx context.Context, token string) error
type ProblemService interface {
CreateProblem(ctx context.Context, problem *models.Problem) (int32, error)
ReadProblem(ctx context.Context, id int32) (*models.Problem, error)
UpdateProblem(ctx context.Context, problem *models.Problem) error
DeleteProblem(ctx context.Context, id int32) error
}
type UserServiceI interface {
CreateUser(ctx context.Context, token, username, password string, email *string, expiresAt *time.Time, role *int32) (*int32, error)
ReadUser(ctx context.Context, token string, id int32) (*storage.User, error)
UpdateUser(ctx context.Context, token string, id int32, username *string, password *string, email *string, expiresAt *time.Time, role *int32) error
DeleteUser(ctx context.Context, token string, id int32) error
}
type AuthServer struct {
emailv1.UnimplementedEmailServiceServer
sessionv1.UnimplementedSessionServiceServer
sessionService SessionServiceI
userv1.UnimplementedUserServiceServer
userService UserServiceI
type TesterServer struct {
testerv1.UnimplementedTesterServiceServer
problemService ProblemService
gRPCServer *grpc.Server
logger *zap.Logger
}
// NewAuthServer creates a new instance of the AuthServer struct.
//
// Parameters:
// - sessionService: A pointer to the SessionServiceI interface.
// - gRPCServer: A pointer to the grpc.Server struct.
// - logger: A pointer to the zap.Logger struct.
//
// Returns:
// - *AuthServer: A pointer to the AuthServer struct.
func NewAuthServer(sessionService SessionServiceI, userService UserServiceI, gRPCServer *grpc.Server, logger *zap.Logger) *AuthServer {
return &AuthServer{
sessionService: sessionService,
userService: userService,
func NewTesterServer(problemService ProblemService, gRPCServer *grpc.Server, logger *zap.Logger) *TesterServer {
server := &TesterServer{
problemService: problemService,
gRPCServer: gRPCServer,
logger: logger,
}
}
// Start starts the AuthServer and listens on port :8090.
//
// It creates a listener on the specified address and starts serving incoming requests.
// It also logs the server start and any errors that occur during serving.
//
// No parameters.
// No return values.
func (s *AuthServer) Start() {
lis, err := net.Listen("tcp", ":8090")
if err != nil {
s.logger.Fatal("")
}
testerv1.RegisterTesterServiceServer(gRPCServer, server)
sessionv1.RegisterSessionServiceServer(s.gRPCServer, s)
go func() {
s.logger.Info("Listening on :8090")
if err := s.gRPCServer.Serve(lis); err != nil {
panic(err.Error())
}
}()
s.logger.Info("server started")
}
// GracefullyStop stops the server gracefully.
//
// No parameters.
// No return values.
func (s *AuthServer) GracefullyStop() {
s.gRPCServer.GracefulStop()
s.logger.Info("server stopped")
return server
}
func AsTimeP(t *timestamppb.Timestamp) *time.Time {
@ -99,25 +46,9 @@ func AsTimeP(t *timestamppb.Timestamp) *time.Time {
return &tt
}
func AsInt32P(v *userv1.Role) *int32 {
if v == nil {
return nil
}
vv := int32(v.Number())
return &vv
}
func AsTimestampP(t *time.Time) *timestamppb.Timestamp {
if t == nil {
return nil
}
return timestamppb.New(*t)
}
func AsRoleP(r *int32) *userv1.Role {
if r == nil {
return nil
}
rr := userv1.Role(*r)
return &rr
}

View file

@ -1,45 +0,0 @@
package transport
import (
"context"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/emptypb"
sessionv1 "ms-auth/pkg/go/gen/session/v1"
)
func (s *AuthServer) Create(ctx context.Context, req *sessionv1.CreateSessionRequest) (*sessionv1.CreateSessionResponse, error) {
token, err := s.sessionService.Create(ctx, req.GetHandle(), req.GetPassword())
if err != nil {
return nil, status.Errorf(codes.Unknown, err.Error()) // FIXME
}
return &sessionv1.CreateSessionResponse{
Token: *token,
}, nil
}
func (s *AuthServer) Read(ctx context.Context, req *sessionv1.ReadSessionRequest) (*sessionv1.ReadSessionResponse, error) {
id, err := s.sessionService.Read(ctx, req.GetToken())
if err != nil {
return nil, status.Errorf(codes.Unknown, err.Error()) // FIXME
}
return &sessionv1.ReadSessionResponse{
UserId: *id,
}, nil
}
func (s *AuthServer) Update(ctx context.Context, req *sessionv1.UpdateSessionRequest) (*emptypb.Empty, error) {
err := s.sessionService.Update(ctx, req.GetToken())
if err != nil {
return nil, status.Errorf(codes.Unknown, err.Error()) // FIXME
}
return &emptypb.Empty{}, nil
}
func (s *AuthServer) Delete(ctx context.Context, req *sessionv1.DeleteSessionRequest) (*emptypb.Empty, error) {
err := s.sessionService.Delete(ctx, req.GetToken())
if err != nil {
return nil, status.Errorf(codes.Unknown, err.Error()) // FIXME
}
return &emptypb.Empty{}, nil
}

View file

@ -0,0 +1,82 @@
package transport
import (
"context"
"git.sch9.ru/new_gate/ms-tester/internal/lib"
"git.sch9.ru/new_gate/ms-tester/internal/models"
testerv1 "git.sch9.ru/new_gate/ms-tester/pkg/go/gen/tester/v1"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/emptypb"
)
func (s *TesterServer) CreateProblem(ctx context.Context, req *testerv1.CreateProblemRequest) (*testerv1.CreateProblemResponse, error) {
problem := req.GetProblem()
if problem == nil {
return nil, status.Errorf(codes.Unknown, "") // FIXME
}
id, err := s.problemService.CreateProblem(
ctx,
&models.Problem{
Name: lib.AsStringP(problem.Name),
Description: lib.AsStringP(problem.Description),
TimeLimit: lib.AsInt32P(problem.TimeLimit),
MemoryLimit: lib.AsInt32P(problem.MemoryLimit),
},
)
if err != nil {
return nil, status.Errorf(codes.Unknown, err.Error()) // FIXME
}
return &testerv1.CreateProblemResponse{
Id: id,
}, nil
}
func (s *TesterServer) ReadProblem(ctx context.Context, req *testerv1.ReadProblemRequest) (*testerv1.ReadProblemResponse, error) {
problem, err := s.problemService.ReadProblem(ctx, req.GetId())
if err != nil {
return nil, status.Errorf(codes.Unknown, err.Error()) // FIXME
}
return &testerv1.ReadProblemResponse{
Problem: &testerv1.ReadProblemResponse_Problem{
Id: *problem.Id,
Name: *problem.Name,
Description: *problem.Description,
TimeLimit: *problem.TimeLimit,
MemoryLimit: *problem.MemoryLimit,
CreatedAt: AsTimestampP(problem.CreatedAt),
UpdatedAt: AsTimestampP(problem.UpdatedAt),
},
}, nil
}
func (s *TesterServer) UpdateProblem(ctx context.Context, req *testerv1.UpdateProblemRequest) (*emptypb.Empty, error) {
problem := req.GetProblem()
if problem == nil {
return nil, status.Errorf(codes.Unknown, "") // FIXME
}
err := s.problemService.UpdateProblem(
ctx,
&models.Problem{
Id: lib.AsInt32P(problem.Id),
Name: problem.Name,
Description: problem.Description,
TimeLimit: problem.TimeLimit,
MemoryLimit: problem.MemoryLimit,
},
)
if err != nil {
return nil, status.Errorf(codes.Unknown, err.Error()) // FIXME
}
return &emptypb.Empty{}, nil
}
func (s *TesterServer) DeleteProblem(ctx context.Context, req *testerv1.DeleteProblemRequest) (*emptypb.Empty, error) {
err := s.problemService.DeleteProblem(ctx, req.GetId())
if err != nil {
return nil, status.Errorf(codes.Unknown, err.Error()) // FIXME
}
return &emptypb.Empty{}, nil
}

View file

@ -1,124 +0,0 @@
package transport
import (
"context"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/emptypb"
userv1 "ms-auth/pkg/go/gen/user/v1"
"strings"
)
func (s *AuthServer) CreateUser(ctx context.Context, req *userv1.CreateUserRequest) (*userv1.CreateUserResponse, error) {
user := req.GetUser()
if user == nil {
return nil, status.Errorf(codes.Unknown, "") // FIXME
}
id, err := s.userService.CreateUser(
ctx,
req.GetToken(),
user.GetUsername(),
user.GetPassword(),
user.Email,
AsTimeP(user.ExpiresAt),
AsInt32P(user.Role),
)
if err != nil {
return nil, status.Errorf(codes.Unknown, err.Error()) // FIXME
}
return &userv1.CreateUserResponse{
Id: *id,
}, nil
}
func (s *AuthServer) ReadUser(ctx context.Context, req *userv1.ReadUserRequest) (*userv1.ReadUserResponse, error) {
user, err := s.userService.ReadUser(
ctx,
req.GetToken(),
req.GetId(),
)
if err != nil {
return nil, status.Errorf(codes.Unknown, err.Error()) // FIXME
}
return &userv1.ReadUserResponse{
User: &userv1.ReadUserResponse_User{
Id: user.Id,
Username: user.Username,
Email: user.Email,
ExpiresAt: AsTimestampP(&user.ExpiresAt),
CreatedAt: AsTimestampP(&user.CreatedAt),
Role: *AsRoleP(&user.Role),
},
}, nil
}
func (s *AuthServer) UpdateUser(ctx context.Context, req *userv1.UpdateUserRequest) (*emptypb.Empty, error) {
user := req.GetUser()
if user == nil {
return nil, status.Errorf(codes.Unknown, "") // FIXME
}
err := s.userService.UpdateUser(
ctx,
req.GetToken(),
user.GetId(),
user.Username,
user.Password,
user.Email,
AsTimeP(user.ExpiresAt),
AsInt32P(user.Role),
)
if err != nil {
return nil, status.Errorf(codes.Unknown, err.Error()) // FIXME
}
return &emptypb.Empty{}, nil
}
func (s *AuthServer) DeleteUser(ctx context.Context, req *userv1.DeleteUserRequest) (*emptypb.Empty, error) {
err := s.userService.DeleteUser(
ctx,
req.GetToken(),
req.GetId(),
)
if err != nil {
return nil, status.Errorf(codes.Unknown, err.Error()) // FIXME
}
return &emptypb.Empty{}, nil
}
func (s *AuthServer) ConfirmEmail(ctx context.Context, req *userv1.ConfirmEmailRequest) (*emptypb.Empty, error) {
panic("not implemented")
}
func (s *AuthServer) RegisterUser(ctx context.Context, req *userv1.RegisterUserRequest) (*emptypb.Empty, error) {
panic("not implemented")
}
func (s *AuthServer) ConfirmRegisterUser(ctx context.Context, req *userv1.ConfirmRegisterUserRequest) (*emptypb.Empty, error) {
panic("not implemented")
}
func (s *AuthServer) ResetPassword(ctx context.Context, req *userv1.ResetPasswordRequest) (*emptypb.Empty, error) {
panic("not implemented")
}
func (s *AuthServer) ConfirmResetPassword(ctx context.Context, req *userv1.ConfirmResetPasswordRequest) (*emptypb.Empty, error) {
panic("not implemented")
}
func shortenEmail(email *string) *string {
if email == nil {
return nil
}
parts := strings.Split(*email, "@")
p1 := parts[0]
p2 := parts[1]
a := "****"
if len(p1) <= 4 {
e := a + "@" + p2
return &e
}
e := p1[:len(p1)-4] + a + "@" + p2
return &e
}