We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Switching editions changes "shelved" date
**Describe the bug**
When switching editions of a book already on your "To Read" list, the "shelved" date is changed to today's date.

**To Reproduce**
Steps to reproduce the behavior:
1. Pick any book on your "To read" list with more than one edition
2. Pick another edition and switch to this
3. Observe that the book's shelved date is now today

**Expected behavior**
This shouldn't changed the shelved date

**Instance**
https://books.theunseen.city

---

**Desktop (please complete the following information):**
    - OS: MacOS 14.1
    - Browser: Firefox
    - Version: 20.0 (64-bit)


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `bookwyrm/views/books/editions.py`
Content:
```
1 """ the good stuff! the books! """
2 from functools import reduce
3 import operator
4 
5 from django.contrib.auth.decorators import login_required
6 from django.core.paginator import Paginator
7 from django.db import transaction
8 from django.db.models import Q
9 from django.shortcuts import get_object_or_404, redirect
10 from django.template.response import TemplateResponse
11 from django.views import View
12 from django.views.decorators.http import require_POST
13 
14 from bookwyrm import forms, models
15 from bookwyrm.activitypub import ActivitypubResponse
16 from bookwyrm.settings import PAGE_LENGTH
17 from bookwyrm.views.helpers import is_api_request
18 
19 
20 # pylint: disable=no-self-use
21 class Editions(View):
22     """list of editions"""
23 
24     def get(self, request, book_id):
25         """list of editions of a book"""
26         work = get_object_or_404(models.Work, id=book_id)
27 
28         if is_api_request(request):
29             return ActivitypubResponse(work.to_edition_list(**request.GET))
30         filters = {}
31 
32         if request.GET.get("language"):
33             filters["languages__contains"] = [request.GET.get("language")]
34         if request.GET.get("format"):
35             filters["physical_format__iexact"] = request.GET.get("format")
36 
37         editions = work.editions.order_by("-edition_rank")
38         languages = set(sum(editions.values_list("languages", flat=True), []))
39 
40         editions = editions.filter(**filters)
41 
42         query = request.GET.get("q")
43         if query:
44             searchable_array_fields = ["languages", "publishers"]
45             searchable_fields = [
46                 "title",
47                 "physical_format",
48                 "isbn_10",
49                 "isbn_13",
50                 "oclc_number",
51                 "asin",
52                 "aasin",
53                 "isfdb",
54             ]
55             search_filter_entries = [
56                 {f"{f}__icontains": query} for f in searchable_fields
57             ] + [{f"{f}__iexact": query} for f in searchable_array_fields]
58             editions = editions.filter(
59                 reduce(operator.or_, (Q(**f) for f in search_filter_entries))
60             )
61 
62         paginated = Paginator(editions, PAGE_LENGTH)
63         page = paginated.get_page(request.GET.get("page"))
64         data = {
65             "editions": page,
66             "page_range": paginated.get_elided_page_range(
67                 page.number, on_each_side=2, on_ends=1
68             ),
69             "work": work,
70             "work_form": forms.EditionFromWorkForm(instance=work),
71             "languages": languages,
72             "formats": set(
73                 e.physical_format.lower() for e in editions if e.physical_format
74             ),
75         }
76         return TemplateResponse(request, "book/editions/editions.html", data)
77 
78 
79 @login_required
80 @require_POST
81 @transaction.atomic
82 def switch_edition(request):
83     """switch your copy of a book to a different edition"""
84     edition_id = request.POST.get("edition")
85     new_edition = get_object_or_404(models.Edition, id=edition_id)
86     shelfbooks = models.ShelfBook.objects.filter(
87         book__parent_work=new_edition.parent_work, shelf__user=request.user
88     )
89     for shelfbook in shelfbooks.all():
90         with transaction.atomic():
91             models.ShelfBook.objects.create(
92                 created_date=shelfbook.created_date,
93                 user=shelfbook.user,
94                 shelf=shelfbook.shelf,
95                 book=new_edition,
96             )
97             shelfbook.delete()
98 
99     readthroughs = models.ReadThrough.objects.filter(
100         book__parent_work=new_edition.parent_work, user=request.user
101     )
102     for readthrough in readthroughs.all():
103         readthrough.book = new_edition
104         readthrough.save()
105 
106     return redirect(f"/book/{new_edition.id}")
107
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/bookwyrm/views/books/editions.py b/bookwyrm/views/books/editions.py
--- a/bookwyrm/views/books/editions.py
+++ b/bookwyrm/views/books/editions.py
@@ -93,6 +93,7 @@
                 user=shelfbook.user,
                 shelf=shelfbook.shelf,
                 book=new_edition,
+                shelved_date=shelfbook.shelved_date,
             )
             shelfbook.delete()

{"golden_diff": "diff --git a/bookwyrm/views/books/editions.py b/bookwyrm/views/books/editions.py\n--- a/bookwyrm/views/books/editions.py\n+++ b/bookwyrm/views/books/editions.py\n@@ -93,6 +93,7 @@\n                 user=shelfbook.user,\n                 shelf=shelfbook.shelf,\n                 book=new_edition,\n+                shelved_date=shelfbook.shelved_date,\n             )\n             shelfbook.delete()\n", "issue": "Switching editions changes \"shelved\" date\n**Describe the bug**\r\nWhen switching editions of a book already on your \"To Read\" list, the \"shelved\" date is changed to today's date.\r\n\r\n**To Reproduce**\r\nSteps to reproduce the behavior:\r\n1. Pick any book on your \"To read\" list with more than one edition\r\n2. Pick another edition and switch to this\r\n3. Observe that the book's shelved date is now today\r\n\r\n**Expected behavior**\r\nThis shouldn't changed the shelved date\r\n\r\n**Instance**\r\nhttps://books.theunseen.city\r\n\r\n---\r\n\r\n**Desktop (please complete the following information):**\r\n    - OS: MacOS 14.1\r\n    - Browser: Firefox\r\n    - Version: 20.0 (64-bit)\r\n\n", "before_files": [{"content": "\"\"\" the good stuff! the books! \"\"\"\nfrom functools import reduce\nimport operator\n\nfrom django.contrib.auth.decorators import login_required\nfrom django.core.paginator import Paginator\nfrom django.db import transaction\nfrom django.db.models import Q\nfrom django.shortcuts import get_object_or_404, redirect\nfrom django.template.response import TemplateResponse\nfrom django.views import View\nfrom django.views.decorators.http import require_POST\n\nfrom bookwyrm import forms, models\nfrom bookwyrm.activitypub import ActivitypubResponse\nfrom bookwyrm.settings import PAGE_LENGTH\nfrom bookwyrm.views.helpers import is_api_request\n\n\n# pylint: disable=no-self-use\nclass Editions(View):\n    \"\"\"list of editions\"\"\"\n\n    def get(self, request, book_id):\n        \"\"\"list of editions of a book\"\"\"\n        work = get_object_or_404(models.Work, id=book_id)\n\n        if is_api_request(request):\n            return ActivitypubResponse(work.to_edition_list(**request.GET))\n        filters = {}\n\n        if request.GET.get(\"language\"):\n            filters[\"languages__contains\"] = [request.GET.get(\"language\")]\n        if request.GET.get(\"format\"):\n            filters[\"physical_format__iexact\"] = request.GET.get(\"format\")\n\n        editions = work.editions.order_by(\"-edition_rank\")\n        languages = set(sum(editions.values_list(\"languages\", flat=True), []))\n\n        editions = editions.filter(**filters)\n\n        query = request.GET.get(\"q\")\n        if query:\n            searchable_array_fields = [\"languages\", \"publishers\"]\n            searchable_fields = [\n                \"title\",\n                \"physical_format\",\n                \"isbn_10\",\n                \"isbn_13\",\n                \"oclc_number\",\n                \"asin\",\n                \"aasin\",\n                \"isfdb\",\n            ]\n            search_filter_entries = [\n                {f\"{f}__icontains\": query} for f in searchable_fields\n            ] + [{f\"{f}__iexact\": query} for f in searchable_array_fields]\n            editions = editions.filter(\n                reduce(operator.or_, (Q(**f) for f in search_filter_entries))\n            )\n\n        paginated = Paginator(editions, PAGE_LENGTH)\n        page = paginated.get_page(request.GET.get(\"page\"))\n        data = {\n            \"editions\": page,\n            \"page_range\": paginated.get_elided_page_range(\n                page.number, on_each_side=2, on_ends=1\n            ),\n            \"work\": work,\n            \"work_form\": forms.EditionFromWorkForm(instance=work),\n            \"languages\": languages,\n            \"formats\": set(\n                e.physical_format.lower() for e in editions if e.physical_format\n            ),\n        }\n        return TemplateResponse(request, \"book/editions/editions.html\", data)\n\n\n@login_required\n@require_POST\n@transaction.atomic\ndef switch_edition(request):\n    \"\"\"switch your copy of a book to a different edition\"\"\"\n    edition_id = request.POST.get(\"edition\")\n    new_edition = get_object_or_404(models.Edition, id=edition_id)\n    shelfbooks = models.ShelfBook.objects.filter(\n        book__parent_work=new_edition.parent_work, shelf__user=request.user\n    )\n    for shelfbook in shelfbooks.all():\n        with transaction.atomic():\n            models.ShelfBook.objects.create(\n                created_date=shelfbook.created_date,\n                user=shelfbook.user,\n                shelf=shelfbook.shelf,\n                book=new_edition,\n            )\n            shelfbook.delete()\n\n    readthroughs = models.ReadThrough.objects.filter(\n        book__parent_work=new_edition.parent_work, user=request.user\n    )\n    for readthrough in readthroughs.all():\n        readthrough.book = new_edition\n        readthrough.save()\n\n    return redirect(f\"/book/{new_edition.id}\")\n", "path": "bookwyrm/views/books/editions.py"}], "after_files": [{"content": "\"\"\" the good stuff! the books! \"\"\"\nfrom functools import reduce\nimport operator\n\nfrom django.contrib.auth.decorators import login_required\nfrom django.core.paginator import Paginator\nfrom django.db import transaction\nfrom django.db.models import Q\nfrom django.shortcuts import get_object_or_404, redirect\nfrom django.template.response import TemplateResponse\nfrom django.views import View\nfrom django.views.decorators.http import require_POST\n\nfrom bookwyrm import forms, models\nfrom bookwyrm.activitypub import ActivitypubResponse\nfrom bookwyrm.settings import PAGE_LENGTH\nfrom bookwyrm.views.helpers import is_api_request\n\n\n# pylint: disable=no-self-use\nclass Editions(View):\n    \"\"\"list of editions\"\"\"\n\n    def get(self, request, book_id):\n        \"\"\"list of editions of a book\"\"\"\n        work = get_object_or_404(models.Work, id=book_id)\n\n        if is_api_request(request):\n            return ActivitypubResponse(work.to_edition_list(**request.GET))\n        filters = {}\n\n        if request.GET.get(\"language\"):\n            filters[\"languages__contains\"] = [request.GET.get(\"language\")]\n        if request.GET.get(\"format\"):\n            filters[\"physical_format__iexact\"] = request.GET.get(\"format\")\n\n        editions = work.editions.order_by(\"-edition_rank\")\n        languages = set(sum(editions.values_list(\"languages\", flat=True), []))\n\n        editions = editions.filter(**filters)\n\n        query = request.GET.get(\"q\")\n        if query:\n            searchable_array_fields = [\"languages\", \"publishers\"]\n            searchable_fields = [\n                \"title\",\n                \"physical_format\",\n                \"isbn_10\",\n                \"isbn_13\",\n                \"oclc_number\",\n                \"asin\",\n                \"aasin\",\n                \"isfdb\",\n            ]\n            search_filter_entries = [\n                {f\"{f}__icontains\": query} for f in searchable_fields\n            ] + [{f\"{f}__iexact\": query} for f in searchable_array_fields]\n            editions = editions.filter(\n                reduce(operator.or_, (Q(**f) for f in search_filter_entries))\n            )\n\n        paginated = Paginator(editions, PAGE_LENGTH)\n        page = paginated.get_page(request.GET.get(\"page\"))\n        data = {\n            \"editions\": page,\n            \"page_range\": paginated.get_elided_page_range(\n                page.number, on_each_side=2, on_ends=1\n            ),\n            \"work\": work,\n            \"work_form\": forms.EditionFromWorkForm(instance=work),\n            \"languages\": languages,\n            \"formats\": set(\n                e.physical_format.lower() for e in editions if e.physical_format\n            ),\n        }\n        return TemplateResponse(request, \"book/editions/editions.html\", data)\n\n\n@login_required\n@require_POST\n@transaction.atomic\ndef switch_edition(request):\n    \"\"\"switch your copy of a book to a different edition\"\"\"\n    edition_id = request.POST.get(\"edition\")\n    new_edition = get_object_or_404(models.Edition, id=edition_id)\n    shelfbooks = models.ShelfBook.objects.filter(\n        book__parent_work=new_edition.parent_work, shelf__user=request.user\n    )\n    for shelfbook in shelfbooks.all():\n        with transaction.atomic():\n            models.ShelfBook.objects.create(\n                created_date=shelfbook.created_date,\n                user=shelfbook.user,\n                shelf=shelfbook.shelf,\n                book=new_edition,\n                shelved_date=shelfbook.shelved_date,\n            )\n            shelfbook.delete()\n\n    readthroughs = models.ReadThrough.objects.filter(\n        book__parent_work=new_edition.parent_work, user=request.user\n    )\n    for readthrough in readthroughs.all():\n        readthrough.book = new_edition\n        readthrough.save()\n\n    return redirect(f\"/book/{new_edition.id}\")\n", "path": "bookwyrm/views/books/editions.py"}]}