package server import ( "net/http" "strings" "jarl/internal/auth" "jarl/internal/engine" "jarl/internal/model" ) // zoneCompare: GET /zones/{zone}/compare lines up a zone's records across // the views that have it (docs/views.md#linked-zones). ?views=a,b picks the // views (default: every view with a primary zone of that name), ?all=1 // includes the names and types that are the same everywhere. func (s *Server) zoneCompare(w http.ResponseWriter, r *http.Request, p *auth.Principal) error { st, err := s.state(r) if err != nil { return err } z, err := s.zoneByPath(r, st, p) if err != nil { // A name in several views is what there is to compare. ref := r.PathValue("zone") if ref == "root" { ref = "." } name, perr := engine.ParseZoneName(ref) if zs := st.ZonesNamed(name); perr != nil || len(zs) < 2 { return err } else { z = zs[0] } } var want []string for _, v := range strings.Split(r.URL.Query().Get("views"), ",") { if v = strings.TrimSpace(v); v != "" { want = append(want, v) } } var zones []*model.Zone for _, o := range st.ZonesNamed(z.Name) { vn := st.ViewName(o) if o.Type != model.ZonePrimary || !p.CanSeeZone(o.Name, vn) || !p.Can(auth.Action{Resource: auth.ResRecords, Zone: o.Name, View: vn}) { continue } if len(want) > 0 && !containsFold(want, vn) { continue } zones = append(zones, o) } st.SortByView(zones) if len(zones) < 2 { return badRequest("zone %s is in only one view (that you may read): there is nothing to compare", engine.Display(z.Name)) } rows := engine.CompareZones(st, zones) all := queryBool(r, "all") out := struct { Zone string `json:"zone"` Views []string `json:"views"` Linked bool `json:"linked"` // all of them in one link Same int `json:"same"` // names and types the same everywhere Rows []engine.CompareRow `json:"rows"` }{Zone: engine.Display(z.Name), Rows: []engine.CompareRow{}, Linked: true} for _, o := range zones { out.Views = append(out.Views, st.ViewName(o)) out.Linked = out.Linked && o.LinkGroup != 0 && o.LinkGroup == zones[0].LinkGroup } for _, row := range rows { if row.Same { out.Same++ if !all { continue } } out.Rows = append(out.Rows, row) } writeJSON(w, http.StatusOK, out) return nil } func containsFold(list []string, s string) bool { for _, x := range list { if strings.EqualFold(x, s) { return true } } return false }