Repository: internetarchive/openlibrary

Issue:
Work deletion api cannot delete works with >1000 editions
<!-- What problem are we solving? What does the experience look like today? What are the symptoms? -->

### Evidence / Screenshot (if possible)

### Relevant url?
<!-- `https://openlibrary.org/...` -->
https://openlibrary.org/works/OL24314717W/College_Ruled_Line_Paper
https://openlibrary.org/works/OL25960344W/Cat_Notebook

### Steps to Reproduce
<!-- What steps caused you to find the bug? -->
1. On an account with api/bot perms, run eg `await fetch('https://openlibrary.org/works/OL24314717W/College_Ruled_Line_Paper/delete.json', {method: 'POST'})`

<!-- What actually happened after these steps? What did you expect to happen? -->
* Actual: Error thrown
* Expected: Works deleted

### Details

- **Logged in (Y/N)?** Y
- **Browser type/version?**
- **Operating system?** Linux
- **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 -->
@BharatKalluri 


Discussion:
Proposal:

Update this code:

https://github.com/internetarchive/openlibrary/blob/9ada5d0ab36fe903833e139010df4dbfa519324f/openlibrary/plugins/openlibrary/api.py#L594-L597

1. if `bulk=true` is in the url, it will include `offset` in the things query, and page through the results until all editions are exhausted.
2. Note it will still error by default since in general we likely do not want that. Ideally `bulk=true` would only work via the UI (#7973)

Resolving patch:
diff --git a/openlibrary/plugins/openlibrary/api.py b/openlibrary/plugins/openlibrary/api.py
--- a/openlibrary/plugins/openlibrary/api.py
+++ b/openlibrary/plugins/openlibrary/api.py
@@ -591,21 +591,38 @@ class work_delete(delegate.page):
     path = r"/works/(OL\d+W)/[^/]+/delete"
 
     def get_editions_of_work(self, work: Work) -> list[dict]:
+        i = web.input(bulk=False)
         limit = 1_000  # This is the max limit of the things function
-        keys: list = web.ctx.site.things(
-            {"type": "/type/edition", "works": work.key, "limit": limit}
-        )
-        if len(keys) == limit:
-            raise web.HTTPError(
-                '400 Bad Request',
-                data=json.dumps(
-                    {
-                        'error': f'API can only delete {limit} editions per work',
-                    }
-                ),
-                headers={"Content-Type": "application/json"},
+        all_keys: list = []
+        offset = 0
+
+        while True:
+            keys: list = web.ctx.site.things(
+                {
+                    "type": "/type/edition",
+                    "works": work.key,
+                    "limit": limit,
+                    "offset": offset,
+                }
             )
-        return web.ctx.site.get_many(keys, raw=True)
+            all_keys.extend(keys)
+            if len(keys) == limit:
+                if not i.bulk:
+                    raise web.HTTPError(
+                        '400 Bad Request',
+                        data=json.dumps(
+                            {
+                                'error': f'API can only delete {limit} editions per work.',
+                            }
+                        ),
+                        headers={"Content-Type": "application/json"},
+                    )
+                else:
+                    offset += limit
+            else:
+                break
+
+        return web.ctx.site.get_many(all_keys, raw=True)
 
     def POST(self, work_id: str):
         if not can_write():


Test patch: