implement DeleteUser soft mode to allow mapping for blocked users #341
This commit is contained in:
@@ -28,7 +28,7 @@ type admin struct {
|
||||
|
||||
type adminStore interface {
|
||||
Delete(locator store.Locator, commentID string, mode store.DeleteMode) error
|
||||
DeleteUser(siteID string, userID string) error
|
||||
DeleteUser(siteID string, userID string, mode store.DeleteMode) error
|
||||
User(siteID, userID string, limit, skip int, user store.User) ([]store.Comment, error)
|
||||
IsBlocked(siteID string, userID string) bool
|
||||
SetBlock(siteID string, userID string, status bool, ttl time.Duration) error
|
||||
@@ -64,7 +64,7 @@ func (a *admin) deleteUserCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
siteID := r.URL.Query().Get("site")
|
||||
log.Printf("[INFO] delete all user comments for %s, site %s", userID, siteID)
|
||||
|
||||
if err := a.dataService.DeleteUser(siteID, userID); err != nil {
|
||||
if err := a.dataService.DeleteUser(siteID, userID, store.HardDelete); err != nil {
|
||||
rest.SendErrorJSON(w, r, http.StatusInternalServerError, err, "can't delete user", rest.ErrInternal)
|
||||
return
|
||||
}
|
||||
@@ -109,7 +109,7 @@ func (a *admin) deleteMeRequestCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if err = a.dataService.DeleteUser(claims.Audience, claims.User.ID); err != nil {
|
||||
if err = a.dataService.DeleteUser(claims.Audience, claims.User.ID, store.HardDelete); err != nil {
|
||||
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't delete user", rest.ErrNoAccess)
|
||||
return
|
||||
}
|
||||
@@ -145,9 +145,9 @@ func (a *admin) setBlockCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// delete comments for blocked user
|
||||
// delete comments for blocked user.
|
||||
if blockStatus {
|
||||
if err := a.dataService.DeleteUser(siteID, userID); err != nil {
|
||||
if err := a.dataService.DeleteUser(siteID, userID, store.SoftDelete); err != nil {
|
||||
log.Printf("[WARN] can't delete comments for blocked user %s on site %s, %v", userID, siteID, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -353,13 +353,23 @@ func TestAdmin_Block(t *testing.T) {
|
||||
|
||||
assert.False(t, srv.adminRest.dataService.IsBlocked("radio-t", "user1"))
|
||||
assert.False(t, srv.adminRest.dataService.IsBlocked("radio-t", "user2"))
|
||||
|
||||
}
|
||||
|
||||
func TestAdmin_BlockedList(t *testing.T) {
|
||||
ts, _, teardown := startupT(t)
|
||||
ts, srv, teardown := startupT(t)
|
||||
defer teardown()
|
||||
|
||||
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"}}
|
||||
c2 := store.Comment{Text: "test test #2", ParentID: "p1", Locator: store.Locator{SiteID: "radio-t",
|
||||
URL: "https://radio-t.com/blah"}, User: store.User{Name: "user2 name", ID: "user2"}}
|
||||
|
||||
// write comments for user1 and user2
|
||||
_, err := srv.DataService.Create(c1)
|
||||
assert.Nil(t, err)
|
||||
_, err = srv.DataService.Create(c2)
|
||||
assert.Nil(t, err)
|
||||
|
||||
// block user1
|
||||
req, err := http.NewRequest(http.MethodPut,
|
||||
fmt.Sprintf("%s/api/v1/admin/user/%s?site=radio-t&block=%d", ts.URL, "user1", 1), nil)
|
||||
@@ -386,8 +396,10 @@ func TestAdmin_BlockedList(t *testing.T) {
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 2, len(users), "two users blocked")
|
||||
assert.Equal(t, "user1", users[0].ID)
|
||||
assert.Equal(t, "user1 name", users[0].Name)
|
||||
assert.Equal(t, "user2", users[1].ID)
|
||||
|
||||
assert.Equal(t, "user2 name", users[1].Name)
|
||||
t.Logf("%+v", users)
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
|
||||
req, err = http.NewRequest("GET", ts.URL+"/api/v1/admin/blocked?site=radio-t", nil)
|
||||
|
||||
@@ -378,7 +378,7 @@ func (b *BoltDB) Delete(req DeleteRequest) error {
|
||||
case req.Locator.URL != "" && req.CommentID != "":
|
||||
return b.deleteComment(bdb, req.Locator, req.CommentID, req.DeleteMode)
|
||||
case req.Locator.SiteID != "" && req.UserID != "" && req.CommentID == "":
|
||||
return b.deleteUser(bdb, req.Locator.SiteID, req.UserID)
|
||||
return b.deleteUser(bdb, req.Locator.SiteID, req.UserID, req.DeleteMode)
|
||||
case req.Locator.SiteID != "" && req.Locator.URL == "" && req.CommentID == "" && req.UserID == "":
|
||||
return b.deleteAll(bdb, req.Locator.SiteID)
|
||||
}
|
||||
@@ -673,7 +673,7 @@ func (b *BoltDB) deleteAll(bdb *bolt.DB, siteID string) error {
|
||||
|
||||
// deleteUser removes all comments for given user. Everything will be market as deleted
|
||||
// and user name and userID will be changed to "deleted". Also removes from last and from user buckets.
|
||||
func (b *BoltDB) deleteUser(bdb *bolt.DB, siteID string, userID string) error {
|
||||
func (b *BoltDB) deleteUser(bdb *bolt.DB, siteID string, userID string, mode store.DeleteMode) error {
|
||||
bdb, err := b.db(siteID)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -717,24 +717,26 @@ func (b *BoltDB) deleteUser(bdb *bolt.DB, siteID string, userID string) error {
|
||||
|
||||
// delete collected comments
|
||||
for _, ci := range comments {
|
||||
if e := b.deleteComment(bdb, ci.locator, ci.commentID, store.HardDelete); e != nil {
|
||||
if e := b.deleteComment(bdb, ci.locator, ci.commentID, mode); e != nil {
|
||||
return errors.Wrapf(err, "failed to delete comment %+v", ci)
|
||||
}
|
||||
}
|
||||
|
||||
// delete user bucket
|
||||
err = bdb.Update(func(tx *bolt.Tx) error {
|
||||
usersBkt := tx.Bucket([]byte(userBucketName))
|
||||
if usersBkt != nil {
|
||||
if e := usersBkt.DeleteBucket([]byte(userID)); e != nil {
|
||||
return errors.Wrapf(err, "failed to delete user bucket for %s", userID)
|
||||
// delete user bucket in hard mode
|
||||
if mode == store.HardDelete {
|
||||
err = bdb.Update(func(tx *bolt.Tx) error {
|
||||
usersBkt := tx.Bucket([]byte(userBucketName))
|
||||
if usersBkt != nil {
|
||||
if e := usersBkt.DeleteBucket([]byte(userID)); e != nil {
|
||||
return errors.Wrapf(err, "failed to delete user bucket for %s", userID)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "can't delete user meta")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "can't delete user meta")
|
||||
}
|
||||
}
|
||||
|
||||
if len(comments) == 0 {
|
||||
|
||||
@@ -683,12 +683,12 @@ func TestBolt_DeleteAll(t *testing.T) {
|
||||
assert.EqualError(t, err, `site "bad" not found`)
|
||||
}
|
||||
|
||||
func TestBoltAdmin_DeleteUser(t *testing.T) {
|
||||
func TestBoltAdmin_DeleteUserHard(t *testing.T) {
|
||||
|
||||
b, teardown := prep(t)
|
||||
defer teardown()
|
||||
|
||||
err := b.Delete(DeleteRequest{Locator: store.Locator{SiteID: "radio-t"}, UserID: "user1"})
|
||||
err := b.Delete(DeleteRequest{Locator: store.Locator{SiteID: "radio-t"}, UserID: "user1", DeleteMode: store.HardDelete})
|
||||
require.NoError(t, err)
|
||||
|
||||
comments, err := b.Find(FindRequest{Locator: store.Locator{SiteID: "radio-t", URL: "https://radio-t.com"}, Sort: "time"})
|
||||
@@ -712,6 +712,40 @@ func TestBoltAdmin_DeleteUser(t *testing.T) {
|
||||
assert.EqualError(t, err, `site "radio-t-bad" not found`)
|
||||
}
|
||||
|
||||
func TestBoltAdmin_DeleteUserSoft(t *testing.T) {
|
||||
|
||||
b, teardown := prep(t)
|
||||
defer teardown()
|
||||
|
||||
err := b.Delete(DeleteRequest{Locator: store.Locator{SiteID: "radio-t"}, UserID: "user1", DeleteMode: store.SoftDelete})
|
||||
require.NoError(t, err)
|
||||
|
||||
comments, err := b.Find(FindRequest{Locator: store.Locator{SiteID: "radio-t", URL: "https://radio-t.com"}, Sort: "time"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 2, len(comments), "2 comments with deleted info")
|
||||
assert.Equal(t, store.User{Name: "user name", ID: "user1", Picture: "", Admin: false, Blocked: false, IP: ""}, comments[0].User)
|
||||
assert.Equal(t, store.User{Name: "user name", ID: "user1", Picture: "", Admin: false, Blocked: false, IP: ""}, comments[1].User)
|
||||
|
||||
c, err := b.Count(FindRequest{Locator: store.Locator{SiteID: "radio-t", URL: "https://radio-t.com"}})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 0, c, "0 count")
|
||||
|
||||
comments, err = b.Find(FindRequest{Locator: store.Locator{SiteID: "radio-t"}, UserID: "user1", Limit: 5})
|
||||
assert.NoError(t, err, "no comments for user user1 in store")
|
||||
assert.Equal(t, 2, len(comments), "2 comments with deleted info")
|
||||
assert.True(t, comments[0].Deleted)
|
||||
assert.True(t, comments[1].Deleted)
|
||||
assert.Equal(t, "", comments[0].Text)
|
||||
assert.Equal(t, "", comments[1].Text)
|
||||
|
||||
comments, err = b.Find(FindRequest{Locator: store.Locator{SiteID: "radio-t"}, Sort: "time"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 0, len(comments), "nothing left")
|
||||
|
||||
err = b.Delete(DeleteRequest{Locator: store.Locator{SiteID: "radio-t-bad"}, UserID: "user1"})
|
||||
assert.EqualError(t, err, `site "radio-t-bad" not found`)
|
||||
}
|
||||
|
||||
func TestBoltDB_ref(t *testing.T) {
|
||||
b := BoltDB{}
|
||||
comment := store.Comment{
|
||||
|
||||
@@ -553,8 +553,8 @@ func (s *DataStore) Delete(locator store.Locator, commentID string, mode store.D
|
||||
}
|
||||
|
||||
// DeleteUser removes all comments from user
|
||||
func (s *DataStore) DeleteUser(siteID string, userID string) error {
|
||||
req := engine.DeleteRequest{Locator: store.Locator{SiteID: siteID}, UserID: userID, DeleteMode: store.HardDelete}
|
||||
func (s *DataStore) DeleteUser(siteID string, userID string, mode store.DeleteMode) error {
|
||||
req := engine.DeleteRequest{Locator: store.Locator{SiteID: siteID}, UserID: userID, DeleteMode: mode}
|
||||
return s.Engine.Delete(req)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user