feat(api): read zone records without template + snapshot-to-template
LoadDomain requires a template, so a zone without one could never be
viewed or snapshotted. Adds a template-free path: store.LoadZone /
service.ZoneRef / DomainService.ZoneRecords read a zone's live records
straight from the provider (no diff, no template). GET
/domains/{did}/records exposes read-only viewing; POST
/domains/{did}/template-from-zone snapshots only managed record types
(NS/SOA excluded) into a new template and auto-attaches it to the domain.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BwxdSt4reTm7Dj1oxRvpP3
This commit is contained in:
@@ -10,7 +10,9 @@ import (
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/vasyakrg/dns-autoresolver/internal/model"
|
||||
"github.com/vasyakrg/dns-autoresolver/internal/service"
|
||||
"github.com/vasyakrg/dns-autoresolver/internal/store/dto"
|
||||
)
|
||||
|
||||
func writeJSON(w http.ResponseWriter, status int, v any) {
|
||||
@@ -70,3 +72,68 @@ func (a *API) handleApply(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
writeJSON(w, http.StatusOK, toChangesetResponse(cs))
|
||||
}
|
||||
|
||||
// handleZoneRecords reads a zone's current records straight from the
|
||||
// provider — no template required, no diff computed. Backs read-only zone
|
||||
// viewing for domains that don't have a template attached (yet).
|
||||
func (a *API) handleZoneRecords(w http.ResponseWriter, r *http.Request) {
|
||||
pid, _ := projectIDFrom(r.Context())
|
||||
did, err := uuid.Parse(chi.URLParam(r, "did"))
|
||||
if err != nil {
|
||||
writeErr(w, http.StatusBadRequest, "invalid domain id")
|
||||
return
|
||||
}
|
||||
recs, err := a.Svc.ZoneRecords(r.Context(), pid, did)
|
||||
if err != nil {
|
||||
log.Printf("api: zone records failed: %v", err)
|
||||
writeErr(w, http.StatusBadGateway, "не удалось получить записи зоны у провайдера")
|
||||
return
|
||||
}
|
||||
doc := dto.FromModel(recs)
|
||||
writeJSON(w, http.StatusOK, doc.Records) // []dto.RecordDTO
|
||||
}
|
||||
|
||||
// handleTemplateFromZone snapshots a zone's current managed records (NS/SOA
|
||||
// excluded — they're read-only, never part of a template) into a brand new
|
||||
// template, then auto-attaches it to the domain so check/apply become
|
||||
// available immediately.
|
||||
func (a *API) handleTemplateFromZone(w http.ResponseWriter, r *http.Request) {
|
||||
pid, _ := projectIDFrom(r.Context())
|
||||
did, err := uuid.Parse(chi.URLParam(r, "did"))
|
||||
if err != nil {
|
||||
writeErr(w, http.StatusBadRequest, "invalid domain id")
|
||||
return
|
||||
}
|
||||
dom, err := a.Store.GetDomain(r.Context(), did, pid)
|
||||
if err != nil {
|
||||
log.Printf("api: template-from-zone: get domain failed: %v", err)
|
||||
writeErr(w, http.StatusInternalServerError, "internal error")
|
||||
return
|
||||
}
|
||||
recs, err := a.Svc.ZoneRecords(r.Context(), pid, did)
|
||||
if err != nil {
|
||||
log.Printf("api: template-from-zone: zone records failed: %v", err)
|
||||
writeErr(w, http.StatusBadGateway, "не удалось получить записи зоны у провайдера")
|
||||
return
|
||||
}
|
||||
// Snapshot only managed records — NS/SOA are read-only and never templated.
|
||||
managed := make([]model.Record, 0, len(recs))
|
||||
for _, rc := range recs {
|
||||
if rc.Type.Managed() {
|
||||
managed = append(managed, rc)
|
||||
}
|
||||
}
|
||||
doc := dto.FromModel(managed)
|
||||
tmpl, err := a.Store.CreateTemplate(r.Context(), pid, dom.ZoneName+" snapshot", doc)
|
||||
if err != nil {
|
||||
log.Printf("api: template-from-zone: create template failed: %v", err)
|
||||
writeErr(w, http.StatusInternalServerError, "internal error")
|
||||
return
|
||||
}
|
||||
if _, err := a.Store.SetDomainTemplate(r.Context(), did, pid, &tmpl.ID); err != nil {
|
||||
log.Printf("api: template-from-zone: attach template failed: %v", err)
|
||||
writeErr(w, http.StatusInternalServerError, "internal error")
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusCreated, toTemplateResponse(tmpl))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user