add deps struct

This commit is contained in:
Pavel 2023-12-29 21:02:50 +03:00
parent 79eb5da3e3
commit b4ce07515c
6 changed files with 88 additions and 46 deletions

@ -9,6 +9,8 @@ import (
"codeword/internal/services" "codeword/internal/services"
"codeword/internal/utils/encrypt" "codeword/internal/utils/encrypt"
"context" "context"
"fmt"
"go.mongodb.org/mongo-driver/mongo"
"go.uber.org/zap" "go.uber.org/zap"
"time" "time"
) )
@ -29,8 +31,16 @@ func Run(ctx context.Context, cfg initialize.Config, logger *zap.Logger) error {
}) })
userRepo := repository.NewUserRepository(mdb) userRepo := repository.NewUserRepository(mdb)
recoveryEmailSender := &client.RecoveryEmailSender{} recoveryEmailSender := &client.RecoveryEmailSender{}
recoveryService := services.NewRecoveryService(logger, userRepo, recoveryEmailSender, encryptService)
recoveryService := services.NewRecoveryService(services.Deps{
Logger: logger,
Repository: userRepo,
Email: recoveryEmailSender,
EncryptService: encryptService,
})
recoveryController := controller.NewRecoveryController(logger, recoveryService) recoveryController := controller.NewRecoveryController(logger, recoveryService)
server := httpserver.NewServer(httpserver.ServerConfig{ server := httpserver.NewServer(httpserver.ServerConfig{
@ -47,19 +57,46 @@ func Run(ctx context.Context, cfg initialize.Config, logger *zap.Logger) error {
<-ctx.Done() <-ctx.Done()
if err := shutdownApp(server, logger); err != nil { fmt.Println("<-ctx.Done()")
if err := shutdownApp(server, mdb, logger); err != nil {
return err return err
} }
logger.Info("Приложение остановлено") logger.Info("Приложение остановлено")
return nil return nil
} }
func shutdownApp(server *httpserver.Server, logger *zap.Logger) error { // TODO возможно стоит вынести в отдельные файлы или отказаться от разделения на отдельные методы
func shutdownApp(server *httpserver.Server, mdb *mongo.Database, logger *zap.Logger) error {
if err := shutdownHTTPServer(server, logger); err != nil {
return err
}
if err := shutdownMongoDB(mdb, logger); err != nil {
return err
}
return nil
}
func shutdownHTTPServer(server *httpserver.Server, logger *zap.Logger) error {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel() defer cancel()
if err := server.Shutdown(ctx); err != nil { if err := server.Shutdown(ctx); err != nil {
logger.Error("Ошибка при остановке сервера Fiber", zap.Error(err)) logger.Error("Ошибка при остановке HTTP-сервера", zap.Error(err))
return err
}
return nil
}
func shutdownMongoDB(mdb *mongo.Database, logger *zap.Logger) error {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := mdb.Client().Disconnect(ctx); err != nil {
logger.Error("Ошибка при закрытии соединения с MongoDB", zap.Error(err))
return err return err
} }
return nil return nil

@ -9,14 +9,14 @@ import (
) )
type RecoveryController struct { type RecoveryController struct {
Logger *zap.Logger logger *zap.Logger
Service *services.RecoveryService service *services.RecoveryService
} }
func NewRecoveryController(logger *zap.Logger, service *services.RecoveryService) *RecoveryController { func NewRecoveryController(logger *zap.Logger, service *services.RecoveryService) *RecoveryController {
return &RecoveryController{ return &RecoveryController{
Logger: logger, logger: logger,
Service: service, service: service,
} }
} }
@ -24,31 +24,31 @@ func NewRecoveryController(logger *zap.Logger, service *services.RecoveryService
func (r *RecoveryController) HandleRecoveryRequest(c *fiber.Ctx) error { func (r *RecoveryController) HandleRecoveryRequest(c *fiber.Ctx) error {
email := c.FormValue("email") email := c.FormValue("email")
key, err := r.Service.GenerateKey() key, err := r.service.GenerateKey()
if err != nil { if err != nil {
r.Logger.Error("Failed to generate key", zap.Error(err)) r.logger.Error("Failed to generate key", zap.Error(err))
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"}) return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"})
} }
fmt.Println(key) fmt.Println(key)
user, err := r.Service.FindUserByEmail(email) user, err := r.service.FindUserByEmail(email)
if err != nil { if err != nil {
r.Logger.Error("Failed to find user by email", zap.Error(err)) r.logger.Error("Failed to find user by email", zap.Error(err))
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "User not found"}) return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "User not found"})
} }
fmt.Println(user) fmt.Println(user)
// сохраняем в бд // сохраняем в бд
signature, err := r.Service.StoreRecoveryRecord("user") signature, err := r.service.StoreRecoveryRecord("user")
if err != nil { if err != nil {
r.Logger.Error("Failed to store recovery record", zap.Error(err)) r.logger.Error("Failed to store recovery record", zap.Error(err))
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"}) return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"})
} }
// тут что-то на подобии канала или что-то подобное так как отправка выполнятеся в воркере, // тут что-то на подобии канала или что-то подобное так как отправка выполнятеся в воркере,
//это пока временное решение для написания структуры кода и проверки отправки, далее перепишу //это пока временное решение для написания структуры кода и проверки отправки, далее перепишу
// под горутины // под горутины
err = r.Service.SendRecoveryEmail(email, signature) err = r.service.SendRecoveryEmail(email, signature)
if err != nil { if err != nil {
r.Logger.Error("Failed to send recovery email", zap.Error(err)) r.logger.Error("Failed to send recovery email", zap.Error(err))
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"}) return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"})
} }
@ -59,21 +59,21 @@ func (r *RecoveryController) HandleRecoveryRequest(c *fiber.Ctx) error {
func (r *RecoveryController) HandleRecoveryLink(c *fiber.Ctx) error { func (r *RecoveryController) HandleRecoveryLink(c *fiber.Ctx) error {
signature := c.Params("sign") signature := c.Params("sign")
// тут получается // тут получается
record, err := r.Service.GetRecoveryRecord(signature) record, err := r.service.GetRecoveryRecord(signature)
if err != nil { if err != nil {
r.Logger.Error("Failed to get recovery record", zap.Error(err)) r.logger.Error("Failed to get recovery record", zap.Error(err))
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"}) return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"})
} }
// проверка на более чем 15 минут // проверка на более чем 15 минут
if time.Since(record.CreatedAt) > 15*time.Minute { if time.Since(record.CreatedAt) > 15*time.Minute {
r.Logger.Error("Recovery link expired", zap.String("signature", signature)) r.logger.Error("Recovery link expired", zap.String("signature", signature))
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "Recovery link expired"}) return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "Recovery link expired"})
} }
tokens, err := r.Service.ExchangeForTokens(record.UserID) tokens, err := r.service.ExchangeForTokens(record.UserID)
if err != nil { if err != nil {
r.Logger.Error("Failed to exchange recovery link for tokens", zap.Error(err)) r.logger.Error("Failed to exchange recovery link for tokens", zap.Error(err))
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"}) return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"})
} }

