add dukcapil
This commit is contained in:
+27
-404
@@ -9,69 +9,39 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"eslogad-be/config"
|
||||
"eslogad-be/internal/client"
|
||||
internalConfig "eslogad-be/internal/config"
|
||||
"eslogad-be/internal/handler"
|
||||
"eslogad-be/internal/middleware"
|
||||
"eslogad-be/internal/processor"
|
||||
"eslogad-be/internal/repository"
|
||||
"eslogad-be/internal/router"
|
||||
"eslogad-be/internal/service"
|
||||
"eslogad-be/internal/validator"
|
||||
|
||||
"gorm.io/gorm"
|
||||
"go-backend-template/config"
|
||||
"go-backend-template/internal/client"
|
||||
"go-backend-template/internal/handler"
|
||||
"go-backend-template/internal/router"
|
||||
"go-backend-template/internal/service"
|
||||
)
|
||||
|
||||
type App struct {
|
||||
server *http.Server
|
||||
db *gorm.DB
|
||||
router *router.Router
|
||||
shutdown chan os.Signal
|
||||
}
|
||||
|
||||
func NewApp(db *gorm.DB) *App {
|
||||
func NewApp() *App {
|
||||
return &App{
|
||||
db: db,
|
||||
shutdown: make(chan os.Signal, 1),
|
||||
}
|
||||
}
|
||||
|
||||
func (a *App) Initialize(cfg *config.Config) error {
|
||||
repos := a.initRepositories()
|
||||
processors := a.initProcessors(cfg, repos)
|
||||
services := a.initServices(processors, repos, cfg)
|
||||
middlewares := a.initMiddleware(services)
|
||||
healthHandler := handler.NewHealthHandler()
|
||||
fileHandler := handler.NewFileHandler(services.fileService)
|
||||
rbacHandler := handler.NewRBACHandler(services.rbacService)
|
||||
masterHandler := handler.NewMasterHandler(services.masterService)
|
||||
letterHandler := handler.NewLetterHandler(services.letterService)
|
||||
letterOutgoingHandler := handler.NewLetterOutgoingHandler(services.letterOutgoingService)
|
||||
adminApprovalFlowHandler := handler.NewAdminApprovalFlowHandler(services.approvalFlowService)
|
||||
dispositionRouteHandler := handler.NewDispositionRouteHandler(services.dispositionRouteService)
|
||||
onlyOfficeHandler := handler.NewOnlyOfficeHandler(services.onlyOfficeService)
|
||||
analyticsHandler := handler.NewAnalyticsHandler(services.analyticsService)
|
||||
notificationHandler := handler.NewNotificationHandler(services.notificationService)
|
||||
repositoryAttachmentHandler := handler.NewRepositoryAttachmentHandler(services.repositoryAttachmentService)
|
||||
|
||||
dukcapilClient := client.NewDukcapilClient(cfg.Dukcapil)
|
||||
dukcapilService := service.NewDukcapilService(dukcapilClient)
|
||||
dukcapilHandler := handler.NewDukcapilHandler(dukcapilService)
|
||||
|
||||
a.router = router.NewRouter(
|
||||
cfg,
|
||||
handler.NewAuthHandler(services.authService),
|
||||
middlewares.authMiddleware,
|
||||
nil, // authHandler
|
||||
nil, // authMiddleware
|
||||
healthHandler,
|
||||
handler.NewUserHandler(services.userService, validator.NewUserValidator()),
|
||||
fileHandler,
|
||||
rbacHandler,
|
||||
masterHandler,
|
||||
letterHandler,
|
||||
letterOutgoingHandler,
|
||||
adminApprovalFlowHandler,
|
||||
dispositionRouteHandler,
|
||||
onlyOfficeHandler,
|
||||
analyticsHandler,
|
||||
notificationHandler,
|
||||
repositoryAttachmentHandler,
|
||||
nil, // userHandler
|
||||
dukcapilHandler,
|
||||
)
|
||||
|
||||
return nil
|
||||
@@ -80,8 +50,20 @@ func (a *App) Initialize(cfg *config.Config) error {
|
||||
func (a *App) Start(port string) error {
|
||||
engine := a.router.Init()
|
||||
|
||||
// Debug: log what port value we received
|
||||
log.Printf("DEBUG: Received port value: %q", port)
|
||||
|
||||
// Ensure proper address format
|
||||
// Only accept port number, not full addresses
|
||||
addr := ":" + port
|
||||
if port == "" {
|
||||
addr = ":8080" // default port
|
||||
}
|
||||
|
||||
log.Printf("DEBUG: Final address: %q", addr)
|
||||
|
||||
a.server = &http.Server{
|
||||
Addr: ":" + port,
|
||||
Addr: addr,
|
||||
Handler: engine,
|
||||
ReadTimeout: 15 * time.Second,
|
||||
WriteTimeout: 15 * time.Second,
|
||||
@@ -115,362 +97,3 @@ func (a *App) Start(port string) error {
|
||||
func (a *App) Shutdown() {
|
||||
close(a.shutdown)
|
||||
}
|
||||
|
||||
type repositories struct {
|
||||
userRepo *repository.UserRepositoryImpl
|
||||
userProfileRepo *repository.UserProfileRepository
|
||||
titleRepo *repository.TitleRepository
|
||||
rbacRepo *repository.RBACRepository
|
||||
labelRepo *repository.LabelRepository
|
||||
priorityRepo *repository.PriorityRepository
|
||||
institutionRepo *repository.InstitutionRepository
|
||||
dispRepo *repository.DispositionActionRepository
|
||||
letterRepo *repository.LetterIncomingRepository
|
||||
letterAttachRepo *repository.LetterIncomingAttachmentRepository
|
||||
activityLogRepo *repository.LetterIncomingActivityLogRepository
|
||||
dispositionRouteRepo *repository.DispositionRouteRepository
|
||||
// new repos
|
||||
letterDispositionRepo *repository.LetterIncomingDispositionRepository
|
||||
letterDispositionDeptRepo *repository.LetterIncomingDispositionDepartmentRepository
|
||||
letterDispActionSelRepo *repository.LetterDispositionActionSelectionRepository
|
||||
dispositionNoteRepo *repository.DispositionNoteRepository
|
||||
letterDiscussionRepo *repository.LetterDiscussionRepository
|
||||
settingRepo *repository.AppSettingRepository
|
||||
recipientRepo *repository.LetterIncomingRecipientRepository
|
||||
departmentRepo *repository.DepartmentRepository
|
||||
userDeptRepo *repository.UserDepartmentRepository
|
||||
// letter outgoing repos
|
||||
letterOutgoingRepo *repository.LetterOutgoingRepository
|
||||
letterOutgoingAttachmentRepo *repository.LetterOutgoingAttachmentRepository
|
||||
letterOutgoingFinalAttachmentRepo *repository.LetterOutgoingFinalAttachmentRepository
|
||||
letterOutgoingRecipientRepo *repository.LetterOutgoingRecipientRepository
|
||||
letterOutgoingDiscussionRepo *repository.LetterOutgoingDiscussionRepository
|
||||
letterOutgoingDiscussionAttachRepo *repository.LetterOutgoingDiscussionAttachmentRepository
|
||||
letterOutgoingActivityLogRepo *repository.LetterOutgoingActivityLogRepository
|
||||
approvalFlowRepo *repository.ApprovalFlowRepository
|
||||
letterOutgoingApprovalRepo *repository.LetterOutgoingApprovalRepository
|
||||
analyticsRepo *repository.AnalyticsRepository
|
||||
repositoryAttachmentRepo *repository.RepositoryAttachmentRepositoryImpl
|
||||
}
|
||||
|
||||
func (a *App) initRepositories() *repositories {
|
||||
return &repositories{
|
||||
userRepo: repository.NewUserRepository(a.db),
|
||||
userProfileRepo: repository.NewUserProfileRepository(a.db),
|
||||
titleRepo: repository.NewTitleRepository(a.db),
|
||||
rbacRepo: repository.NewRBACRepository(a.db),
|
||||
labelRepo: repository.NewLabelRepository(a.db),
|
||||
priorityRepo: repository.NewPriorityRepository(a.db),
|
||||
institutionRepo: repository.NewInstitutionRepository(a.db),
|
||||
dispRepo: repository.NewDispositionActionRepository(a.db),
|
||||
letterRepo: repository.NewLetterIncomingRepository(a.db),
|
||||
letterAttachRepo: repository.NewLetterIncomingAttachmentRepository(a.db),
|
||||
activityLogRepo: repository.NewLetterIncomingActivityLogRepository(a.db),
|
||||
dispositionRouteRepo: repository.NewDispositionRouteRepository(a.db),
|
||||
letterDispositionRepo: repository.NewLetterIncomingDispositionRepository(a.db),
|
||||
letterDispositionDeptRepo: repository.NewLetterIncomingDispositionDepartmentRepository(a.db),
|
||||
letterDispActionSelRepo: repository.NewLetterDispositionActionSelectionRepository(a.db),
|
||||
dispositionNoteRepo: repository.NewDispositionNoteRepository(a.db),
|
||||
letterDiscussionRepo: repository.NewLetterDiscussionRepository(a.db),
|
||||
settingRepo: repository.NewAppSettingRepository(a.db),
|
||||
recipientRepo: repository.NewLetterIncomingRecipientRepository(a.db),
|
||||
departmentRepo: repository.NewDepartmentRepository(a.db),
|
||||
userDeptRepo: repository.NewUserDepartmentRepository(a.db),
|
||||
letterOutgoingRepo: repository.NewLetterOutgoingRepository(a.db),
|
||||
letterOutgoingAttachmentRepo: repository.NewLetterOutgoingAttachmentRepository(a.db),
|
||||
letterOutgoingFinalAttachmentRepo: repository.NewLetterOutgoingFinalAttachmentRepository(a.db),
|
||||
letterOutgoingRecipientRepo: repository.NewLetterOutgoingRecipientRepository(a.db),
|
||||
letterOutgoingDiscussionRepo: repository.NewLetterOutgoingDiscussionRepository(a.db),
|
||||
letterOutgoingDiscussionAttachRepo: repository.NewLetterOutgoingDiscussionAttachmentRepository(a.db),
|
||||
letterOutgoingActivityLogRepo: repository.NewLetterOutgoingActivityLogRepository(a.db),
|
||||
approvalFlowRepo: repository.NewApprovalFlowRepository(a.db),
|
||||
letterOutgoingApprovalRepo: repository.NewLetterOutgoingApprovalRepository(a.db),
|
||||
analyticsRepo: repository.NewAnalyticsRepository(a.db),
|
||||
repositoryAttachmentRepo: repository.NewRepositoryAttachmentRepositoryImpl(a.db),
|
||||
}
|
||||
}
|
||||
|
||||
type processors struct {
|
||||
userProcessor *processor.UserProcessorImpl
|
||||
cachedUserProcessor *processor.CachedUserProcessor
|
||||
letterProcessor *processor.LetterProcessorImpl
|
||||
letterOutgoingProcessor *processor.LetterOutgoingProcessorImpl
|
||||
activityLogger *processor.ActivityLogProcessorImpl
|
||||
letterNumberGenerator *processor.LetterNumberGeneratorImpl
|
||||
onlyOfficeProcessor *processor.OnlyOfficeProcessorImpl
|
||||
novuProcessor processor.NovuProcessor
|
||||
notificationProcessor processor.NotificationProcessor
|
||||
recipientProcessor *processor.RecipientProcessorImpl
|
||||
letterDispositionProcessor *processor.LetterDispositionProcessorImpl
|
||||
letterDispositionDeptProcessor *processor.LetterDispositionDepartmentProcessorImpl
|
||||
// Modular processors for letter outgoing
|
||||
letterValidationProcessor processor.LetterValidationProcessor
|
||||
letterCreationProcessor processor.LetterCreationProcessor
|
||||
letterApprovalProcessor processor.LetterApprovalProcessor
|
||||
letterAttachmentProcessor processor.LetterAttachmentProcessor
|
||||
letterOutgoingRecipientProcessor processor.LetterOutgoingRecipientProcessor
|
||||
letterActivityProcessor processor.LetterActivityProcessor
|
||||
repositoryAttachmentProcessor *processor.RepositoryAttachmentProcessorImpl
|
||||
txManager *repository.TxManager
|
||||
}
|
||||
|
||||
func (a *App) initProcessors(cfg *config.Config, repos *repositories) *processors {
|
||||
txMgr := repository.NewTxManager(a.db)
|
||||
activity := processor.NewActivityLogProcessor(repos.activityLogRepo)
|
||||
|
||||
// Create the letter number generator
|
||||
letterNumberGen := processor.NewLetterNumberGenerator(repos.settingRepo)
|
||||
|
||||
// Create letter processors with the number generator
|
||||
letterProc := processor.NewLetterProcessor(
|
||||
repos.letterRepo, repos.letterAttachRepo, txMgr, activity,
|
||||
repos.letterDispositionRepo, repos.letterDispositionDeptRepo,
|
||||
repos.letterDispActionSelRepo, repos.dispositionNoteRepo,
|
||||
repos.letterDiscussionRepo, repos.settingRepo,
|
||||
repos.recipientRepo, repos.letterOutgoingRecipientRepo,
|
||||
repos.departmentRepo, repos.userDeptRepo,
|
||||
repos.priorityRepo, repos.institutionRepo, repos.dispRepo,
|
||||
letterNumberGen, repos.dispositionRouteRepo,
|
||||
)
|
||||
|
||||
// Create modular processors for letter outgoing
|
||||
letterValidationProc := processor.NewLetterValidationProcessor()
|
||||
letterCreationProc := processor.NewLetterCreationProcessor(
|
||||
repos.letterOutgoingRepo,
|
||||
repos.approvalFlowRepo,
|
||||
letterNumberGen,
|
||||
)
|
||||
letterApprovalProc := processor.NewLetterApprovalProcessor(
|
||||
repos.letterOutgoingApprovalRepo,
|
||||
repos.approvalFlowRepo,
|
||||
repos.letterOutgoingRepo,
|
||||
)
|
||||
letterAttachmentProc := processor.NewLetterAttachmentProcessor(
|
||||
repos.letterOutgoingAttachmentRepo,
|
||||
)
|
||||
letterOutgoingRecipientProc := processor.NewLetterOutgoingRecipientProcessor(
|
||||
repos.letterOutgoingRecipientRepo,
|
||||
repos.approvalFlowRepo,
|
||||
repos.userDeptRepo,
|
||||
)
|
||||
letterActivityProc := processor.NewLetterActivityProcessor(
|
||||
repos.letterOutgoingActivityLogRepo,
|
||||
)
|
||||
|
||||
// Create the main letter outgoing processor for backward compatibility
|
||||
letterOutgoingProc := processor.NewLetterOutgoingProcessor(
|
||||
a.db,
|
||||
repos.letterOutgoingRepo,
|
||||
repos.letterOutgoingAttachmentRepo,
|
||||
repos.letterOutgoingFinalAttachmentRepo,
|
||||
repos.letterOutgoingRecipientRepo,
|
||||
repos.letterOutgoingDiscussionRepo,
|
||||
repos.letterOutgoingDiscussionAttachRepo,
|
||||
repos.letterOutgoingActivityLogRepo,
|
||||
repos.approvalFlowRepo,
|
||||
repos.letterOutgoingApprovalRepo,
|
||||
letterNumberGen,
|
||||
txMgr,
|
||||
repos.priorityRepo,
|
||||
repos.institutionRepo,
|
||||
)
|
||||
|
||||
// Create document repositories
|
||||
docSessionRepo := repository.NewDocumentSessionRepository(a.db)
|
||||
docVersionRepo := repository.NewDocumentVersionRepository(a.db)
|
||||
docMetadataRepo := repository.NewDocumentMetadataRepository(a.db)
|
||||
docErrorRepo := repository.NewDocumentErrorRepository(a.db)
|
||||
|
||||
// Create OnlyOffice processor
|
||||
onlyOfficeProc := processor.NewOnlyOfficeProcessor(
|
||||
a.db,
|
||||
docSessionRepo,
|
||||
docVersionRepo,
|
||||
docMetadataRepo,
|
||||
docErrorRepo,
|
||||
txMgr,
|
||||
)
|
||||
|
||||
// Create Novu processor for backward compatibility
|
||||
novuConfig := internalConfig.LoadNovuConfig(cfg)
|
||||
novuProc := processor.NewNovuProcessor(novuConfig)
|
||||
|
||||
// Create notification processor with Novu provider
|
||||
novuProvider := processor.NewNovuProvider(novuConfig)
|
||||
notificationProc := processor.NewNotificationProcessor(novuProvider, novuConfig.IncomingLetterWorkflowID)
|
||||
|
||||
// Create user role processor
|
||||
userRoleProc := processor.NewUserRoleProcessor(a.db)
|
||||
|
||||
// Create user processor with Novu integration
|
||||
userProc := processor.NewUserProcessor(repos.userRepo, repos.userProfileRepo, userRoleProc)
|
||||
userProc.SetNovuProcessor(novuProc)
|
||||
|
||||
// Create cached user processor for auth middleware
|
||||
cachedUserProc := processor.NewCachedUserProcessor(repos.userRepo, repos.userProfileRepo, userRoleProc)
|
||||
|
||||
// Create recipient processor
|
||||
recipientProc := processor.NewRecipientProcessor(
|
||||
repos.recipientRepo,
|
||||
repos.settingRepo,
|
||||
repos.departmentRepo,
|
||||
repos.userDeptRepo,
|
||||
)
|
||||
|
||||
// Create letter disposition processor
|
||||
letterDispositionProc := processor.NewLetterDispositionProcessor(
|
||||
repos.letterDispositionRepo,
|
||||
repos.letterDispositionDeptRepo,
|
||||
repos.letterDispActionSelRepo,
|
||||
repos.dispositionNoteRepo,
|
||||
repos.letterDiscussionRepo,
|
||||
repos.dispRepo,
|
||||
activity,
|
||||
)
|
||||
|
||||
// Create letter disposition department processor
|
||||
letterDispositionDeptProc := processor.NewLetterDispositionDepartmentProcessor(
|
||||
repos.letterDispositionDeptRepo,
|
||||
repos.dispositionNoteRepo,
|
||||
repos.letterRepo,
|
||||
)
|
||||
|
||||
repositoryAttachmentProc := processor.NewRepositoryAttachmentProcessor(
|
||||
repos.repositoryAttachmentRepo)
|
||||
|
||||
return &processors{
|
||||
userProcessor: userProc,
|
||||
cachedUserProcessor: cachedUserProc,
|
||||
letterProcessor: letterProc,
|
||||
letterOutgoingProcessor: letterOutgoingProc,
|
||||
activityLogger: activity,
|
||||
letterNumberGenerator: letterNumberGen,
|
||||
onlyOfficeProcessor: onlyOfficeProc,
|
||||
novuProcessor: novuProc,
|
||||
notificationProcessor: notificationProc,
|
||||
recipientProcessor: recipientProc,
|
||||
letterDispositionProcessor: letterDispositionProc,
|
||||
letterDispositionDeptProcessor: letterDispositionDeptProc,
|
||||
// Modular processors
|
||||
letterValidationProcessor: letterValidationProc,
|
||||
letterCreationProcessor: letterCreationProc,
|
||||
letterApprovalProcessor: letterApprovalProc,
|
||||
letterAttachmentProcessor: letterAttachmentProc,
|
||||
letterOutgoingRecipientProcessor: letterOutgoingRecipientProc,
|
||||
letterActivityProcessor: letterActivityProc,
|
||||
repositoryAttachmentProcessor: repositoryAttachmentProc,
|
||||
txManager: txMgr,
|
||||
}
|
||||
}
|
||||
|
||||
type services struct {
|
||||
userService *service.UserServiceImpl
|
||||
authService *service.AuthServiceImpl
|
||||
fileService *service.FileServiceImpl
|
||||
rbacService *service.RBACServiceImpl
|
||||
masterService *service.MasterServiceImpl
|
||||
letterService *service.LetterServiceImpl
|
||||
letterOutgoingService *service.LetterOutgoingServiceImpl
|
||||
approvalFlowService *service.ApprovalFlowServiceImpl
|
||||
dispositionRouteService *service.DispositionRouteServiceImpl
|
||||
onlyOfficeService *service.OnlyOfficeServiceImpl
|
||||
analyticsService *service.AnalyticsServiceImpl
|
||||
notificationService *service.NotificationServiceImpl
|
||||
repositoryAttachmentService *service.RepositoryAttachmentServiceImpl
|
||||
}
|
||||
|
||||
func (a *App) initServices(processors *processors, repos *repositories, cfg *config.Config) *services {
|
||||
authConfig := cfg.Auth()
|
||||
jwtSecret := authConfig.AccessTokenSecret()
|
||||
authService := service.NewAuthService(processors.userProcessor, jwtSecret)
|
||||
|
||||
userSvc := service.NewUserService(processors.userProcessor, repos.titleRepo)
|
||||
|
||||
fileCfg := cfg.S3Config
|
||||
s3Client := client.NewFileClient(fileCfg)
|
||||
fileSvc := service.NewFileService(s3Client, processors.userProcessor, "profile", "documents", "finals")
|
||||
|
||||
rbacSvc := service.NewRBACService(repos.rbacRepo)
|
||||
|
||||
masterSvc := service.NewMasterService(repos.labelRepo, repos.priorityRepo, repos.institutionRepo, repos.dispRepo, repos.departmentRepo, cfg)
|
||||
|
||||
txManager := repository.NewTxManager(a.db)
|
||||
letterSvc := service.NewLetterService(
|
||||
processors.letterProcessor,
|
||||
txManager,
|
||||
processors.letterNumberGenerator,
|
||||
processors.recipientProcessor,
|
||||
processors.activityLogger,
|
||||
processors.letterDispositionProcessor,
|
||||
processors.notificationProcessor,
|
||||
processors.activityLogger,
|
||||
)
|
||||
dispRouteSvc := service.NewDispositionRouteService(repos.dispositionRouteRepo)
|
||||
letterOutgoingSvc := service.NewLetterOutgoingService(
|
||||
processors.letterOutgoingProcessor,
|
||||
processors.txManager,
|
||||
processors.letterValidationProcessor,
|
||||
processors.letterCreationProcessor,
|
||||
processors.letterApprovalProcessor,
|
||||
processors.letterAttachmentProcessor,
|
||||
processors.letterOutgoingRecipientProcessor,
|
||||
processors.notificationProcessor,
|
||||
processors.letterActivityProcessor,
|
||||
)
|
||||
|
||||
approvalFlowStepRepo := repository.NewApprovalFlowStepRepository(a.db)
|
||||
approvalFlowSvc := service.NewApprovalFlowService(
|
||||
a.db,
|
||||
repos.approvalFlowRepo,
|
||||
approvalFlowStepRepo,
|
||||
txManager,
|
||||
)
|
||||
|
||||
// Create OnlyOffice service with file storage
|
||||
onlyOfficeSvc := service.NewOnlyOfficeService(processors.onlyOfficeProcessor, &cfg.OnlyOffice, a.db, s3Client)
|
||||
|
||||
// Create Analytics service
|
||||
analyticsSvc := service.NewAnalyticsService(repos.analyticsRepo)
|
||||
|
||||
// Create Notification service
|
||||
novuConfig := internalConfig.LoadNovuConfig(cfg)
|
||||
notificationSvc := service.NewNotificationService(novuConfig, processors.userProcessor)
|
||||
|
||||
repositoryAttachmentSvc := service.NewRepositoryAttachmentService(processors.repositoryAttachmentProcessor)
|
||||
|
||||
return &services{
|
||||
userService: userSvc,
|
||||
authService: authService,
|
||||
fileService: fileSvc,
|
||||
rbacService: rbacSvc,
|
||||
masterService: masterSvc,
|
||||
letterService: letterSvc,
|
||||
letterOutgoingService: letterOutgoingSvc,
|
||||
approvalFlowService: approvalFlowSvc,
|
||||
dispositionRouteService: dispRouteSvc,
|
||||
onlyOfficeService: onlyOfficeSvc,
|
||||
analyticsService: analyticsSvc,
|
||||
notificationService: notificationSvc,
|
||||
repositoryAttachmentService: repositoryAttachmentSvc,
|
||||
}
|
||||
}
|
||||
|
||||
type middlewares struct {
|
||||
authMiddleware *middleware.AuthMiddleware
|
||||
}
|
||||
|
||||
func (a *App) initMiddleware(services *services) *middlewares {
|
||||
return &middlewares{
|
||||
authMiddleware: middleware.NewAuthMiddleware(services.authService),
|
||||
}
|
||||
}
|
||||
|
||||
type validators struct {
|
||||
userValidator *validator.UserValidatorImpl
|
||||
}
|
||||
|
||||
func (a *App) initValidators() *validators {
|
||||
return &validators{
|
||||
userValidator: validator.NewUserValidator(),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user