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:
2026-07-03 14:53:29 +07:00
parent 763919d23f
commit ae6a4d7f4c
6 changed files with 918 additions and 8 deletions
+80
View File
@@ -0,0 +1,80 @@
package api
import (
"github.com/google/uuid"
"github.com/vasyakrg/dns-autoresolver/internal/store"
"github.com/vasyakrg/dns-autoresolver/internal/store/dto"
)
type accountRequest struct {
Provider string `json:"provider"`
Secret string `json:"secret"`
Comment string `json:"comment"`
}
// accountResponse deliberately excludes the secret (plaintext or encrypted).
type accountResponse struct {
ID string `json:"id"`
Provider string `json:"provider"`
Comment string `json:"comment"`
}
func toAccountResponse(a store.Account) accountResponse {
return accountResponse{ID: a.ID.String(), Provider: a.Provider, Comment: a.Comment}
}
type templateRequest struct {
Name string `json:"name"`
Records []dto.RecordDTO `json:"records"`
}
type templateResponse struct {
ID string `json:"id"`
Name string `json:"name"`
Records []dto.RecordDTO `json:"records"`
Version int32 `json:"version"`
}
func toTemplateResponse(t store.Template) templateResponse {
return templateResponse{ID: t.ID.String(), Name: t.Name, Records: t.Doc.Records, Version: t.Version}
}
type domainRequest struct {
ProviderAccountID string `json:"providerAccountId"`
ZoneName string `json:"zoneName"`
ZoneID string `json:"zoneId"`
TemplateID *string `json:"templateId,omitempty"`
}
type domainResponse struct {
ID string `json:"id"`
ProviderAccountID string `json:"providerAccountId"`
ZoneName string `json:"zoneName"`
ZoneID string `json:"zoneId"`
TemplateID *string `json:"templateId,omitempty"`
}
func toDomainResponse(d store.Domain) domainResponse {
resp := domainResponse{
ID: d.ID.String(), ProviderAccountID: d.ProviderAccountID.String(),
ZoneName: d.ZoneName, ZoneID: d.ZoneID,
}
if d.TemplateID != nil {
s := d.TemplateID.String()
resp.TemplateID = &s
}
return resp
}
// parseOptionalUUID parses s (may be nil/empty) into *uuid.UUID; returns ok=false on invalid input.
func parseOptionalUUID(s *string) (*uuid.UUID, bool) {
if s == nil || *s == "" {
return nil, true
}
id, err := uuid.Parse(*s)
if err != nil {
return nil, false
}
return &id, true
}