@ -14,9 +14,9 @@ type Config struct {
MongoPassword string `env:"MONGO_PASSWORD" envDefault:"admin"` MongoPassword string `env:"MONGO_PASSWORD" envDefault:"admin"`
MongoDatabase string `env:"MONGO_DB" envDefault:"codeword_db"` MongoDatabase string `env:"MONGO_DB" envDefault:"codeword_db"`
MongoAuth string `env:"MONGO_AUTH" envDefault:"admin"` MongoAuth string `env:"MONGO_AUTH" envDefault:"admin"`
PublicCurveKey string `env:"PUBLIC_CURVE_KEY,required"` PublicCurveKey string `env:"PUBLIC_CURVE_KEY" envDefault:"test"`
PrivateCurveKey string `env:"PRIVATE_CURVE_KEY,required"` PrivateCurveKey string `env:"PRIVATE_CURVE_KEY" envDefault:"test"`
SignSecret string `env:"SIGN_SECRET,required"` SignSecret string `env:"SIGN_SECRET" envDefault:"test"`
} }
func LoadConfig() (*Config, error) { func LoadConfig() (*Config, error) {

@ -12,6 +12,8 @@ type UserRepository struct {
db *mongo.Database db *mongo.Database
} }
//todo реализовать
func NewUserRepository(db *mongo.Database) *UserRepository { func NewUserRepository(db *mongo.Database) *UserRepository {
return &UserRepository{db} return &UserRepository{db}
} }
@ -28,8 +30,6 @@ func (r *UserRepository) StoreRecoveryRecord(userID, signature string, createdAt
} }
func (r *UserRepository) GetRecoveryRecord(signature string) (*models.RestoreRequest, error) { func (r *UserRepository) GetRecoveryRecord(signature string) (*models.RestoreRequest, error) {
//todo
return &models.RestoreRequest{UserID: "123", Sign: signature, CreatedAt: time.Now()}, nil return &models.RestoreRequest{UserID: "123", Sign: signature, CreatedAt: time.Now()}, nil
} }

