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/utils/encrypt"
"context"
"fmt"
"go.mongodb.org/mongo-driver/mongo"
"go.uber.org/zap"
"time"
)
@ -29,8 +31,16 @@ func Run(ctx context.Context, cfg initialize.Config, logger *zap.Logger) error {
})
userRepo := repository.NewUserRepository(mdb)
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)
server := httpserver.NewServer(httpserver.ServerConfig{
@ -47,19 +57,46 @@ func Run(ctx context.Context, cfg initialize.Config, logger *zap.Logger) error {
<-ctx.Done()
if err := shutdownApp(server, logger); err != nil {
fmt.Println("<-ctx.Done()")
if err := shutdownApp(server, mdb, logger); err != nil {
return err
}
logger.Info("Приложение остановлено")
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)
defer cancel()
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 nil

@ -9,14 +9,14 @@ import (
)
type RecoveryController struct {
Logger *zap.Logger
Service *services.RecoveryService
logger *zap.Logger
service *services.RecoveryService
}
func NewRecoveryController(logger *zap.Logger, service *services.RecoveryService) *RecoveryController {
return &RecoveryController{
Logger: logger,
Service: service,
logger: logger,
service: service,
}
}
@ -24,31 +24,31 @@ func NewRecoveryController(logger *zap.Logger, service *services.RecoveryService
func (r *RecoveryController) HandleRecoveryRequest(c *fiber.Ctx) error {
email := c.FormValue("email")
key, err := r.Service.GenerateKey()
key, err := r.service.GenerateKey()
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"})
}
fmt.Println(key)
user, err := r.Service.FindUserByEmail(email)
user, err := r.service.FindUserByEmail(email)
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"})
}
fmt.Println(user)
// сохраняем в бд
signature, err := r.Service.StoreRecoveryRecord("user")
signature, err := r.service.StoreRecoveryRecord("user")
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"})
}
// тут что-то на подобии канала или что-то подобное так как отправка выполнятеся в воркере,
//это пока временное решение для написания структуры кода и проверки отправки, далее перепишу
// под горутины
err = r.Service.SendRecoveryEmail(email, signature)
err = r.service.SendRecoveryEmail(email, signature)
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"})
}
@ -59,21 +59,21 @@ func (r *RecoveryController) HandleRecoveryRequest(c *fiber.Ctx) error {
func (r *RecoveryController) HandleRecoveryLink(c *fiber.Ctx) error {
signature := c.Params("sign")
// тут получается
record, err := r.Service.GetRecoveryRecord(signature)
record, err := r.service.GetRecoveryRecord(signature)
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"})
}
// проверка на более чем 15 минут
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"})
}
tokens, err := r.Service.ExchangeForTokens(record.UserID)
tokens, err := r.service.ExchangeForTokens(record.UserID)
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"})
}

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

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

@ -38,6 +38,14 @@ func NewServer(config ServerConfig) *Server {
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() {
s.app.Get("/liveness", s.handleLiveness)
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)
}
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
}
// todo deps
type RecoveryService struct {
type Deps struct {
Logger *zap.Logger
Repository UserRepository
Email EmailSender
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{
Logger: logger,
Repository: repository,
Email: email,
EncryptService: encryptService,
logger: deps.Logger,
repository: deps.Repository,
email: deps.Email,
encryptService: deps.EncryptService,
}
}
@ -43,25 +48,25 @@ func (s *RecoveryService) GenerateKey() (string, error) {
// FindUserByEmail ищет пользователя по электронной почте
func (s *RecoveryService) FindUserByEmail(email string) (*models.User, error) {
return s.Repository.FindByEmail(email)
return s.repository.FindByEmail(email)
}
// StoreRecoveryRecord сохраняет запись восстановления в базе данных
func (s *RecoveryService) StoreRecoveryRecord(userID string) (string, error) {
signature := ""
createdAt := time.Now()
err := s.Repository.StoreRecoveryRecord(userID, signature, createdAt)
err := s.repository.StoreRecoveryRecord(userID, signature, createdAt)
return signature, err
}
// GetRecoveryRecord получает запись восстановления из базы данных
func (s *RecoveryService) GetRecoveryRecord(signature string) (*models.RestoreRequest, error) {
return s.Repository.GetRecoveryRecord(signature)
return s.repository.GetRecoveryRecord(signature)
}
// SendRecoveryEmail посылает письмо для восстановления доступа пользователю
func (s *RecoveryService) SendRecoveryEmail(email string, signature string) error {
return s.Email.SendRecoveryEmail(email, signature)
return s.email.SendRecoveryEmail(email, signature)
}
// ExchangeForTokens обменивает ссылку восстановления на токены используя сервис аутентификации.