Repository: internetarchive/openlibrary

Issue:
The export list option does not include the works, only the editions
The export list option doesn't work when the list include works only. If the list include works and editions, it exports editions only. If the list only includes works, it does not export anything.

### Evidence
This [list](https://openlibrary.org/people/dcapillae/lists/OL202672L) includes works only.  Try to export it in any format. The results are null.

### Steps to Reproduce
1. Go to any list containing only works (OL...W) or works and editions (OL...W and OL...M)
2. Try to export the list and check the results: if the list contains only works (OL...W), it exports nothing; if it contains works and editions, it exports the editions (OL...M), but does not include the works (OL...W). 

* Actual: It is not possible to export lists that include works in a satisfactory way. The results are partial (only editions) or null.
* Expected: When exporting a list in any format (json, html, or bib), the results should include all seeds, including both works (OL...W) and editions (OL...M).

### Details

- **Logged in (Y/N)?** Y 
- **Browser type/version?** Mozilla Firefox  94.0
- **Operating system?** Ubuntu 20.04.3 LTS
- **Environment (prod/dev/local)?** prod






Discussion:
Hi, I will take a shot at solving this!
Related to this issue, maybe it could also consider solving the export of lists that include authors. Open library offers the possibility to add authors to lists, but the export option does not work correctly with this type of items. ([example](https://openlibrary.org/people/dcapillae/lists/OL202608L): this list only includes authors, but the export options offer a strange mix of results.)

Resolving patch:
diff --git a/openlibrary/core/lists/model.py b/openlibrary/core/lists/model.py
--- a/openlibrary/core/lists/model.py
+++ b/openlibrary/core/lists/model.py
@@ -18,7 +18,6 @@
 import six
 from six.moves import urllib
 
-
 logger = logging.getLogger("openlibrary.lists.model")
 
 # this will be imported on demand to avoid circular dependency
@@ -162,6 +161,37 @@ def _get_edition_keys_from_solr(self, query_terms):
             for k in doc['edition_key']:
                 yield "/books/" + k
 
+    def get_export_list(self)  -> dict[str, list]:
+        """Returns all the editions, works and authors of this list in arbitrary order.
+
+        The return value is an iterator over all the entries. Each entry is a dictionary.
+
+        This works even for lists with too many seeds as it doesn't try to
+        return entries in the order of last-modified.
+        """
+
+        # Separate by type each of the keys
+        edition_keys = {
+            seed.key for seed in self.seeds if seed and seed.type.key == '/type/edition'
+        }
+        work_keys = {
+            "/works/%s" % seed.key.split("/")[-1] for seed in self.seeds if seed and seed.type.key == '/type/work'
+        }
+        author_keys = {
+            "/authors/%s" % seed.key.split("/")[-1] for seed in self.seeds if seed and seed.type.key == '/type/author'
+        }
+
+        # Create the return dictionary
+        export_list = {}
+        if edition_keys:
+            export_list["editions"] = [doc.dict() for doc in web.ctx.site.get_many(list(edition_keys))]
+        if work_keys:
+            export_list["works"] = [doc.dict() for doc in web.ctx.site.get_many(list(work_keys))]
+        if author_keys:
+            export_list["authors"] = [doc.dict() for doc in web.ctx.site.get_many(list(author_keys))]
+
+        return export_list
+
     def _preload(self, keys):
         keys = list(set(keys))
         return self._site.get_many(keys)
diff --git a/openlibrary/plugins/openlibrary/lists.py b/openlibrary/plugins/openlibrary/lists.py
--- a/openlibrary/plugins/openlibrary/lists.py
+++ b/openlibrary/plugins/openlibrary/lists.py
@@ -451,24 +451,65 @@ def GET(self, key):
         format = web.input(format="html").format
 
         if format == "html":
-            html = render_template("lists/export_as_html", lst, self.get_editions(lst))
+            data = self.get_exports(lst)
+            html = render_template("lists/export_as_html", lst, data["editions"], data["works"], data["authors"])
             return delegate.RawText(html)
         elif format == "bibtex":
+            data = self.get_exports(lst)
             html = render_template(
-                "lists/export_as_bibtex", lst, self.get_editions(lst)
+                "lists/export_as_bibtex", lst, data["editions"], data["works"], data["authors"]
             )
             return delegate.RawText(html)
         elif format == "json":
-            data = {"editions": self.get_editions(lst, raw=True)}
+            data = self.get_exports(lst, raw=True)
             web.header("Content-Type", "application/json")
             return delegate.RawText(json.dumps(data))
         elif format == "yaml":
-            data = {"editions": self.get_editions(lst, raw=True)}
+            data = self.get_exports(lst, raw=True)
             web.header("Content-Type", "application/yaml")
             return delegate.RawText(formats.dump_yaml(data))
         else:
             raise web.notfound()
 
+    def get_exports(self, lst: list, raw: bool = False) -> dict[str, list]:
+        export_data = lst.get_export_list()
+        if "editions" in export_data:
+            export_data["editions"] = sorted(
+                export_data["editions"],
+                key=lambda doc: doc['last_modified']['value'],
+                reverse=True,
+            )
+        if "works" in export_data:
+            export_data["works"] = sorted(
+                export_data["works"],
+                key=lambda doc: doc['last_modified']['value'],
+                reverse=True,
+            )
+        if "authors" in export_data:
+            export_data["authors"] = sorted(
+                export_data["authors"],
+                key=lambda doc: doc['last_modified']['value'],
+                reverse=True,
+            )
+
+        if not raw:
+            if "editions" in export_data:
+                export_data["editions"] = [self.make_doc(e) for e in export_data["editions"]]
+                lst.preload_authors(export_data["editions"])
+            else:
+                export_data["editions"] = []
+            if "works" in export_data:
+                export_data["works"] = [self.make_doc(e) for e in export_data["works"]]
+                lst.preload_authors(export_data["works"])
+            else:
+                export_data["works"] = []
+            if "authors" in export_data:
+                export_data["authors"] = [self.make_doc(e) for e in export_data["authors"]]
+                lst.preload_authors(export_data["authors"])
+            else:
+                export_data["authors"] = []
+        return export_data
+
     def get_editions(self, lst, raw=False):
         editions = sorted(
             lst.get_all_editions(),


Test patch: