refactor: use actors for db configuration (#1604)

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Alessandro (Ale) Segala
2026-07-19 20:48:05 -10:00
committed by GitHub
parent 472fff33ea
commit 2cfbcb4b67
53 changed files with 2061 additions and 1714 deletions

View File

@@ -1,6 +1,7 @@
package usersignup
import (
"fmt"
"net/http"
"time"
@@ -16,10 +17,10 @@ const defaultSignupTokenDuration = time.Hour
type handler struct {
service *Service
appConfig AppConfigProvider
appConfig AppConfigResolver
}
func newHandler(service *Service, appConfig AppConfigProvider) *handler {
func newHandler(service *Service, appConfig AppConfigResolver) *handler {
return &handler{service: service, appConfig: appConfig}
}
@@ -48,13 +49,19 @@ func (h *handler) checkInitialAdminSetupAvailable(c *gin.Context) {
// @Success 200 {object} dto.UserDto
// @Router /api/signup/setup [post]
func (h *handler) signUpInitialAdmin(c *gin.Context) {
config, err := h.appConfig.GetConfig(c.Request.Context())
if err != nil {
_ = c.Error(fmt.Errorf("error loading app configuration: %w", err))
return
}
var input signUpDto
if err := dto.ShouldBindWithNormalizedJSON(c, &input); err != nil {
_ = c.Error(err)
return
}
user, token, err := h.service.SignUpInitialAdmin(c.Request.Context(), input)
user, token, err := h.service.SignUpInitialAdmin(c.Request.Context(), config, input)
if err != nil {
_ = c.Error(err)
return
@@ -66,7 +73,7 @@ func (h *handler) signUpInitialAdmin(c *gin.Context) {
return
}
maxAge := int(h.appConfig.GetDbConfig().SessionDuration.AsDurationMinutes().Seconds())
maxAge := int(config.SessionDuration.AsDurationMinutes().Seconds())
cookie.AddAccessTokenCookie(c, maxAge, token)
c.JSON(http.StatusOK, userDto)
@@ -169,6 +176,12 @@ func (h *handler) deleteSignupToken(c *gin.Context) {
// @Success 201 {object} dto.UserDto
// @Router /api/signup [post]
func (h *handler) signup(c *gin.Context) {
config, err := h.appConfig.GetConfig(c.Request.Context())
if err != nil {
_ = c.Error(fmt.Errorf("error loading app configuration: %w", err))
return
}
var input signUpDto
if err := dto.ShouldBindWithNormalizedJSON(c, &input); err != nil {
_ = c.Error(err)
@@ -178,13 +191,13 @@ func (h *handler) signup(c *gin.Context) {
ipAddress := c.ClientIP()
userAgent := c.GetHeader("User-Agent")
user, accessToken, err := h.service.SignUp(c.Request.Context(), input, ipAddress, userAgent)
user, accessToken, err := h.service.SignUp(c.Request.Context(), config, input, ipAddress, userAgent)
if err != nil {
_ = c.Error(err)
return
}
maxAge := int(h.appConfig.GetDbConfig().SessionDuration.AsDurationMinutes().Seconds())
maxAge := int(config.SessionDuration.AsDurationMinutes().Seconds())
cookie.AddAccessTokenCookie(c, maxAge, accessToken)
var userDto dto.UserDto

View File

@@ -2,28 +2,31 @@ package usersignup
import (
"context"
"time"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
"github.com/pocket-id/pocket-id/backend/internal/appconfig"
"github.com/pocket-id/pocket-id/backend/internal/dto"
"github.com/pocket-id/pocket-id/backend/internal/model"
)
type TokenService interface {
GenerateAccessToken(user model.User, authenticationMethod string) (string, error)
GenerateAccessToken(user model.User, authenticationMethod string, sessionDuration time.Duration) (string, error)
}
type AuditLogger interface {
Create(ctx context.Context, event model.AuditLogEvent, ipAddress, userAgent, userID string, data model.AuditLogData, tx *gorm.DB) (model.AuditLog, bool)
}
type AppConfigProvider interface {
GetDbConfig() *model.AppConfig
type UserCreator interface {
CreateUserInternal(ctx context.Context, dbConfig *appconfig.AppConfigModel, input dto.UserCreateDto, isLdapSync bool, tx *gorm.DB) (model.User, error)
}
type UserCreator interface {
CreateUserInternal(ctx context.Context, input dto.UserCreateDto, isLdapSync bool, tx *gorm.DB) (model.User, error)
// AppConfigResolver loads the current application configuration, so handlers can pass it explicitly to the service methods that need it
type AppConfigResolver interface {
GetConfig(ctx context.Context) (*appconfig.AppConfigModel, error)
}
type Dependencies struct {
@@ -31,8 +34,8 @@ type Dependencies struct {
Signer TokenService
AuditLog AuditLogger
AppConfig AppConfigProvider
UserCreator UserCreator
AppConfig AppConfigResolver
}
type Module struct {

View File

@@ -9,6 +9,7 @@ import (
"gorm.io/gorm"
"gorm.io/gorm/clause"
"github.com/pocket-id/pocket-id/backend/internal/appconfig"
"github.com/pocket-id/pocket-id/backend/internal/common"
"github.com/pocket-id/pocket-id/backend/internal/dto"
"github.com/pocket-id/pocket-id/backend/internal/model"
@@ -25,7 +26,6 @@ type Service struct {
userCreator UserCreator
signer TokenService
auditLog AuditLogger
appConfig AppConfigProvider
}
func newService(deps Dependencies) *Service {
@@ -34,11 +34,10 @@ func newService(deps Dependencies) *Service {
userCreator: deps.UserCreator,
signer: deps.Signer,
auditLog: deps.AuditLog,
appConfig: deps.AppConfig,
}
}
func (s *Service) SignUp(ctx context.Context, signupData signUpDto, ipAddress, userAgent string) (model.User, string, error) {
func (s *Service) SignUp(ctx context.Context, config *appconfig.AppConfigModel, signupData signUpDto, ipAddress, userAgent string) (model.User, string, error) {
tx := s.db.Begin()
defer func() {
tx.Rollback()
@@ -46,8 +45,7 @@ func (s *Service) SignUp(ctx context.Context, signupData signUpDto, ipAddress, u
tokenProvided := signupData.Token != ""
config := s.appConfig.GetDbConfig()
if config.AllowUserSignups.Value != "open" && !tokenProvided {
if config.AllowUserSignups.String() != "open" && !tokenProvided {
return model.User{}, "", &common.OpenSignupDisabledError{}
}
@@ -84,15 +82,15 @@ func (s *Service) SignUp(ctx context.Context, signupData signUpDto, ipAddress, u
LastName: signupData.LastName,
DisplayName: strings.TrimSpace(signupData.FirstName + " " + signupData.LastName),
UserGroupIds: userGroupIDs,
EmailVerified: s.appConfig.GetDbConfig().EmailsVerified.IsTrue(),
EmailVerified: config.EmailsVerified.IsTrue(),
}
user, err := s.userCreator.CreateUserInternal(ctx, userToCreate, false, tx)
user, err := s.userCreator.CreateUserInternal(ctx, config, userToCreate, false, tx)
if err != nil {
return model.User{}, "", err
}
accessToken, err := s.signer.GenerateAccessToken(user, "")
accessToken, err := s.signer.GenerateAccessToken(user, "", config.SessionDuration.AsDurationMinutes())
if err != nil {
return model.User{}, "", err
}
@@ -122,7 +120,7 @@ func (s *Service) SignUp(ctx context.Context, signupData signUpDto, ipAddress, u
return user, accessToken, nil
}
func (s *Service) SignUpInitialAdmin(ctx context.Context, signUpData signUpDto) (model.User, string, error) {
func (s *Service) SignUpInitialAdmin(ctx context.Context, config *appconfig.AppConfigModel, signUpData signUpDto) (model.User, string, error) {
tx := s.db.Begin()
defer func() {
tx.Rollback()
@@ -145,12 +143,12 @@ func (s *Service) SignUpInitialAdmin(ctx context.Context, signUpData signUpDto)
IsAdmin: true,
}
user, err := s.userCreator.CreateUserInternal(ctx, userToCreate, false, tx)
user, err := s.userCreator.CreateUserInternal(ctx, config, userToCreate, false, tx)
if err != nil {
return model.User{}, "", err
}
token, err := s.signer.GenerateAccessToken(user, authenticationMethodOneTimePassword)
token, err := s.signer.GenerateAccessToken(user, authenticationMethodOneTimePassword, config.SessionDuration.AsDurationMinutes())
if err != nil {
return model.User{}, "", err
}