feat: disable registration

This commit is contained in:
juancwu 2026-05-17 14:30:59 +00:00
commit 39330ce821
17 changed files with 179 additions and 132 deletions

View file

@ -191,8 +191,8 @@ func (h *allocationHandler) renderSectionWithCreateError(w http.ResponseWriter,
}
ui.Render(w, r, blocks.AllocationsSection(blocks.AllocationsSectionProps{
SpaceID: spaceID, AccountID: accountID, Summary: summary,
CreateForm: &state,
ShowCreateForm: true,
CreateForm: &state,
ShowCreateForm: true,
}))
}

View file

@ -88,6 +88,23 @@ func (h *authHandler) SendMagicLink(w http.ResponseWriter, r *http.Request) {
err = h.authService.SendMagicLink(email)
if err != nil {
slog.Warn("magic link send failed", "error", err, "email", email)
if errors.Is(err, service.ErrRegistrationDisabled) {
msg := "Registration is disabled. Please contact an administrator if you need an account."
if r.URL.Query().Get("resend") == "true" {
ui.RenderToast(w, r, toast.Toast(toast.Props{
Title: "Magic link not sent",
Description: msg,
Variant: toast.VariantError,
Icon: true,
Dismissible: true,
Duration: 5000,
}))
return
}
ui.Render(w, r, pages.Auth(msg))
return
}
}
if r.URL.Query().Get("resend") == "true" {

View file

@ -24,7 +24,7 @@ func newTestAuthHandler(dbi testutil.DBInfo) *authHandler {
spaceSvc := service.NewSpaceService(spaceRepo)
accountSvc := service.NewAccountService(accountRepo)
emailSvc := service.NewEmailService(nil, "test@example.com", "http://localhost:9999", "Budgit Test", false)
authSvc := service.NewAuthService(emailSvc, userRepo, tokenRepo, spaceSvc, accountSvc, cfg.JWTSecret, cfg.JWTExpiry, cfg.TokenMagicLinkExpiry, false)
authSvc := service.NewAuthService(emailSvc, userRepo, tokenRepo, spaceSvc, accountSvc, cfg.JWTSecret, cfg.JWTExpiry, cfg.TokenMagicLinkExpiry, false, false)
inviteSvc := service.NewInviteService(inviteRepo, spaceRepo, userRepo, emailSvc, nil)
return NewAuthHandler(authSvc, inviteSvc, spaceSvc)
}

View file

@ -78,22 +78,22 @@ func (h *recurringEventHandler) CreatePage(w http.ResponseWriter, r *http.Reques
now := time.Now()
formProps := forms.RecurringEventFormProps{
SpaceID: spaceID,
Action: routeurl.URL("action.app.spaces.space.recurring.create", "spaceID", spaceID),
CancelHref: routeurl.URL("page.app.spaces.space.recurring", "spaceID", spaceID),
SubmitLabel: "Create",
Accounts: accounts,
Timezones: timezone.CommonTimezones(),
Kind: string(model.RecurringEventKindBill),
Frequency: string(model.RecurringFrequencyMonthly),
IntervalCount: "1",
FireTime: "09:00",
SpaceID: spaceID,
Action: routeurl.URL("action.app.spaces.space.recurring.create", "spaceID", spaceID),
CancelHref: routeurl.URL("page.app.spaces.space.recurring", "spaceID", spaceID),
SubmitLabel: "Create",
Accounts: accounts,
Timezones: timezone.CommonTimezones(),
Kind: string(model.RecurringEventKindBill),
Frequency: string(model.RecurringFrequencyMonthly),
IntervalCount: "1",
FireTime: "09:00",
Timezone: "UTC",
StartDate: now.Format("2006-01-02"),
BusinessDaysOnly: false,
DayOfMonth: strconv.Itoa(now.Day()),
DayOfWeek: strconv.Itoa(int(now.Weekday())),
MonthOfYear: strconv.Itoa(int(now.Month())),
DayOfMonth: strconv.Itoa(now.Day()),
DayOfWeek: strconv.Itoa(int(now.Weekday())),
MonthOfYear: strconv.Itoa(int(now.Month())),
}
ui.Render(w, r, pages.SpaceCreateRecurringEventPage(pages.SpaceCreateRecurringEventPageProps{
@ -126,19 +126,19 @@ func (h *recurringEventHandler) EditPage(w http.ResponseWriter, r *http.Request)
}
formProps := forms.RecurringEventFormProps{
SpaceID: spaceID,
Action: routeurl.URL("action.app.spaces.space.recurring.event.edit", "spaceID", spaceID, "eventID", eventID),
CancelHref: routeurl.URL("page.app.spaces.space.recurring", "spaceID", spaceID),
SubmitLabel: "Save",
Accounts: accounts,
Timezones: timezone.CommonTimezones(),
Title: ev.Title,
Kind: string(ev.Kind),
SourceAccountID: ev.SourceAccountID,
Amount: ev.Amount.StringFixedBank(2),
Frequency: string(ev.Frequency),
IntervalCount: strconv.Itoa(ev.IntervalCount),
FireTime: formatTimeOfDay(ev.FireHour, ev.FireMinute),
SpaceID: spaceID,
Action: routeurl.URL("action.app.spaces.space.recurring.event.edit", "spaceID", spaceID, "eventID", eventID),
CancelHref: routeurl.URL("page.app.spaces.space.recurring", "spaceID", spaceID),
SubmitLabel: "Save",
Accounts: accounts,
Timezones: timezone.CommonTimezones(),
Title: ev.Title,
Kind: string(ev.Kind),
SourceAccountID: ev.SourceAccountID,
Amount: ev.Amount.StringFixedBank(2),
Frequency: string(ev.Frequency),
IntervalCount: strconv.Itoa(ev.IntervalCount),
FireTime: formatTimeOfDay(ev.FireHour, ev.FireMinute),
Timezone: ev.Timezone,
StartDate: ev.NextRunAt.In(mustLoc(ev.Timezone)).Format("2006-01-02"),
BusinessDaysOnly: ev.BusinessDaysOnly,
@ -215,19 +215,19 @@ func (h *recurringEventHandler) HandleEdit(w http.ResponseWriter, r *http.Reques
}
if _, err := h.recurringService.Update(service.UpdateRecurringEventInput{
ID: eventID,
Kind: parsed.Kind,
SourceAccountID: parsed.SourceAccountID,
Title: parsed.Title,
Amount: parsed.Amount,
Description: parsed.Description,
Frequency: parsed.Frequency,
IntervalCount: parsed.IntervalCount,
DayOfWeek: parsed.DayOfWeek,
DayOfMonth: parsed.DayOfMonth,
MonthOfYear: parsed.MonthOfYear,
FireHour: parsed.FireHour,
FireMinute: parsed.FireMinute,
ID: eventID,
Kind: parsed.Kind,
SourceAccountID: parsed.SourceAccountID,
Title: parsed.Title,
Amount: parsed.Amount,
Description: parsed.Description,
Frequency: parsed.Frequency,
IntervalCount: parsed.IntervalCount,
DayOfWeek: parsed.DayOfWeek,
DayOfMonth: parsed.DayOfMonth,
MonthOfYear: parsed.MonthOfYear,
FireHour: parsed.FireHour,
FireMinute: parsed.FireMinute,
Timezone: parsed.Timezone,
BusinessDaysOnly: parsed.BusinessDaysOnly,
StartDate: parsed.StartDate,
@ -305,19 +305,19 @@ func (h *recurringEventHandler) parseForm(r *http.Request, spaceID string) (serv
businessDaysOnly := r.FormValue("business_days_only") != ""
props := forms.RecurringEventFormProps{
SpaceID: spaceID,
Accounts: accounts,
Timezones: timezone.CommonTimezones(),
Title: title,
Kind: kind,
SourceAccountID: sourceID,
Amount: amountStr,
Description: descriptionStr,
Frequency: frequency,
IntervalCount: intervalStr,
DayOfWeek: dowStr,
DayOfMonth: domStr,
MonthOfYear: moyStr,
SpaceID: spaceID,
Accounts: accounts,
Timezones: timezone.CommonTimezones(),
Title: title,
Kind: kind,
SourceAccountID: sourceID,
Amount: amountStr,
Description: descriptionStr,
Frequency: frequency,
IntervalCount: intervalStr,
DayOfWeek: dowStr,
DayOfMonth: domStr,
MonthOfYear: moyStr,
FireTime: fireTime,
Timezone: tz,
StartDate: startDateStr,

View file

@ -21,7 +21,7 @@ func newTestSettingsHandler(dbi testutil.DBInfo) (*settingsHandler, *service.Aut
spaceSvc := service.NewSpaceService(spaceRepo)
accountSvc := service.NewAccountService(accountRepo)
emailSvc := service.NewEmailService(nil, "test@example.com", "http://localhost:9999", "Budgit Test", false)
authSvc := service.NewAuthService(emailSvc, userRepo, tokenRepo, spaceSvc, accountSvc, cfg.JWTSecret, cfg.JWTExpiry, cfg.TokenMagicLinkExpiry, false)
authSvc := service.NewAuthService(emailSvc, userRepo, tokenRepo, spaceSvc, accountSvc, cfg.JWTSecret, cfg.JWTExpiry, cfg.TokenMagicLinkExpiry, false, false)
userSvc := service.NewUserService(userRepo)
return NewSettingsHandler(authSvc, userSvc), authSvc
}

View file

@ -330,15 +330,15 @@ func (h *spaceHandler) SpaceAccountPage(w http.ResponseWriter, r *http.Request)
}
ui.Render(w, r, pages.SpaceAccountPage(pages.SpaceAccountPageProps{
SpaceID: spaceID,
SpaceName: space.Name,
AccountID: accountID,
AccountName: account.Name,
AccountBalance: account.Balance,
AccountCurrency: account.Currency,
RecentTransactions: recent,
SpaceID: spaceID,
SpaceName: space.Name,
AccountID: accountID,
AccountName: account.Name,
AccountBalance: account.Balance,
AccountCurrency: account.Currency,
RecentTransactions: recent,
NonEditableTransactionIDs: h.nonEditableTransactionIDs(recent),
AllocationSummary: allocSummary,
AllocationSummary: allocSummary,
}))
}
@ -396,16 +396,16 @@ func (h *spaceHandler) SpaceAccountTransactionsPage(w http.ResponseWriter, r *ht
}
ui.Render(w, r, pages.SpaceAccountTransactionsPage(pages.SpaceAccountTransactionsPageProps{
SpaceID: spaceID,
SpaceName: space.Name,
AccountID: accountID,
AccountName: account.Name,
Transactions: txns,
SpaceID: spaceID,
SpaceName: space.Name,
AccountID: accountID,
AccountName: account.Name,
Transactions: txns,
NonEditableTransactionIDs: h.nonEditableTransactionIDs(txns),
CurrentPage: page,
TotalPages: totalPages,
TotalCount: total,
PerPage: perPage,
CurrentPage: page,
TotalPages: totalPages,
TotalCount: total,
PerPage: perPage,
}))
}