Refactor database interface in smaller interfaces

This commit is contained in:
nemunaire 2025-05-04 15:26:08 +02:00
parent a224f0e212
commit 001e352e57
24 changed files with 211 additions and 128 deletions

View file

@ -36,10 +36,10 @@ import (
type AuthUserController struct {
auService happydns.AuthUserUsecase
store storage.Storage
store storage.AuthUserStorage
}
func NewAuthUserController(auService happydns.AuthUserUsecase, store storage.Storage) *AuthUserController {
func NewAuthUserController(auService happydns.AuthUserUsecase, store storage.AuthUserStorage) *AuthUserController {
return &AuthUserController{
auService,
store,

View file

@ -37,10 +37,10 @@ import (
type DomainController struct {
domainService happydns.DomainUsecase
store storage.Storage
store storage.DomainStorage
}
func NewDomainController(duService happydns.DomainUsecase, store storage.Storage) *DomainController {
func NewDomainController(duService happydns.DomainUsecase, store storage.DomainStorage) *DomainController {
return &DomainController{
duService,
store,
@ -55,22 +55,11 @@ func (dc *DomainController) ListDomains(c *gin.Context) {
return
}
var domains happydns.Domains
users, err := dc.store.ListAllUsers()
domains, err := dc.store.ListAllDomains()
if err != nil {
middleware.ErrorResponse(c, http.StatusInternalServerError, fmt.Errorf("unable to retrieve users list: %w", err))
middleware.ErrorResponse(c, http.StatusInternalServerError, fmt.Errorf("unable to retrieve domains list: %w", err))
return
}
for _, user := range users {
usersDomains, err := dc.store.ListDomains(user)
if err != nil {
middleware.ErrorResponse(c, http.StatusInternalServerError, fmt.Errorf("unable to retrieve %s's domains: %w", user.Email, err))
return
}
domains = append(domains, usersDomains...)
}
happydns.ApiResponse(c, domains, nil)
}
@ -121,22 +110,15 @@ func (dc *DomainController) DeleteDomain(c *gin.Context) {
}
func (dc *DomainController) searchUserDomain(filter func(*happydns.Domain) bool) *happydns.User {
users, err := dc.store.ListAllUsers()
domains, err := dc.store.ListAllDomains()
if err != nil {
log.Println("Unable to retrieve users list:", err.Error())
log.Println("Unable to retrieve domains list:", err.Error())
return nil
}
for _, user := range users {
usersDomains, err := dc.store.ListDomains(user)
if err != nil {
log.Printf("Unable to retrieve %s's domains: %s", user.Email, err.Error())
continue
}
for _, domain := range usersDomains {
if filter(domain) {
return user
}
for _, domain := range domains {
if filter(domain) {
// Create a fake minimal user, as only the Id is required to perform further actions on database
return &happydns.User{Id: domain.Owner}
}
}
@ -225,3 +207,15 @@ func (dc *DomainController) ClearDomains(c *gin.Context) {
happydns.ApiResponse(c, true, dc.store.ClearDomains())
}
func (dc *DomainController) UpdateZones(c *gin.Context) {
domain := c.MustGet("domain").(*happydns.Domain)
err := c.ShouldBindJSON(&domain.ZoneHistory)
if err != nil {
middleware.ErrorResponse(c, http.StatusNotFound, fmt.Errorf("something is wrong in received data: %w", err))
return
}
happydns.ApiResponse(c, domain, dc.store.UpdateDomain(domain))
}

View file

@ -36,10 +36,10 @@ import (
type ProviderController struct {
providerService happydns.ProviderUsecase
store storage.Storage
store storage.ProviderStorage
}
func NewProviderController(providerService happydns.ProviderUsecase, store storage.Storage) *ProviderController {
func NewProviderController(providerService happydns.ProviderUsecase, store storage.ProviderStorage) *ProviderController {
return &ProviderController{
providerService,
store,
@ -54,25 +54,19 @@ func (pc *ProviderController) ListProviders(c *gin.Context) {
return
}
var providers []*happydns.ProviderMeta
var res []*happydns.ProviderMeta
users, err := pc.store.ListAllUsers()
providers, err := pc.store.ListAllProviders()
if err != nil {
middleware.ErrorResponse(c, http.StatusInternalServerError, fmt.Errorf("unable to list users: %w", err))
middleware.ErrorResponse(c, http.StatusInternalServerError, fmt.Errorf("unable to list providers: %w", err))
return
}
for _, user := range users {
usersProviders, err := pc.store.ListProviders(user)
if err != nil {
middleware.ErrorResponse(c, http.StatusInternalServerError, fmt.Errorf("unable to list users: %w", err))
return
}
providers = append(providers, usersProviders.Metas()...)
for _, provider := range providers {
res = append(res, &provider.ProviderMeta)
}
happydns.ApiResponse(c, providers, nil)
happydns.ApiResponse(c, res, nil)
}
func (pc *ProviderController) AddProvider(c *gin.Context) {

View file

@ -28,7 +28,6 @@ import (
"github.com/gin-gonic/gin"
"git.happydns.org/happyDomain/api/middleware"
"git.happydns.org/happyDomain/internal/storage"
"git.happydns.org/happyDomain/model"
"git.happydns.org/happyDomain/usecase"
)
@ -36,14 +35,12 @@ import (
type ServiceController struct {
serviceService happydns.ServiceUsecase
zoneService happydns.ZoneUsecase
store storage.Storage
}
func NewServiceController(serviceService happydns.ServiceUsecase, zoneService happydns.ZoneUsecase, store storage.Storage) *ServiceController {
func NewServiceController(serviceService happydns.ServiceUsecase, zoneService happydns.ZoneUsecase) *ServiceController {
return &ServiceController{
serviceService,
zoneService,
store,
}
}

View file

@ -33,10 +33,10 @@ import (
type SessionController struct {
config *config.Options
store storage.Storage
store storage.SessionStorage
}
func NewSessionController(cfg *config.Options, store storage.Storage) *SessionController {
func NewSessionController(cfg *config.Options, store storage.SessionStorage) *SessionController {
return &SessionController{
config: cfg,
store: store,

View file

@ -0,0 +1,43 @@
// This file is part of the happyDomain (R) project.
// Copyright (c) 2020-2024 happyDomain
// Authors: Pierre-Olivier Mercier, et al.
//
// This program is offered under a commercial and under the AGPL license.
// For commercial licensing, contact us at <contact@happydomain.org>.
//
// For AGPL licensing:
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package controller
import (
"github.com/gin-gonic/gin"
"git.happydns.org/happyDomain/internal/storage"
"git.happydns.org/happyDomain/model"
)
type TidyController struct {
store storage.Storage
}
func NewTidyController(store storage.Storage) *TidyController {
return &TidyController{
store: store,
}
}
func (tc *TidyController) TidyDB(c *gin.Context) {
happydns.ApiResponse(c, true, tc.store.Tidy())
}

View file

@ -34,7 +34,7 @@ import (
type UserController struct {
userService happydns.UserUsecase
store storage.Storage
store storage.UserStorage
}
func NewUserController(store storage.Storage, userService happydns.UserUsecase) *UserController {
@ -104,7 +104,3 @@ func (uc *UserController) DeleteUser(c *gin.Context) {
happydns.ApiResponse(c, true, uc.store.DeleteUser(user.Id))
}
func (uc *UserController) TidyDB(c *gin.Context) {
happydns.ApiResponse(c, true, uc.store.Tidy())
}

View file

@ -36,10 +36,10 @@ import (
type ZoneController struct {
domainService happydns.DomainUsecase
zoneService happydns.ZoneUsecase
store storage.Storage
store storage.ZoneStorage
}
func NewZoneController(domainService happydns.DomainUsecase, zoneService happydns.ZoneUsecase, store storage.Storage) *ZoneController {
func NewZoneController(domainService happydns.DomainUsecase, zoneService happydns.ZoneUsecase, store storage.ZoneStorage) *ZoneController {
return &ZoneController{
domainService,
zoneService,
@ -93,15 +93,3 @@ func (zc *ZoneController) UpdateZone(c *gin.Context) {
happydns.ApiResponse(c, uz, zc.store.UpdateZone(uz))
}
func (zc *ZoneController) UpdateZones(c *gin.Context) {
domain := c.MustGet("domain").(*happydns.Domain)
err := c.ShouldBindJSON(&domain.ZoneHistory)
if err != nil {
middleware.ErrorResponse(c, http.StatusNotFound, fmt.Errorf("something is wrong in received data: %w", err))
return
}
happydns.ApiResponse(c, domain, zc.store.UpdateDomain(domain))
}

View file

@ -45,5 +45,6 @@ func declareDomainRoutes(router *gin.RouterGroup, dependancies happydns.UsecaseD
apiDomainsRoutes.GET("", dc.GetDomain)
apiDomainsRoutes.PUT("", dc.UpdateDomain)
apiDomainsRoutes.PUT("/zones", dc.UpdateZones)
declareZoneRoutes(apiDomainsRoutes, dependancies, store)
}

View file

@ -39,5 +39,6 @@ func DeclareRoutes(cfg *config.Options, router *gin.Engine, s storage.Storage, d
declareSessionsRoutes(cfg, apiRoutes, s)
declareUserAuthsRoutes(apiRoutes, dependancies, s)
declareUsersRoutes(apiRoutes, dependancies, s)
declareTidyRoutes(apiRoutes, s)
api.DeclareVersionRoutes(apiRoutes)
}

View file

@ -31,7 +31,7 @@ import (
)
func declareZoneServiceRoutes(apiZonesRoutes *gin.RouterGroup, zc *controller.ZoneController, dependancies happydns.UsecaseDependancies, store storage.Storage) {
sc := controller.NewServiceController(dependancies.GetServiceService(), dependancies.GetZoneService(), store)
sc := controller.NewServiceController(dependancies.GetServiceService(), dependancies.GetZoneService())
apiZonesServiceIdRoutes := apiZonesRoutes.Group("/services/:serviceid")
apiZonesServiceIdRoutes.Use(middleware.ServiceIdHandler(dependancies.GetServiceService()))

35
api-admin/route/tidy.go Normal file
View file

@ -0,0 +1,35 @@
// This file is part of the happyDomain (R) project.
// Copyright (c) 2020-2024 happyDomain
// Authors: Pierre-Olivier Mercier, et al.
//
// This program is offered under a commercial and under the AGPL license.
// For commercial licensing, contact us at <contact@happydomain.org>.
//
// For AGPL licensing:
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package route
import (
"github.com/gin-gonic/gin"
"git.happydns.org/happyDomain/api-admin/controller"
"git.happydns.org/happyDomain/internal/storage"
)
func declareTidyRoutes(router *gin.RouterGroup, store storage.Storage) {
tc := controller.NewTidyController(store)
router.POST("/tidy", tc.TidyDB)
}

View file

@ -45,6 +45,4 @@ func declareUsersRoutes(router *gin.RouterGroup, dependancies happydns.UsecaseDe
declareDomainRoutes(apiUsersRoutes, dependancies, store)
declareProviderRoutes(apiUsersRoutes, dependancies, store)
router.POST("/tidy", sc.TidyDB)
}

View file

@ -34,8 +34,8 @@ func declareZoneRoutes(router *gin.RouterGroup, dependancies happydns.UsecaseDep
zc := controller.NewZoneController(dependancies.GetDomainService(), dependancies.GetZoneService(), store)
router.GET("/zones", zc.ListZones)
router.PUT("/zones", zc.UpdateZones)
router.POST("/zones", zc.AddZone)
// PUT /zones is handled by DomainController
router.DELETE("/zones/:zoneid", zc.DeleteZone)

View file

@ -27,21 +27,8 @@ import (
"git.happydns.org/happyDomain/model"
)
type Storage interface {
// SchemaVersion returns the version of the migration currently in use.
SchemaVersion() int
// DoMigration is the first function called.
DoMigration() error
// Tidy should optimize the database, looking for orphan records, ...
Tidy() error
// Close shutdown the connection with the database and releases all structure.
Close() error
// AUTH -------------------------------------------------------
// AUTH ---------------------------------------------------------------
type AuthUserStorage interface {
// ListAllAuthUsers retrieves the list of known Users.
ListAllAuthUsers() (happydns.UserAuths, error)
@ -65,9 +52,10 @@ type Storage interface {
// ClearAuthUsers deletes all AuthUsers present in the database.
ClearAuthUsers() error
}
// DOMAINS ----------------------------------------------------
// DOMAINS ------------------------------------------------------------
type DomainStorage interface {
// ListAllDomains retrieves the list of known Domains.
ListAllDomains() (happydns.Domains, error)
@ -101,17 +89,19 @@ type Storage interface {
UpdateDomainLog(*happydns.Domain, *happydns.DomainLog) error
DeleteDomainLog(*happydns.Domain, *happydns.DomainLog) error
}
// INSIGHTS ----------------------------------------------------
// INSIGHTS -----------------------------------------------------------
type InsightStorage interface {
// InsightsRun registers a insights process run just now.
InsightsRun() error
// LastInsightsRun gets the last time insights process run.
LastInsightsRun() (*time.Time, happydns.Identifier, error)
}
// PROVIDERS ----------------------------------------------------
// PROVIDERS ----------------------------------------------------------
type ProviderStorage interface {
// ListAllProviders retrieves the list of known Providers.
ListAllProviders() (happydns.ProviderMessages, error)
@ -132,9 +122,10 @@ type Storage interface {
// ClearProviders deletes all Providers present in the database.
ClearProviders() error
}
// SESSIONS ---------------------------------------------------
// SESSIONS -----------------------------------------------------------
type SessionStorage interface {
// ListAllSessions retrieves the list of known Sessions.
ListAllSessions() ([]*happydns.Session, error)
@ -155,9 +146,10 @@ type Storage interface {
// ClearSessions deletes all Sessions present in the database.
ClearSessions() error
}
// USERS ------------------------------------------------------
// USERS --------------------------------------------------------------
type UserStorage interface {
// ListAllUsers retrieves the list of known Users.
ListAllUsers() (happydns.Users, error)
@ -175,9 +167,10 @@ type Storage interface {
// ClearUsers deletes all Users present in the database.
ClearUsers() error
}
// ZONES ------------------------------------------------------
// ZONES --------------------------------------------------------------
type ZoneStorage interface {
// ListAllZones retrieves the list of known Zones.
ListAllZones() ([]*happydns.ZoneMessage, error)
@ -199,3 +192,46 @@ type Storage interface {
// ClearZones deletes all Zones present in the database.
ClearZones() error
}
type AuthenticationStorage interface {
AuthUserStorage
UserStorage
}
type AuthUserAndSessionStorage interface {
AuthUserStorage
SessionStorage
}
type ProviderAndDomainStorage interface {
ProviderStorage
DomainStorage
}
type UserAndSessionStorage interface {
AuthUserStorage
SessionStorage
UserStorage
}
type Storage interface {
AuthUserStorage
DomainStorage
InsightStorage
ProviderStorage
SessionStorage
UserStorage
ZoneStorage
// SchemaVersion returns the version of the migration currently in use.
SchemaVersion() int
// DoMigration is the first function called.
DoMigration() error
// Tidy should optimize the database, looking for orphan records, ...
Tidy() error
// Close shutdown the connection with the database and releases all structure.
Close() error
}

View file

@ -38,10 +38,10 @@ import (
type authUserUsecase struct {
config *config.Options
mailer *mailer.Mailer
store storage.Storage
store storage.AuthUserAndSessionStorage
}
func NewAuthUserUsecase(cfg *config.Options, m *mailer.Mailer, store storage.Storage) happydns.AuthUserUsecase {
func NewAuthUserUsecase(cfg *config.Options, m *mailer.Mailer, store storage.AuthUserAndSessionStorage) happydns.AuthUserUsecase {
return &authUserUsecase{
config: cfg,
mailer: m,

View file

@ -32,11 +32,11 @@ import (
type loginUsecase struct {
config *config.Options
store storage.Storage
store storage.AuthenticationStorage
userService happydns.UserUsecase
}
func NewAuthenticationUsecase(cfg *config.Options, store storage.Storage, userService happydns.UserUsecase) happydns.AuthenticationUsecase {
func NewAuthenticationUsecase(cfg *config.Options, store storage.AuthenticationStorage, userService happydns.UserUsecase) happydns.AuthenticationUsecase {
return &loginUsecase{
config: cfg,
store: store,

View file

@ -38,11 +38,11 @@ import (
type domainUsecase struct {
domainLogService happydns.DomainLogUsecase
providerService happydns.ProviderUsecase
store storage.Storage
store storage.DomainStorage
zoneService happydns.ZoneUsecase
}
func NewDomainUsecase(store storage.Storage, domainLogService happydns.DomainLogUsecase, providerService happydns.ProviderUsecase, zoneService happydns.ZoneUsecase) happydns.DomainUsecase {
func NewDomainUsecase(store storage.DomainStorage, domainLogService happydns.DomainLogUsecase, providerService happydns.ProviderUsecase, zoneService happydns.ZoneUsecase) happydns.DomainUsecase {
return &domainUsecase{
domainLogService: domainLogService,
providerService: providerService,
@ -116,7 +116,7 @@ corrections:
// Create a new zone in history for futher updates
newZone := zone.DerivateNew()
err = du.store.CreateZone(newZone)
err = du.zoneService.CreateZone(newZone)
if err != nil {
return nil, happydns.InternalError{
Err: fmt.Errorf("unable to CreateZone: %w", err),
@ -138,15 +138,15 @@ corrections:
}
// Commit changes in previous zone
now := time.Now()
zone.ZoneMeta.IdAuthor = user.Id
zone.CommitMsg = &form.CommitMsg
zone.ZoneMeta.CommitDate = &now
zone.ZoneMeta.Published = &now
err = du.zoneService.UpdateZone(zone.ZoneMeta.Id, func(zone *happydns.Zone) {
now := time.Now()
zone.ZoneMeta.IdAuthor = user.Id
zone.CommitMsg = &form.CommitMsg
zone.ZoneMeta.CommitDate = &now
zone.ZoneMeta.Published = &now
zone.LastModified = time.Now()
err = du.store.UpdateZone(zone)
zone.LastModified = time.Now()
})
if err != nil {
return nil, happydns.InternalError{
Err: fmt.Errorf("unable to UpdateZone: %w", err),

View file

@ -31,10 +31,10 @@ import (
)
type domainLogUsecase struct {
store storage.Storage
store storage.DomainStorage
}
func NewDomainLogUsecase(store storage.Storage) happydns.DomainLogUsecase {
func NewDomainLogUsecase(store storage.DomainStorage) happydns.DomainLogUsecase {
return &domainLogUsecase{
store: store,
}

View file

@ -37,7 +37,7 @@ type providerUsecase struct {
config *config.Options
}
func NewProviderUsecase(cfg *config.Options, store storage.Storage) happydns.ProviderUsecase {
func NewProviderUsecase(cfg *config.Options, store storage.ProviderAndDomainStorage) happydns.ProviderUsecase {
return &providerUsecase{
ProviderUsecase: NewAdminProviderUsecase(store),
config: cfg,
@ -89,10 +89,10 @@ func (pu *providerUsecase) UpdateProviderFromMessage(providerid happydns.Identif
}
type adminProviderUsecase struct {
store storage.Storage
store storage.ProviderAndDomainStorage
}
func NewAdminProviderUsecase(store storage.Storage) happydns.ProviderUsecase {
func NewAdminProviderUsecase(store storage.ProviderAndDomainStorage) happydns.ProviderUsecase {
return &adminProviderUsecase{
store: store,
}

View file

@ -34,10 +34,10 @@ import (
type providerSettingsUsecase struct {
config *config.Options
providerService happydns.ProviderUsecase
store storage.Storage
store storage.ProviderStorage
}
func NewProviderSettingsUsecase(cfg *config.Options, ps happydns.ProviderUsecase, store storage.Storage) happydns.ProviderSettingsUsecase {
func NewProviderSettingsUsecase(cfg *config.Options, ps happydns.ProviderUsecase, store storage.ProviderStorage) happydns.ProviderSettingsUsecase {
return &providerSettingsUsecase{
config: cfg,
providerService: ps,

View file

@ -33,10 +33,10 @@ import (
)
type sessionUsecase struct {
store storage.Storage
store storage.SessionStorage
}
func NewSessionUsecase(store storage.Storage) happydns.SessionUsecase {
func NewSessionUsecase(store storage.SessionStorage) happydns.SessionUsecase {
return &sessionUsecase{
store: store,
}

View file

@ -35,10 +35,10 @@ import (
type userUsecase struct {
newsletter happydns.NewsletterSubscriptor
store storage.Storage
store storage.UserAndSessionStorage
}
func NewUserUsecase(store storage.Storage, ns happydns.NewsletterSubscriptor) happydns.UserUsecase {
func NewUserUsecase(store storage.UserAndSessionStorage, ns happydns.NewsletterSubscriptor) happydns.UserUsecase {
return &userUsecase{
newsletter: ns,
store: store,

View file

@ -36,10 +36,10 @@ import (
type zoneUsecase struct {
providerService happydns.ProviderUsecase
serviceService happydns.ServiceUsecase
store storage.Storage
store storage.ZoneStorage
}
func NewZoneUsecase(pu happydns.ProviderUsecase, su happydns.ServiceUsecase, store storage.Storage) happydns.ZoneUsecase {
func NewZoneUsecase(pu happydns.ProviderUsecase, su happydns.ServiceUsecase, store storage.ZoneStorage) happydns.ZoneUsecase {
return &zoneUsecase{
providerService: pu,
serviceService: su,