Skip to content
quarry Artifact [5d9686253c]
Login

Artifact [5d9686253c]

Artifact 5d9686253c2dd80c3d2419bd31a97e46a93cad9dca4f166d494a61fb9de89171:


package web

import (
	"context"
	"fmt"
	"net/http"
	"net/http/httptest"
	"net/url"
	"strings"
	"testing"

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

// An edit the channel refuses is answered in the channel (#378): back to
// the page it was made on with the refusal as a notice, never a bare
// 403 page that takes the chat away and the typed edit with it. The
// page it goes back to is a local path or the channel itself.
func TestARefusedChatEditStaysInTheChannel(t *testing.T) {
	type editIn struct {
		Repo string `json:"repo"`
		Seq  uint64 `json:"seq"`
		Text string `json:"text"`
	}
	type editOut struct {
		OK bool `json:"ok"`
	}
	r := ops.NewRegistry()
	if err := ops.Register(r, ops.Op[editIn, editOut]{
		Name: "chat.edit", Caps: "C", Doc: "test stub", Kind: ops.Command, Auth: ops.Token,
		Route: "POST /api/v1/r/{repo}/chat/{seq}/edit",
		Run: func(context.Context, editIn) (editOut, error) {
			return editOut{}, fmt.Errorf("a message takes edits for five minutes after it is sent, and this one is older: %w", ops.ErrForbidden)
		},
	}); err != nil {
		t.Fatal(err)
	}
	verify := Verify(func(repo, user, pass string, need ops.Auth) api.Decision { return api.Allowed })
	h := HandlerWith(r, nil, nil, []Option{WithSessions(fakeSessions{user: "dan", roles: map[string]ops.Auth{"alpha": ops.Admin}})}, verify)
	srv := httptest.NewServer(h)
	t.Cleanup(srv.Close)
	client := &http.Client{CheckRedirect: func(*http.Request, []*http.Request) error { return http.ErrUseLastResponse }}
	edit := func(back string) *http.Response {
		req, _ := http.NewRequest("POST", srv.URL+"/r/alpha/chat/7/edit",
			strings.NewReader(url.Values{"text": {"changed"}, "back": {back}}.Encode()))
		req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
		req.AddCookie(&http.Cookie{Name: sessionCookie, Value: "good"})
		resp, err := client.Do(req)
		if err != nil {
			t.Fatal(err)
		}
		resp.Body.Close()
		return resp
	}
	resp := edit("/r/crew/alpha/chat")
	if resp.StatusCode != http.StatusSeeOther || resp.Header.Get("Location") != "/r/crew/alpha/chat" {
		t.Fatalf("FAIL: a refused edit answered %d to %q, want 303 back to the page", resp.StatusCode, resp.Header.Get("Location"))
	}
	var flash string
	for _, c := range resp.Cookies() {
		if c.Name == flashCookie {
			flash = c.Value
		}
	}
	if !strings.Contains(flash, "five minutes") || strings.Contains(flash, "forbidden") {
		t.Errorf("FAIL: the refusal carried back is %q", flash)
	}
	if resp := edit("//elsewhere.example/x"); resp.Header.Get("Location") != "/r/alpha/chat" {
		t.Errorf("FAIL: an off-site back went to %q", resp.Header.Get("Location"))
	}
	t.Log("ok: a refused edit returns to the channel with its reason")
}