@ -38,6 +38,14 @@ func NewServer(config ServerConfig) *Server {
return s return s
} }
func (s *Server) Start(addr string) error {
return s.app.Listen(addr)
}
func (s *Server) Shutdown(ctx context.Context) error {
return s.app.Shutdown()
}
func (s *Server) registerRoutes() { func (s *Server) registerRoutes() {
s.app.Get("/liveness", s.handleLiveness) s.app.Get("/liveness", s.handleLiveness)
s.app.Get("/readiness", s.handleReadiness) s.app.Get("/readiness", s.handleReadiness)
@ -64,11 +72,3 @@ func (s *Server) handleReadiness(c *fiber.Ctx) error {
return c.Status(fiber.StatusOK).SendString(responseMessage) return c.Status(fiber.StatusOK).SendString(responseMessage)
} }
func (s *Server) Start(addr string) error {
return s.app.Listen(addr)
}
func (s *Server) Shutdown(ctx context.Context) error {
return s.app.Shutdown()
}

@ -17,21 +17,26 @@ type EmailSender interface {
SendRecoveryEmail(email, signature string) error SendRecoveryEmail(email, signature string) error
} }
// todo deps type Deps struct {
type RecoveryService struct {
Logger *zap.Logger Logger *zap.Logger
Repository UserRepository Repository UserRepository
Email EmailSender Email EmailSender
EncryptService *encrypt.Encrypt EncryptService *encrypt.Encrypt
} }
func NewRecoveryService(logger *zap.Logger, repository UserRepository, email EmailSender, encryptService *encrypt.Encrypt) *RecoveryService { type RecoveryService struct {
logger *zap.Logger
repository UserRepository
email EmailSender
encryptService *encrypt.Encrypt
}
func NewRecoveryService(deps Deps) *RecoveryService {
return &RecoveryService{ return &RecoveryService{
Logger: logger, logger: deps.Logger,
Repository: repository, repository: deps.Repository,
Email: email, email: deps.Email,
EncryptService: encryptService, encryptService: deps.EncryptService,
} }
} }
@ -43,25 +48,25 @@ func (s *RecoveryService) GenerateKey() (string, error) {
// FindUserByEmail ищет пользователя по электронной почте // FindUserByEmail ищет пользователя по электронной почте
func (s *RecoveryService) FindUserByEmail(email string) (*models.User, error) { func (s *RecoveryService) FindUserByEmail(email string) (*models.User, error) {
return s.Repository.FindByEmail(email) return s.repository.FindByEmail(email)
} }
// StoreRecoveryRecord сохраняет запись восстановления в базе данных // StoreRecoveryRecord сохраняет запись восстановления в базе данных
func (s *RecoveryService) StoreRecoveryRecord(userID string) (string, error) { func (s *RecoveryService) StoreRecoveryRecord(userID string) (string, error) {
signature := "" signature := ""
createdAt := time.Now() createdAt := time.Now()
err := s.Repository.StoreRecoveryRecord(userID, signature, createdAt) err := s.repository.StoreRecoveryRecord(userID, signature, createdAt)
return signature, err return signature, err
} }
// GetRecoveryRecord получает запись восстановления из базы данных // GetRecoveryRecord получает запись восстановления из базы данных
func (s *RecoveryService) GetRecoveryRecord(signature string) (*models.RestoreRequest, error) { func (s *RecoveryService) GetRecoveryRecord(signature string) (*models.RestoreRequest, error) {
return s.Repository.GetRecoveryRecord(signature) return s.repository.GetRecoveryRecord(signature)
} }
// SendRecoveryEmail посылает письмо для восстановления доступа пользователю // SendRecoveryEmail посылает письмо для восстановления доступа пользователю
func (s *RecoveryService) SendRecoveryEmail(email string, signature string) error { func (s *RecoveryService) SendRecoveryEmail(email string, signature string) error {
return s.Email.SendRecoveryEmail(email, signature) return s.email.SendRecoveryEmail(email, signature)
} }
// ExchangeForTokens обменивает ссылку восстановления на токены используя сервис аутентификации. // ExchangeForTokens обменивает ссылку восстановления на токены используя сервис аутентификации.