From cc9f2adadfa93aceb446f2ebe3c4b49167fcf5a1 Mon Sep 17 00:00:00 2001 From: Umputun Date: Sat, 16 Jun 2018 13:22:37 -0500 Subject: [PATCH] don't allow reset RO for aged comments #55 --- app/rest/api/admin.go | 15 ++++++++++++ app/rest/api/admin_test.go | 48 ++++++++++++++++++++++++++++++++++++-- app/rest/api/rest.go | 1 + remark.rest | 2 +- 4 files changed, 63 insertions(+), 3 deletions(-) diff --git a/app/rest/api/admin.go b/app/rest/api/admin.go index db752891..8c2c5a7f 100644 --- a/app/rest/api/admin.go +++ b/app/rest/api/admin.go @@ -2,6 +2,7 @@ package api import ( "compress/gzip" + "errors" "fmt" "io" "log" @@ -25,6 +26,7 @@ type admin struct { exporter migrator.Exporter cache cache.LoadingCache authenticator auth.Authenticator + readOnlyAge int } func (a *admin) routes(middlewares ...func(http.Handler) http.Handler) chi.Router { @@ -128,6 +130,19 @@ func (a *admin) setReadOnlyCtrl(w http.ResponseWriter, r *http.Request) { locator := store.Locator{SiteID: r.URL.Query().Get("site"), URL: r.URL.Query().Get("url")} roStatus := r.URL.Query().Get("ro") == "1" + isRoByAge := func(info store.PostInfo) bool { + return a.readOnlyAge > 0 && !info.FirstTS.IsZero() && + info.FirstTS.AddDate(0, 0, a.readOnlyAge).Before(time.Now()) + } + + // don't allow to reset ro for posts turned to ro by ReadOnlyAge + if !roStatus { + if info, e := a.dataService.Info(locator, a.readOnlyAge); e == nil && isRoByAge(info) { + rest.SendErrorJSON(w, r, http.StatusForbidden, errors.New("rejected"), "read-only due the age") + return + } + } + if err := a.dataService.SetReadOnly(locator, roStatus); err != nil { rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't set readonly status") return diff --git a/app/rest/api/admin_test.go b/app/rest/api/admin_test.go index 5a38c431..cffa1a32 100644 --- a/app/rest/api/admin_test.go +++ b/app/rest/api/admin_test.go @@ -259,8 +259,9 @@ func TestAdmin_ReadOnly(t *testing.T) { fmt.Sprintf("%s/api/v1/admin/readonly?site=radio-t&url=https://radio-t.com/blah&ro=1", ts.URL), nil) assert.Nil(t, err) req.SetBasicAuth("dev", "password") - _, err = client.Do(req) + resp, err := client.Do(req) require.Nil(t, err) + assert.Equal(t, 200, resp.StatusCode) info, err = srv.DataService.Info(store.Locator{SiteID: "radio-t", URL: "https://radio-t.com/blah"}, 0) assert.Nil(t, err) assert.True(t, info.ReadOnly) @@ -270,13 +271,56 @@ func TestAdmin_ReadOnly(t *testing.T) { fmt.Sprintf("%s/api/v1/admin/readonly?site=radio-t&url=https://radio-t.com/blah&ro=0", ts.URL), nil) assert.Nil(t, err) req.SetBasicAuth("dev", "password") - _, err = client.Do(req) + resp, err = client.Do(req) + assert.Equal(t, 200, resp.StatusCode) require.Nil(t, err) info, err = srv.DataService.Info(store.Locator{SiteID: "radio-t", URL: "https://radio-t.com/blah"}, 0) assert.Nil(t, err) assert.False(t, info.ReadOnly) } +func TestAdmin_ReadOnlyWithAge(t *testing.T) { + srv, ts := prep(t) + assert.NotNil(t, srv) + defer cleanup(ts) + + c1 := store.Comment{Text: "test test #1", Locator: store.Locator{SiteID: "radio-t", + URL: "https://radio-t.com/blah"}, User: store.User{Name: "user1 name", ID: "user1"}, + Timestamp: time.Date(2001, 1, 1, 1, 1, 1, 0, time.Local)} + _, err := srv.DataService.Create(c1) + assert.Nil(t, err) + + info, err := srv.DataService.Info(store.Locator{SiteID: "radio-t", URL: "https://radio-t.com/blah"}, 10) + assert.Nil(t, err) + assert.True(t, info.ReadOnly, "ro by age") + + client := http.Client{} + + // set post to read-only + req, err := http.NewRequest(http.MethodPut, + fmt.Sprintf("%s/api/v1/admin/readonly?site=radio-t&url=https://radio-t.com/blah&ro=1", ts.URL), nil) + assert.Nil(t, err) + req.SetBasicAuth("dev", "password") + resp, err := client.Do(req) + require.Nil(t, err) + assert.Equal(t, 200, resp.StatusCode) + info, err = srv.DataService.Info(store.Locator{SiteID: "radio-t", URL: "https://radio-t.com/blah"}, 0) + assert.Nil(t, err) + assert.True(t, info.ReadOnly) + + // reset post's read-only + req, err = http.NewRequest(http.MethodPut, + fmt.Sprintf("%s/api/v1/admin/readonly?site=radio-t&url=https://radio-t.com/blah&ro=0", ts.URL), nil) + assert.Nil(t, err) + req.SetBasicAuth("dev", "password") + resp, err = client.Do(req) + assert.Equal(t, 403, resp.StatusCode) + require.Nil(t, err) + info, err = srv.DataService.Info(store.Locator{SiteID: "radio-t", URL: "https://radio-t.com/blah"}, 0) + assert.Nil(t, err) + assert.True(t, info.ReadOnly) + +} func TestAdmin_Verify(t *testing.T) { srv, ts := prep(t) assert.NotNil(t, srv) diff --git a/app/rest/api/rest.go b/app/rest/api/rest.go index 848e2c99..6be7ceda 100644 --- a/app/rest/api/rest.go +++ b/app/rest/api/rest.go @@ -105,6 +105,7 @@ func (s *Rest) routes() chi.Router { exporter: s.Exporter, cache: s.Cache, authenticator: s.Authenticator, + readOnlyAge: s.ReadOnlyAge, } ipFn := func(ip string) string { return store.HashValue(ip, s.DataService.Secret)[:12] } // logger uses it for anonymization diff --git a/remark.rest b/remark.rest index 2efe5dc4..c6679fce 100644 --- a/remark.rest +++ b/remark.rest @@ -68,7 +68,7 @@ GET {{host}}/api/v1/id/a2ddb8d2f65008ee1a1e3af8df0f26beb042309c?site=remark&url= GET {{host}}/api/v1/comments?site={{site}}&user=github_ef0f706a79cc24b17bbbb374cd234a691d034128&limit=5 ### get comment by user id2 -GET {{host}}/api/v1/comments?site=remark&user=disqus_kpmy +GET {{host}}/api/v1/comments?site=radiot&user=github_0a4349d868946d7841424c9bdd4415629df771e6 ### get count GET {{host}}/api/v1/count?site=remark&url={{url}}