feat(api): CRUD accounts/templates/domains + import зон (полный цикл), secret не в ответах
Task 9 Фазы 1B: узкий интерфейс TenantStore (внутри store.Account/Template/Domain,
без db.* в api) реализован тонкими обёртками в internal/store/tenant.go; API.Store/
Cipher/Reg добавлены к существующему Svc. Роуты POST/GET/DELETE для accounts/
templates/domains + POST /accounts/{aid}/import (ListZones -> CreateDomain на зону).
accountResponse не содержит секрет ни в каком виде.
This commit is contained in:
+64
-7
@@ -9,7 +9,10 @@ import (
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/vasyakrg/dns-autoresolver/internal/diff"
|
||||
"github.com/vasyakrg/dns-autoresolver/internal/provider"
|
||||
"github.com/vasyakrg/dns-autoresolver/internal/service"
|
||||
"github.com/vasyakrg/dns-autoresolver/internal/store"
|
||||
"github.com/vasyakrg/dns-autoresolver/internal/store/dto"
|
||||
)
|
||||
|
||||
// CheckApplier is the service surface the API depends on.
|
||||
@@ -18,10 +21,42 @@ type CheckApplier interface {
|
||||
Apply(ctx context.Context, domainID uuid.UUID, req service.ApplyRequest) (diff.Changeset, error)
|
||||
}
|
||||
|
||||
// API holds handler dependencies. Store/Cipher are used by CRUD handlers
|
||||
// (added by the implementer following the accounts pattern).
|
||||
// TenantStore is the narrow persistence surface the CRUD handlers depend on.
|
||||
// *store.Store satisfies it directly via its thin wrapper methods (see
|
||||
// internal/store/tenant.go); tests can supply their own mock.
|
||||
type TenantStore interface {
|
||||
CreateAccount(ctx context.Context, projectID uuid.UUID, provider, secretEnc, comment string) (store.Account, error)
|
||||
ListAccounts(ctx context.Context, projectID uuid.UUID) ([]store.Account, error)
|
||||
GetAccount(ctx context.Context, id, projectID uuid.UUID) (store.Account, error)
|
||||
DeleteAccount(ctx context.Context, id, projectID uuid.UUID) error
|
||||
|
||||
CreateTemplate(ctx context.Context, projectID uuid.UUID, name string, doc dto.TemplateDoc) (store.Template, error)
|
||||
ListTemplates(ctx context.Context, projectID uuid.UUID) ([]store.Template, error)
|
||||
UpdateTemplate(ctx context.Context, id, projectID uuid.UUID, name string, doc dto.TemplateDoc) (store.Template, error)
|
||||
DeleteTemplate(ctx context.Context, id, projectID uuid.UUID) error
|
||||
|
||||
CreateDomain(ctx context.Context, projectID, accountID uuid.UUID, zoneName, zoneID string, templateID *uuid.UUID) (store.Domain, error)
|
||||
ListDomains(ctx context.Context, projectID uuid.UUID) ([]store.Domain, error)
|
||||
DeleteDomain(ctx context.Context, id, projectID uuid.UUID) error
|
||||
}
|
||||
|
||||
// Cipher encrypts/decrypts provider account secrets. *crypto.Cipher satisfies it.
|
||||
type Cipher interface {
|
||||
Encrypt(plaintext []byte) (string, error)
|
||||
Decrypt(enc string) ([]byte, error)
|
||||
}
|
||||
|
||||
// ProviderRegistry resolves a provider.Provider by name. *registry.Registry satisfies it.
|
||||
type ProviderRegistry interface {
|
||||
ByName(name string) (provider.Provider, error)
|
||||
}
|
||||
|
||||
// API holds handler dependencies.
|
||||
type API struct {
|
||||
Svc CheckApplier
|
||||
Svc CheckApplier
|
||||
Store TenantStore
|
||||
Cipher Cipher
|
||||
Reg ProviderRegistry
|
||||
}
|
||||
|
||||
func NewRouter(a *API) http.Handler {
|
||||
@@ -30,11 +65,33 @@ func NewRouter(a *API) http.Handler {
|
||||
r.Use(middleware.Recoverer)
|
||||
|
||||
r.Route("/api/v1/projects/{pid}", func(r chi.Router) {
|
||||
r.Route("/domains/{did}", func(r chi.Router) {
|
||||
r.Get("/check", a.handleCheck)
|
||||
r.Post("/apply", a.handleApply)
|
||||
r.Route("/domains", func(r chi.Router) {
|
||||
r.Post("/", a.handleCreateDomain)
|
||||
r.Get("/", a.handleListDomains)
|
||||
r.Route("/{did}", func(r chi.Router) {
|
||||
r.Get("/check", a.handleCheck)
|
||||
r.Post("/apply", a.handleApply)
|
||||
r.Delete("/", a.handleDeleteDomain)
|
||||
})
|
||||
})
|
||||
|
||||
r.Route("/accounts", func(r chi.Router) {
|
||||
r.Post("/", a.handleCreateAccount)
|
||||
r.Get("/", a.handleListAccounts)
|
||||
r.Route("/{aid}", func(r chi.Router) {
|
||||
r.Delete("/", a.handleDeleteAccount)
|
||||
r.Post("/import", a.handleImportZones)
|
||||
})
|
||||
})
|
||||
|
||||
r.Route("/templates", func(r chi.Router) {
|
||||
r.Post("/", a.handleCreateTemplate)
|
||||
r.Get("/", a.handleListTemplates)
|
||||
r.Route("/{tid}", func(r chi.Router) {
|
||||
r.Put("/", a.handleUpdateTemplate)
|
||||
r.Delete("/", a.handleDeleteTemplate)
|
||||
})
|
||||
})
|
||||
// accounts/templates/domains CRUD маунтятся тем же паттерном (Task 4 sqlc-методы)
|
||||
})
|
||||
return r
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user