Repository: internetarchive/openlibrary

Issue:
Block User & Revert Edits does not delete editions or works created by that user
<!-- What problem are we solving? What does the experience look like today? What are the symptoms? -->
Sometimes spammers create spam in the form of works and editions. The admin action to block user and revert edits should revert ALL edits by that account, including deletion of any works, editions, or lists created by that account. Currently, this is not happening; I believe it used to. 

### Evidence / Screenshot (if possible)

### Relevant url?
<!-- `https://openlibrary.org/...` -->
https://openlibrary.org/admin/people/quickbookshelp8269

### Steps to Reproduce
<!-- What steps caused you to find the bug? -->
1. Go to ...a spammer account admin page
2. Do ...click Block and revert all edits

<!-- What actually happened after these steps? What did you expect to happen? -->
* Actual: account blocked, but edits are not reverted
* Expected: all edits should be reverted, anything created under the account should be deleted

### Details

- **Logged in (Y/N)?**
- **Browser type/version?**
- **Operating system?**
- **Environment (prod/dev/local)?** prod
<!-- If not sure, put prod -->

### Proposal & Constraints
<!-- What is the proposed solution / implementation? Is there a precedent of this approach succeeding elsewhere? -->

### Related files
<!-- Files related to this issue; this is super useful for new contributors who might want to help! If you're not sure, leave this blank; a maintainer will add them. -->

### Stakeholders
<!-- @ tag stakeholders of this bug -->
@mekarpeles 


Discussion:
This solution may be related / helpful as reference:
https://github.com/internetarchive/openlibrary/pull/6771
@jimchamp -- this may be related to #563

Resolving patch:
diff --git a/openlibrary/plugins/admin/code.py b/openlibrary/plugins/admin/code.py
--- a/openlibrary/plugins/admin/code.py
+++ b/openlibrary/plugins/admin/code.py
@@ -311,16 +311,28 @@ def POST_block_account_and_revert(self, account):
         i = 0
         edits = 0
         stop = False
+        keys_to_delete = set()
         while not stop:
             changes = account.get_recentchanges(limit=100, offset=100 * i)
+            added_records: list[list[dict]] = [
+                c.changes for c in changes if c.kind == 'add-book'
+            ]
+            flattened_records: list[dict] = sum(added_records, [])
+            keys_to_delete |= {r['key'] for r in flattened_records}
             changeset_ids = [c.id for c in changes]
             _, len_docs = ipaddress_view().revert(changeset_ids, "Reverted Spam")
             edits += len_docs
             i += 1
             if len(changes) < 100:
                 stop = True
+
+        delete_payload = [
+            {'key': key, 'type': {'key': '/type/delete'}} for key in keys_to_delete
+        ]
+        web.ctx.site.save_many(delete_payload, 'Delete spam')
         add_flash_message(
-            "info", f"Blocked the account and reverted all {edits} edits."
+            "info",
+            f"Blocked the account and reverted all {edits} edits. {len(delete_payload)} records deleted.",
         )
         raise web.seeother(web.ctx.path)
 


Test patch: