feat: sync durable moderation and appeals
This commit is contained in:
parent
e1a95c7318
commit
9f467f4be7
140 changed files with 13730 additions and 316 deletions
|
|
@ -57,6 +57,147 @@ type fakeUniqueGifts struct {
|
|||
calls int
|
||||
}
|
||||
|
||||
type fakeModerationAppeals struct {
|
||||
link domain.ModerationAppealLink
|
||||
found bool
|
||||
resolveErr error
|
||||
appeal domain.ModerationAppeal
|
||||
submitErr error
|
||||
submitCalls int
|
||||
submitText string
|
||||
}
|
||||
|
||||
func (f *fakeModerationAppeals) ResolveAppealLink(_ context.Context, _ string, _ time.Time) (domain.ModerationAppealLink, bool, error) {
|
||||
return f.link, f.found, f.resolveErr
|
||||
}
|
||||
|
||||
func (f *fakeModerationAppeals) Appeal(_ context.Context, appealID int64) (domain.ModerationAppeal, bool, error) {
|
||||
if f.appeal.ID != appealID {
|
||||
return domain.ModerationAppeal{}, false, nil
|
||||
}
|
||||
return f.appeal, true, nil
|
||||
}
|
||||
|
||||
func (f *fakeModerationAppeals) SubmitAppealLink(_ context.Context, _ string, text string, _ time.Time) (domain.ModerationAppeal, bool, error) {
|
||||
f.submitCalls++
|
||||
f.submitText = text
|
||||
return f.appeal, true, f.submitErr
|
||||
}
|
||||
|
||||
func TestHandlerModerationAppealGetAndIdempotentPost(t *testing.T) {
|
||||
now := time.Now().UTC()
|
||||
resolver := &fakeModerationAppeals{
|
||||
found: true,
|
||||
link: domain.ModerationAppealLink{
|
||||
ID: 1, CaseID: 2, AppellantUserID: 3,
|
||||
TokenHash: [32]byte{1}, ExpiresAt: now.Add(time.Hour),
|
||||
CreatedAt: now,
|
||||
},
|
||||
appeal: domain.ModerationAppeal{
|
||||
ID: 4, CaseID: 2, Status: domain.ModerationAppealPending,
|
||||
},
|
||||
}
|
||||
handler, err := NewHandler(Config{
|
||||
StickerSets: fakeResolver{},
|
||||
ModerationAppeals: resolver,
|
||||
PublicBaseURL: "https://telesrv.example",
|
||||
AppName: "Telesrv",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
get := httptest.NewRecorder()
|
||||
handler.ServeHTTP(get, httptest.NewRequest(
|
||||
http.MethodGet, "/appeal/valid-token", nil,
|
||||
))
|
||||
if get.Code != http.StatusOK ||
|
||||
!strings.Contains(get.Body.String(), "Case #2") ||
|
||||
!strings.Contains(get.Body.String(), "Do not include passwords") {
|
||||
t.Fatalf("GET status=%d body=%s", get.Code, get.Body.String())
|
||||
}
|
||||
if got := get.Header().Get("Cache-Control"); got != "no-store" {
|
||||
t.Fatalf("Cache-Control=%q", got)
|
||||
}
|
||||
if got := get.Header().Get("Referrer-Policy"); got != "no-referrer" {
|
||||
t.Fatalf("Referrer-Policy=%q", got)
|
||||
}
|
||||
|
||||
post := httptest.NewRecorder()
|
||||
postRequest := httptest.NewRequest(
|
||||
http.MethodPost, "/appeal/valid-token",
|
||||
strings.NewReader("appeal_text=+Please+review+this.+"),
|
||||
)
|
||||
postRequest.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
handler.ServeHTTP(post, postRequest)
|
||||
if post.Code != http.StatusOK ||
|
||||
!strings.Contains(post.Body.String(), "appeal #4") ||
|
||||
resolver.submitCalls != 1 || resolver.submitText != "Please review this." {
|
||||
t.Fatalf("POST status=%d calls=%d text=%q body=%s",
|
||||
post.Code, resolver.submitCalls, resolver.submitText, post.Body.String())
|
||||
}
|
||||
|
||||
resolver.link.AppealID = 4
|
||||
retry := httptest.NewRecorder()
|
||||
retryRequest := httptest.NewRequest(
|
||||
http.MethodPost, "/appeal/valid-token",
|
||||
strings.NewReader("appeal_text=must+not+resubmit"),
|
||||
)
|
||||
retryRequest.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
handler.ServeHTTP(retry, retryRequest)
|
||||
if retry.Code != http.StatusOK || resolver.submitCalls != 1 ||
|
||||
!strings.Contains(retry.Body.String(), "appeal #4") {
|
||||
t.Fatalf("retry status=%d calls=%d body=%s",
|
||||
retry.Code, resolver.submitCalls, retry.Body.String())
|
||||
}
|
||||
|
||||
resolver.appeal.Status = domain.ModerationAppealGranted
|
||||
granted := httptest.NewRecorder()
|
||||
handler.ServeHTTP(granted, httptest.NewRequest(
|
||||
http.MethodGet, "/appeal/valid-token", nil,
|
||||
))
|
||||
if granted.Code != http.StatusOK ||
|
||||
!strings.Contains(granted.Body.String(), "was granted") {
|
||||
t.Fatalf("granted status=%d body=%s", granted.Code, granted.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandlerModerationAppealFailsClosed(t *testing.T) {
|
||||
resolver := &fakeModerationAppeals{}
|
||||
handler, err := NewHandler(Config{
|
||||
StickerSets: fakeResolver{}, ModerationAppeals: resolver,
|
||||
PublicBaseURL: "https://telesrv.example",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
missing := httptest.NewRecorder()
|
||||
handler.ServeHTTP(missing, httptest.NewRequest(
|
||||
http.MethodGet, "/appeal/invalid", nil,
|
||||
))
|
||||
if missing.Code != http.StatusNotFound {
|
||||
t.Fatalf("missing status=%d", missing.Code)
|
||||
}
|
||||
|
||||
now := time.Now().UTC()
|
||||
resolver.found = true
|
||||
resolver.link = domain.ModerationAppealLink{
|
||||
ID: 1, CaseID: 2, AppellantUserID: 3,
|
||||
TokenHash: [32]byte{1}, ExpiresAt: now.Add(time.Hour), CreatedAt: now,
|
||||
}
|
||||
resolver.submitErr = domain.ErrModerationCaseConflict
|
||||
conflict := httptest.NewRecorder()
|
||||
conflictRequest := httptest.NewRequest(
|
||||
http.MethodPost, "/appeal/valid",
|
||||
strings.NewReader("appeal_text=still+finalizing"),
|
||||
)
|
||||
conflictRequest.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
handler.ServeHTTP(conflict, conflictRequest)
|
||||
if conflict.Code != http.StatusConflict ||
|
||||
!strings.Contains(conflict.Body.String(), "still being finalized") {
|
||||
t.Fatalf("conflict status=%d body=%s", conflict.Code, conflict.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func (f *fakeUniqueGifts) UniqueBySlug(_ context.Context, slug string) (domain.UniqueStarGift, bool, error) {
|
||||
f.calls++
|
||||
if f.err != nil {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue