package cabana import ( "context" "encoding/json" "strings" "testing" "git.golem15.com/golem15/summercms/modules/bouncer" "git.golem15.com/golem15/summercms/modules/pact" ) // TestRecordActionDanger checks UI-SPEC F5 without a database: the record // actions offered on a record carry pact.AdminRecordAction.Danger through // to cabana's RecordAction, in the form's declared order; an ordinary // action defaults to false and omits the key on the wire, so existing // payloads stay byte-identical; an action the principal may not run or // that does not apply is not offered at all. func TestRecordActionDanger(t *testing.T) { run := func(context.Context, pact.AdminRecordActionInput) (pact.AdminRecordActionResult, error) { return pact.AdminRecordActionResult{}, nil } cc := &CompiledController{ Form: &FormSchema{recordActions: []string{"resend", "void", "archive", "locked"}}, RecordActions: map[string]pact.AdminRecordAction{ "void": {Name: "void", Label: "Void invoice", Confirm: "Void this invoice?", Danger: true, Run: run}, "resend": {Name: "resend", Label: "Send again", Run: run}, "archive": {Name: "archive", Label: "Archive", Danger: true, Run: run, Applies: func(context.Context, any) (bool, error) { return false, nil }}, "locked": {Name: "locked", Label: "Locked", Permissions: []string{"acme.payments.void"}, Run: run}, }, } editor := &bouncer.Principal{ID: 2, Backend: true, PermissionGrants: map[string]bool{"acme.payments.access": true}} actions, err := (CRUDService{}).offeredRecordActions(bouncer.WithUser(context.Background(), editor), cc, struct{}{}) if err != nil { t.Fatal(err) } if len(actions) != 2 { t.Fatalf("actions = %+v, want resend and void (archive does not apply, locked needs a permission)", actions) } if actions[0].Name != "resend" || actions[0].Danger || actions[1].Name != "void" || !actions[1].Danger { t.Fatalf("actions = %+v", actions) } if actions[1].Label != "Void invoice" || actions[1].Confirm != "Void this invoice?" { t.Fatalf("void = %+v", actions[1]) } resend, err := json.Marshal(actions[0]) if err != nil { t.Fatal(err) } void, err := json.Marshal(actions[1]) if err != nil { t.Fatal(err) } if strings.Contains(string(resend), "danger") { t.Fatalf("an ordinary action carries the danger key: %s", resend) } if !strings.Contains(string(void), `"danger":true`) { t.Fatalf("the danger action lacks danger:true: %s", void) } super := &bouncer.Principal{ID: 1, Backend: true, IsSuperuser: true} actions, err = (CRUDService{}).offeredRecordActions(bouncer.WithUser(context.Background(), super), cc, struct{}{}) if err != nil { t.Fatal(err) } if len(actions) != 3 || actions[2].Name != "locked" || actions[2].Danger { t.Fatalf("superuser actions = %+v", actions) } // The zero value of the pact field is false: actions written before // Phase 18 keep the default confirm variant. if (pact.AdminRecordAction{Name: "legacy"}).Danger { t.Fatal("Danger defaults to true") } }