Repository: internetarchive/openlibrary

Issue:
Add to staff picks fails if any dark item associated with Work ID
<!-- What problem are we solving? What does the experience look like today? What are the symptoms? -->
<class 'internetarchive.exceptions.ItemLocateError'> at /admin/staffpicks
Item cannot be located because it is dark or does not exist.

### Evidence / Screenshot (if possible)
<img width="1141" alt="Screenshot 2023-10-28 at 16 19 59" src="https://github.com/internetarchive/openlibrary/assets/17739465/6927a5e6-81ad-425f-9f7d-34f62466aeaa">

### Relevant url?
<!-- `https://openlibrary.org/...` -->
https://openlibrary.org/admin/staffpicks?debug=true

### Steps to Reproduce
<!-- What steps caused you to find the bug? -->
1. Go to ...https://openlibrary.org/admin/staffpicks?debug=true
2. Do ...add OL1807144W

<!-- What actually happened after these steps? What did you expect to happen? -->
* Actual: Error noted above. 
* Expected: Editions should be added to staff picks.

### 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:
@jimchamp @mekarpeles 
Can I be assigned this issue so I can attempt it?
I also need to know if 'Editions should be added to staff picks' is the correct fix.
@seabelis are you still experiencing this issue?  I was unable to reproduce this with OL1807144W (which is now a staff pick).  I also tried with a recently published book and didn't see an error page.

@ClementineAccount if this bug is still occurring, I'll assign you and help to find a solution.
It's hard to say as I've been removing the dark item links and I only add to staff picks every now and then. I will see if I can find an appropriate test work.
Found an example. https://openlibrary.org/works/OL2950942W/The_Demon-Haunted_World 
Thanks @seabelis!  What happens when the button works?  From what I can gather from the code, it looks like some JSON response is displayed.  That seems inconvenient if it's true...

@ClementineAccount, are you still interested in working on this?  I think that wrapping [this call](https://github.com/internetarchive/openlibrary/blob/e7404e7f15df39fdc11a0e45f86be3988540f102/openlibrary/plugins/admin/code.py#L205-L207) in a `try` block would work.  If there's an exception, return some JSON that contains an error message.
> Thanks @seabelis! What happens when the button works? From what I can gather from the code, it looks like some JSON response is displayed. That seems inconvenient if it's true...
> 
> @ClementineAccount, are you still interested in working on this? I think that wrapping [this call](https://github.com/internetarchive/openlibrary/blob/e7404e7f15df39fdc11a0e45f86be3988540f102/openlibrary/plugins/admin/code.py#L205-L207) in a `try` block would work. If there's an exception, return some JSON that contains an error message.

Yes I am interested. Once assigned I can start attempting the suggestion of wrapping the call and trying it out.
Thanks @ClementineAccount!
Yes, when there's an eligible edition a json success message is returned. If no eligible edition exists (for example, all already have the tag) a json failure message is returned. When there's a dark item no json is returned. I believe the code just doesn't execute at all when it hits a dark item.

If possible, it should just skip over the dark item and still find the eligible items.
> If possible, it should just skip over the dark item and still find the eligible items.

This is correct ----  @ClementineAccount, instead of returning immediately if an error is encountered, continue processing all of the `ocaids`.  Sorry for the bad instructions earlier...

@seabelis, would it be useful if the failed `ocaids` were returned after the button was pressed, or maybe some kind of `n/m items added to staff picks` message?
@jimchamp I have started work on this properly today now that the holiday period is over. Will let you know if I encounter blocks or have questions.
> @jimchamp I have started work on this properly today now that the holiday period is over. Will let you know if I encounter blocks or have questions.

Just realized that something happened on that day and I wasn't able to start it. I apologize for that. I will now reply to this post again once I have started working on it and reproducing the bug.
Assignees removed automatically after 14 days.
@jimchamp It would be helpful if the edition ID is returned.
Alright, that should be easy enough.  When we are iterating through the `ocaid`s, we can store any `ocaid` that failed in a list.  Once the `ocaid`s have been processed, we can include the list in the JSON response.

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
@@ -10,6 +10,8 @@
 import logging
 import json
 
+from internetarchive.exceptions import ItemLocateError
+
 from infogami import config
 from infogami.utils import delegate
 from infogami.utils.view import render, public
@@ -202,9 +204,14 @@ def POST(self):
             ocaids = [edition.ocaid for edition in editions if edition.ocaid]
             results[work_id] = {}
             for ocaid in ocaids:
-                results[work_id][ocaid] = create_ol_subjects_for_ocaid(
-                    ocaid, subjects=subjects
-                )
+                try:
+                    results[work_id][ocaid] = create_ol_subjects_for_ocaid(
+                        ocaid, subjects=subjects
+                    )
+                except ItemLocateError as err:
+                    results[work_id][
+                        ocaid
+                    ] = f'Failed to add to staff picks. Error message: {err}'
 
         return delegate.RawText(json.dumps(results), content_type="application/json")
 


Test patch: