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, ""
}