Files
test_deploy/internal/http/router.go
Alex Shevchuk d84487d238 1
2025-08-18 17:12:04 +03:00

336 lines
16 KiB
Go

package http_router
import (
"fmt"
"log/slog"
"net/http"
"net/http/pprof"
"strings"
"git-molva.ru/Molva/molva-backend/services/api_gateway/internal/logger"
"git-molva.ru/Molva/molva-backend/services/api_gateway/internal/cache"
"git-molva.ru/Molva/molva-backend/services/api_gateway/internal/database"
"git-molva.ru/Molva/molva-backend/services/api_gateway/internal/feed"
"git-molva.ru/Molva/molva-backend/services/api_gateway/internal/file_manager/s3_storage"
"git-molva.ru/Molva/molva-backend/services/api_gateway/internal/integration"
objectStorage "git-molva.ru/Molva/molva-backend/services/api_gateway/internal/object_storage"
"git-molva.ru/Molva/molva-backend/services/api_gateway/internal/services/agent"
authinfra "git-molva.ru/Molva/molva-backend/services/api_gateway/internal/services/auth_infrastructure"
"git-molva.ru/Molva/molva-backend/services/api_gateway/internal/services/distributor"
pgdb "git-molva.ru/Molva/molva-backend/services/api_gateway/internal/database/postgres"
formgenerator "git-molva.ru/Molva/molva-backend/services/api_gateway/internal/form_generator"
"git-molva.ru/Molva/molva-backend/services/api_gateway/internal/config"
"github.com/gorilla/mux"
)
type Router struct {
Mux *mux.Router
env string
logger *slog.Logger
middleware *Middleware
shortenerCfg *config.SecretConfig
abstractAPI string
cache cache.Client
objectStorage objectStorage.Client
feedHandler *feed.Handler
integrationClient integration.Client
databaseClient database.Client
agentService agent.AgentService
distributorService distributor.DistributorService
}
func New(logger *slog.Logger, cfg *config.Config) (*Router, error) {
middleware, err := NewMiddleware(&ConfigMiddleware{
logger: logger,
keycloakCfg: &cfg.Keycloak,
})
if err != nil {
return nil, err
}
cacheClient, err := cache.New(cache.ValKeyCacheConfig{
Addrs: strings.Split(cfg.ValkeyCache.Addrs, ","),
Password: cfg.ValkeyCache.Password,
ReadOnly: cfg.ValkeyCache.ReadOnly,
DialTimeout: cfg.ValkeyCache.DialTimeout,
PoolSize: cfg.ValkeyCache.PoolSize,
DefaultTTL: cfg.ValkeyCache.DefaultTTL,
RootCaFilePath: cfg.ValkeyCache.RootCaFilePath,
}, cache.ValkeyCacheType)
if err != nil {
return nil, err
}
databaseClient, err := database.New(database.PostgresClientType, pgdb.PostgresConfig{
Host: cfg.Database.Host,
Port: cfg.Database.Port,
Username: cfg.Database.Username,
Password: cfg.Database.Password,
Database: cfg.Database.DBName,
Schema: cfg.Database.Schema,
SSLMode: cfg.Database.SSLMode,
SSLRootCert: cfg.Database.RootCaFilePath,
})
if err != nil {
return nil, err
}
agentService, err := agent.New(agent.CrmAgentServiceType, agent.CrmAgentServiceConfig{
DbClient: databaseClient,
})
if err != nil {
return nil, err
}
distributorService, err := distributor.New(distributor.CrmDistributorServiceType, distributor.CrmDistributorServiceConfig{
DbClient: databaseClient,
})
if err != nil {
return nil, err
}
objectStorageClient, err := objectStorage.New(objectStorage.S3StorageConfig{
Bucket: cfg.S3Storage.Bucket,
DefaultLinkTTL: cfg.ValkeyCache.DefaultTTL,
}, objectStorage.ClientTypeS3)
if err != nil {
return nil, err
}
integrationClient, err := integration.New(integration.Config{
Cache: cacheClient,
Db: databaseClient,
Logger: logger,
Secrets: map[string]integration.CompanySecrets{
integration.VkusvillCompanyName: integration.VkusvillSecretsConfig{
ApiToken: cfg.Integration.Vkusvill.ApiToken,
},
},
})
if err != nil {
return nil, err
}
// TODO: вырезать ненужные аргументы в рамках https://tracker.yandex.ru/MOLVARAZRABOTKA-363
service, err := feed.NewService(fmt.Sprintf(
"postgres://%s:%s@%s:%d/%s?sslmode=%s",
cfg.Database.Username,
cfg.Database.Password,
cfg.Database.Host,
cfg.Database.Port,
cfg.Database.DBName,
cfg.Database.SSLMode,
), cfg.Database.Schema, logger, databaseClient)
if err != nil {
return nil, err
}
return &Router{
Mux: mux.NewRouter(),
env: cfg.Env,
logger: logger,
middleware: middleware,
shortenerCfg: &cfg.Secret,
abstractAPI: cfg.EmailVerificationService.APIKey, // may be nil dereference if no email verification service is configured
cache: cacheClient,
objectStorage: objectStorageClient,
feedHandler: feed.NewFeedHandler(logger, service),
databaseClient: databaseClient,
agentService: agentService,
distributorService: distributorService,
integrationClient: integrationClient,
}, nil
}
func SetupRouter(r *Router, buildCfg config.BuildInfo) {
authInfraService, err := authinfra.New(authinfra.CacheAuthInfrastructureServiceType, authinfra.CacheAuthInfraServiceConfig{
CacheClient: r.cache,
})
if err != nil {
panic(err)
}
s3FileManager := s3_storage.NewS3Storage(
r.objectStorage,
r.cache,
)
h := newHandler(&Config{
env: r.env,
logger: r.logger,
authManager: r.middleware.authManager,
authInfraService: authInfraService,
fileManager: s3FileManager,
dbClient: r.databaseClient,
agentService: r.agentService,
distributorService: r.distributorService,
secretConfig: r.shortenerCfg,
emailVerificationServiceAPIKey: r.abstractAPI,
cacheClient: r.cache,
objectStorageClient: r.objectStorage,
feed: r.feedHandler,
integrationClient: r.integrationClient,
buildConfig: buildCfg,
})
r.Mux.Use(r.middleware.loggingMiddleware)
setupAuthHandlers(r, h)
setupIntegrationHandlers(r, h)
setupClientHandlers(r, h)
setupValidationHandlers(r, h)
if r.env != logger.EnvProd {
setupSystemInfoHandlers(r, h)
}
subRouter := r.Mux.PathPrefix("/api/v1").Subrouter()
subRouter.Use(r.middleware.authMiddleware)
setupAgentHandlers(subRouter, h)
setupDistributorHandlers(subRouter, h)
setupEmployeesHandlers(subRouter, h)
setupLogoHandlers(subRouter, h)
// --------------- DOCUMENTS FOR FORM ------------
r.Mux.HandleFunc("/api/v1/docs/{file}", h.getFileHandler).Methods(http.MethodGet)
// --------------- FEED ------------
subRouter.HandleFunc("/feed/{uid}/events", h.GetUserEventsHandler).Methods(http.MethodGet)
}
func setupAuthHandlers(r *Router, h *handler) {
r.Mux.HandleFunc("/api/v1/login", h.loginHandler).Methods(http.MethodPost)
r.Mux.HandleFunc("/api/v1/register", h.registerHandler).Methods(http.MethodPost)
r.Mux.HandleFunc("/api/v1/logout", h.logoutHandler).Methods(http.MethodPost)
r.Mux.HandleFunc("/api/v1/refresh-token", h.refreshTokenHandler).Methods(http.MethodPost)
r.Mux.HandleFunc("/api/v1/verify_email", h.verifyEmailHandler).Methods(http.MethodPatch)
r.Mux.HandleFunc("/api/v1/verify_email", h.getEmailVerificationStatusHandler).Methods(http.MethodGet)
r.Mux.HandleFunc("/api/v1/confirm_email", h.confirmEmailPageHandler).Methods(http.MethodGet)
r.Mux.HandleFunc("/api/v1/forgot_password", h.forgotPasswordHandler).Methods(http.MethodPost)
r.Mux.HandleFunc("/api/v1/validate_otp", h.validateOTPHandler).Methods(http.MethodGet)
r.Mux.HandleFunc("/api/v1/reset_password", h.resetPasswordHandler).Methods(http.MethodPut)
}
func setupAgentHandlers(subRouter *mux.Router, h *handler) {
// // =============== COMPANY HANDLERS ===============
subRouter.HandleFunc("/agents/{agent_id}/companies", h.getCompanyListAgentHandler).Methods(http.MethodGet)
subRouter.HandleFunc("/agents/{agent_id}/company/{company_id}", h.getCompanyByIdAgentHandler).Methods(http.MethodGet)
// TODO: review
// subRouter.HandleFunc("/agents/{agent_id}/company/{company_id}", h.addNewAgentCompanyMemberHandler).Methods(http.MethodPost)
subRouter.HandleFunc("/agents/{agent_id}/company", h.createCompanyAgentHandler).Methods(http.MethodPost)
subRouter.HandleFunc("/agents/{agent_id}/company/{company_id}", h.updateCompanyAgentHandler).Methods(http.MethodPatch)
// // =============== VACANCY HANDLERS ===============
subRouter.HandleFunc("/agents/{agent_id}/vacancies", h.getVacancyListAgentHandler).Methods(http.MethodGet)
subRouter.HandleFunc("/agents/{agent_id}/vacancies/{vacancy_id}", h.getPersonalLinkHandler).Methods(http.MethodGet)
// // =============== SUBMISSION HANDLERS ===============
subRouter.HandleFunc("/agents/{agent_id}/submissions", h.getSubmissionListAgentHandler).Methods(http.MethodGet)
subRouter.HandleFunc("/agents/{agent_id}/submissions/{submission_id}", h.deleteSubmissionAgentHandler).Methods(http.MethodDelete)
subRouter.HandleFunc("/agents/{agent_id}/submissions/{submission_id}/cv", h.getSubmissionCVHandler).Methods(http.MethodGet)
// // =============== PROFILE HANDLERS ===============
subRouter.HandleFunc("/agents/{agent_id}/profile", h.getProfileAgentHandler).Methods(http.MethodGet)
subRouter.HandleFunc("/agents/{agent_id}/profile", h.updateProfileAgentHandler).Methods(http.MethodPatch)
// // =============== BALANCE HANDLERS ===============
subRouter.HandleFunc("/agents/{agent_id}/balance", h.getBalanceAgentHandler).Methods(http.MethodGet)
subRouter.HandleFunc("/agents/{agent_id}/transactions", h.getTransactionListAgentHandler).Methods(http.MethodGet)
subRouter.HandleFunc("/agents/{agent_id}/transactions", h.createTransactionAgentHandler).Methods(http.MethodPost)
subRouter.HandleFunc("/agents/{agent_id}/bank_accounts", h.getBankAccountListAgentHandler).Methods(http.MethodGet)
subRouter.HandleFunc("/agents/{agent_id}/bank_accounts", h.createBankAccountAgentHandler).Methods(http.MethodPost)
subRouter.HandleFunc("/agents/{agent_id}/bank_accounts/{bank_account_id}", h.updateBankAccountAgentHandler).Methods(http.MethodPatch)
subRouter.HandleFunc("/agents/{agent_id}/bank_accounts/{bank_account_id}", h.deleteBankAccountAgentHandler).Methods(http.MethodDelete)
}
func setupDistributorHandlers(subRouter *mux.Router, h *handler) {
// // =============== COMPANY HANDLERS ===============
subRouter.HandleFunc("/distributor/{distributor_id}/companies", h.getCompanyListDistributorHandler).Methods(http.MethodGet)
subRouter.HandleFunc("/distributor/{distributor_id}/company/{company_id}", h.getCompanyByIdDistributorHandler).Methods(http.MethodGet)
subRouter.HandleFunc("/distributor/{distributor_id}/company/{company_id}", h.addCompanyMemberDistributorHandler).Methods(http.MethodPost)
subRouter.HandleFunc("/distributor/{distributor_id}/company/{company_id}", h.updateCompanyDistributorHandler).Methods(http.MethodPatch)
subRouter.HandleFunc("/distributor/{distributor_id}/company", h.createCompanyDistributorHandler).Methods(http.MethodPost)
// // =============== VACANCY HANDLERS ===============
subRouter.HandleFunc("/distributor/{distributor_id}/vacancies", h.getVacancyListDistributorHandler).Methods(http.MethodGet)
subRouter.HandleFunc("/distributor/{distributor_id}/vacancies", h.createVacancyDistributorHandler).Methods(http.MethodPost)
subRouter.HandleFunc("/distributor/{distributor_id}/vacancies/{vacancy_id}", h.updateVacancyDistributorHandler).Methods(http.MethodPatch)
subRouter.HandleFunc("/distributor/{distributor_id}/vacancies/{vacancy_id}", h.deleteVacancyDistributorHandler).Methods(http.MethodDelete)
subRouter.HandleFunc("/distributor/{distributor_id}/vacancies/{vacancy_id}/moderation", h.sendVacancyToModerationHandler).Methods(http.MethodPost)
// // =============== SUBMISSION HANDLERS ===============
subRouter.HandleFunc("/distributor/{distributor_id}/vacancies/{vacancy_id}/submissions", h.getSubmissionListDistributorHandler).Methods(http.MethodGet)
subRouter.HandleFunc("/distributor/{distributor_id}/vacancies/{vacancy_id}/submissions/{submission_id}/status", h.updateSubmissionStatusDistributorHandler).Methods(http.MethodPost)
subRouter.HandleFunc("/distributor/{distributor_id}/submissions/{submission_id}/cv", h.getSubmissionCVHandler).Methods(http.MethodGet)
// // =============== PROFILE HANDLERS ===============
subRouter.HandleFunc("/distributor/{distributor_id}/profile", h.getProfileDisributorHandler).Methods(http.MethodGet)
subRouter.HandleFunc("/distributor/{distributor_id}/profile", h.updateProfileDistributorHandler).Methods(http.MethodPatch)
// // =============== BALANCE HANDLERS ===============
subRouter.HandleFunc("/distributor/{distributor_id}/balance", h.getBalanceDistributorHandler).Methods(http.MethodGet)
subRouter.HandleFunc("/distributor/{distributor_id}/company/{company_id}/balance", h.getCompanyBalanceDistributorHandler).Methods(http.MethodGet)
subRouter.HandleFunc("/distributor/{distributor_id}/transactions", h.getTransactionListDistributorHandler).Methods(http.MethodGet)
subRouter.HandleFunc("/distributor/{distributor_id}/company/{company_id}/transactions", h.getCompanyTransactionListDistributorHandler).Methods(http.MethodGet)
subRouter.HandleFunc("/distributor/{distributor_id}/transactions", h.createTransactionDistributorHandler).Methods(http.MethodPost)
subRouter.HandleFunc("/distributor/{distributor_id}/bank_accounts", h.getBankAccountListDistributorHandler).Methods(http.MethodGet)
subRouter.HandleFunc("/distributor/{distributor_id}/company/{company_id}/bank_accounts", h.getCompanyBankAccountListDistributorHandler).Methods(http.MethodGet)
subRouter.HandleFunc("/distributor/{distributor_id}/company/{company_id}/bank_accounts", h.createBankAccountDistributorHandler).Methods(http.MethodPost)
subRouter.HandleFunc("/distributor/{distributor_id}/bank_accounts/{bank_account_id}", h.updateBankAccountDistributorHandler).Methods(http.MethodPut)
subRouter.HandleFunc("/distributor/{distributor_id}/bank_accounts/{bank_account_id}", h.deleteBankAccountDistributorHandler).Methods(http.MethodDelete)
}
func setupEmployeesHandlers(subRouter *mux.Router, h *handler) {
// // =============== EMPLOYEES HANDLERS ===============
subRouter.HandleFunc("/companies/{company_id}/employees", h.getEmployeesHandler).Methods(http.MethodGet)
}
func setupClientHandlers(r *Router, h *handler) {
// // =============== CLIENT HANDLERS ===============
r.Mux.HandleFunc("/api/v1/anketa", h.getAnketaHandler).Methods(http.MethodGet)
r.Mux.HandleFunc("/api/v1/anketa", h.postAnketaHandler).Methods(http.MethodPost)
// --------------- FORM METADATA ---------------
//TODO FROM ALEXANDER: make err validation
formSys, _ := formgenerator.GetFileSystem()
r.Mux.PathPrefix("/api/v1/anketa/static/").Handler(http.StripPrefix("/api/v1/anketa/static/", http.FileServer(http.FS(formSys))))
}
func setupValidationHandlers(r *Router, h *handler) {
// // =============== VALIDATION HANDLERS ===============
r.Mux.HandleFunc("/api/v1/{uid}/validation", h.getUserValidationStatusHandler).Methods(http.MethodGet)
}
func setupLogoHandlers(subRouter *mux.Router, h *handler) {
// // =============== LOGO HANDLERS ===============
subRouter.HandleFunc("/distributor/{distributor_id}/company/{company_id}/logo", h.getCompanyLogoHandler).Methods(http.MethodGet)
subRouter.HandleFunc("/distributor/{distributor_id}/company/{company_id}/logo", h.createCompanyLogoHandler).Methods(http.MethodPost)
subRouter.HandleFunc("/distributor/{distributor_id}/company/{company_id}/logo", h.updateCompanyLogoHandler).Methods(http.MethodPut)
subRouter.HandleFunc("/distributor/{distributor_id}/company/{company_id}/logo", h.deleteCompanyLogoHandler).Methods(http.MethodDelete)
}
func setupIntegrationHandlers(r *Router, h *handler) {
r.Mux.HandleFunc("/api/v1/integration/vkusvill/callback", h.vkusvillIntegrationCallbackHandler).Methods(http.MethodPost)
}
func setupSystemInfoHandlers(r *Router, h *handler) {
r.Mux.HandleFunc("/api/v1/healthcheck", h.getBuildInfoHandler).Methods(http.MethodGet)
r.Mux.HandleFunc("/debug/pprof/", pprof.Index).Methods(http.MethodGet)
r.Mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline).Methods(http.MethodGet)
r.Mux.HandleFunc("/debug/pprof/profile", pprof.Profile).Methods(http.MethodGet)
r.Mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol).Methods(http.MethodGet)
r.Mux.HandleFunc("/debug/pprof/trace", pprof.Trace).Methods(http.MethodGet)
r.Mux.Handle("/debug/pprof/goroutine", pprof.Handler("goroutine")).Methods(http.MethodGet)
r.Mux.Handle("/debug/pprof/heap", pprof.Handler("heap")).Methods(http.MethodGet)
r.Mux.Handle("/debug/pprof/threadcreate", pprof.Handler("threadcreate")).Methods(http.MethodGet)
r.Mux.Handle("/debug/pprof/block", pprof.Handler("block")).Methods(http.MethodGet)
}