add deps struct
This commit is contained in:
parent
79eb5da3e3
commit
b4ce07515c
@ -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 обменивает ссылку восстановления на токены используя сервис аутентификации.
|
||||||
|
Loading…
Reference in New Issue
Block a user