Skip to content
quarry Artifact [89af7c3d16]
Login

Artifact [89af7c3d16]

Artifact 89af7c3d16ca1088c048de9c3780daba2453bc2a5e38a7c7e31a2e0f3bc9a9a1:


package web

import (
	"net/http"
	"net/url"
	"strings"

	"craftdesign.group/quarry/internal/ops"
)

// fossilMirrorPanel is the Mirror to Fossil section as the page draws
// it. The password is not on it, and the form never pre-fills one.
type fossilMirrorPanel struct {
	On        bool   `json:"on"`
	Remote    string `json:"remote"`
	User      string `json:"user"`
	Pushed    string `json:"pushed"`
	PushedAt  string `json:"pushed_at"`
	LastErr   string `json:"error"`
	LastErrAt string `json:"error_at"`
	Paused    string `json:"paused"`
	// Err is this section's own refusal, back from its POST in the
	// flash, never from the address.
	Err string `json:"-"`
}

// fossilMirrorPanelFor reads the mirror through `repo.fossilmirror.get`,
// the op the API serves. nil, so no section, when the forge keeps no
// mirrors. The form is always filled from what is saved: what a refused
// post typed is not carried back, because it would have to travel in the
// address.
func fossilMirrorPanelFor(r *ops.Registry, req *http.Request, repo string) *fossilMirrorPanel {
	out, err := invoke(req.Context(), r, "repo.fossilmirror.get", url.Values{"repo": {repo}})
	if err != nil {
		return nil
	}
	var p fossilMirrorPanel
	remarshal(out, &p)
	return &p
}

// fossilMirrorRefusalFlash is the flash that carries a refused post's
// words back to the settings page, marked so it is told from a saved
// panel's name.
const fossilMirrorRefusalFlash = "fossil-mirror-refused:"

// flashFossilMirrorRefusal sets the flash for a refusal. The words are
// the op's, with any user name or password the remote carried removed,
// so a secret typed into the address is echoed nowhere.
func flashFossilMirrorRefusal(w http.ResponseWriter, req *http.Request, err error, remote string) {
	words := opRefusal(err)
	if u, perr := url.Parse(remote); perr == nil && u.User != nil {
		for _, secret := range []string{u.User.Username(), passwordOf(u)} {
			if secret != "" {
				words = strings.ReplaceAll(words, secret, "")
			}
		}
	}
	setFlash(w, req, fossilMirrorRefusalFlash+url.QueryEscape(words))
}

func passwordOf(u *url.URL) string {
	p, _ := u.User.Password()
	return p
}

// takeFossilMirrorRefusal splits a refusal's words out of the flash the
// settings page just took: the words, and the flash left for the other
// panels (empty when it was the refusal).
func takeFossilMirrorRefusal(flash string) (words, rest string) {
	enc, ok := strings.CutPrefix(flash, fossilMirrorRefusalFlash)
	if !ok {
		return "", flash
	}
	words, err := url.QueryUnescape(enc)
	if err != nil {
		return "", ""
	}
	return words, ""
}