We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Import from Goodreads doesn't work correctly
**Describe the bug**

Import  from goodreads csv imports only first line of csv and stops with 'success' status. If user tries to reimport same csv again importer takes the same first imported line yet again. 

Broken import examples https://bookwyrm.social/import/775 https://bookwyrm.social/import/776

**Expected behavior**
Importer correctly imports all lines of csv or returns error message to user

--- 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/import_data.py`
Content:
```
1 """ import books from another app """
2 from io import TextIOWrapper
3 
4 from django.contrib.auth.decorators import login_required
5 from django.core.exceptions import PermissionDenied
6 from django.http import HttpResponseBadRequest
7 from django.shortcuts import get_object_or_404, redirect
8 from django.template.response import TemplateResponse
9 from django.utils.decorators import method_decorator
10 from django.utils.translation import gettext_lazy as _
11 from django.views import View
12 
13 from bookwyrm import forms, models
14 from bookwyrm.importers import (
15     Importer,
16     LibrarythingImporter,
17     GoodreadsImporter,
18     StorygraphImporter,
19 )
20 from bookwyrm.tasks import app
21 
22 # pylint: disable= no-self-use
23 @method_decorator(login_required, name="dispatch")
24 class Import(View):
25     """import view"""
26 
27     def get(self, request):
28         """load import page"""
29         return TemplateResponse(
30             request,
31             "import.html",
32             {
33                 "import_form": forms.ImportForm(),
34                 "jobs": models.ImportJob.objects.filter(user=request.user).order_by(
35                     "-created_date"
36                 ),
37             },
38         )
39 
40     def post(self, request):
41         """ingest a goodreads csv"""
42         form = forms.ImportForm(request.POST, request.FILES)
43         if form.is_valid():
44             include_reviews = request.POST.get("include_reviews") == "on"
45             privacy = request.POST.get("privacy")
46             source = request.POST.get("source")
47 
48             importer = None
49             if source == "LibraryThing":
50                 importer = LibrarythingImporter()
51             elif source == "Storygraph":
52                 importer = StorygraphImporter()
53             else:
54                 # Default : GoodReads
55                 importer = GoodreadsImporter()
56 
57             try:
58                 job = importer.create_job(
59                     request.user,
60                     TextIOWrapper(
61                         request.FILES["csv_file"], encoding=importer.encoding
62                     ),
63                     include_reviews,
64                     privacy,
65                 )
66             except (UnicodeDecodeError, ValueError, KeyError):
67                 return HttpResponseBadRequest(_("Not a valid csv file"))
68 
69             importer.start_import(job)
70 
71             return redirect("/import/%d" % job.id)
72         return HttpResponseBadRequest()
73 
74 
75 @method_decorator(login_required, name="dispatch")
76 class ImportStatus(View):
77     """status of an existing import"""
78 
79     def get(self, request, job_id):
80         """status of an import job"""
81         job = get_object_or_404(models.ImportJob, id=job_id)
82         if job.user != request.user:
83             raise PermissionDenied
84 
85         try:
86             task = app.AsyncResult(job.task_id)
87             # triggers attribute error if the task won't load
88             task.status  # pylint: disable=pointless-statement
89         except (ValueError, AttributeError):
90             task = None
91 
92         items = job.items.order_by("index").all()
93         failed_items = [i for i in items if i.fail_reason]
94         items = [i for i in items if not i.fail_reason]
95         return TemplateResponse(
96             request,
97             "import_status.html",
98             {"job": job, "items": items, "failed_items": failed_items, "task": task},
99         )
100 
101     def post(self, request, job_id):
102         """retry lines from an import"""
103         job = get_object_or_404(models.ImportJob, id=job_id)
104         items = []
105         for item in request.POST.getlist("import_item"):
106             items.append(get_object_or_404(models.ImportItem, id=item))
107 
108         importer = Importer()
109         job = importer.create_retry_job(
110             request.user,
111             job,
112             items,
113         )
114         importer.start_import(job)
115         return redirect("/import/%d" % job.id)
116
```
--- 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/import_data.py b/bookwyrm/views/import_data.py
--- a/bookwyrm/views/import_data.py
+++ b/bookwyrm/views/import_data.py
@@ -28,7 +28,7 @@
         """load import page"""
         return TemplateResponse(
             request,
-            "import.html",
+            "import/import.html",
             {
                 "import_form": forms.ImportForm(),
                 "jobs": models.ImportJob.objects.filter(user=request.user).order_by(
@@ -94,7 +94,7 @@
         items = [i for i in items if not i.fail_reason]
         return TemplateResponse(
             request,
-            "import_status.html",
+            "import/import_status.html",
             {"job": job, "items": items, "failed_items": failed_items, "task": task},
         )

{"golden_diff": "diff --git a/bookwyrm/views/import_data.py b/bookwyrm/views/import_data.py\n--- a/bookwyrm/views/import_data.py\n+++ b/bookwyrm/views/import_data.py\n@@ -28,7 +28,7 @@\n         \"\"\"load import page\"\"\"\n         return TemplateResponse(\n             request,\n-            \"import.html\",\n+            \"import/import.html\",\n             {\n                 \"import_form\": forms.ImportForm(),\n                 \"jobs\": models.ImportJob.objects.filter(user=request.user).order_by(\n@@ -94,7 +94,7 @@\n         items = [i for i in items if not i.fail_reason]\n         return TemplateResponse(\n             request,\n-            \"import_status.html\",\n+            \"import/import_status.html\",\n             {\"job\": job, \"items\": items, \"failed_items\": failed_items, \"task\": task},\n         )\n", "issue": "Import from Goodreads doesn't work correctly\n**Describe the bug**\r\n\r\nImport  from goodreads csv imports only first line of csv and stops with 'success' status. If user tries to reimport same csv again importer takes the same first imported line yet again. \r\n\r\nBroken import examples https://bookwyrm.social/import/775 https://bookwyrm.social/import/776\r\n\r\n**Expected behavior**\r\nImporter correctly imports all lines of csv or returns error message to user\n", "before_files": [{"content": "\"\"\" import books from another app \"\"\"\nfrom io import TextIOWrapper\n\nfrom django.contrib.auth.decorators import login_required\nfrom django.core.exceptions import PermissionDenied\nfrom django.http import HttpResponseBadRequest\nfrom django.shortcuts import get_object_or_404, redirect\nfrom django.template.response import TemplateResponse\nfrom django.utils.decorators import method_decorator\nfrom django.utils.translation import gettext_lazy as _\nfrom django.views import View\n\nfrom bookwyrm import forms, models\nfrom bookwyrm.importers import (\n    Importer,\n    LibrarythingImporter,\n    GoodreadsImporter,\n    StorygraphImporter,\n)\nfrom bookwyrm.tasks import app\n\n# pylint: disable= no-self-use\n@method_decorator(login_required, name=\"dispatch\")\nclass Import(View):\n    \"\"\"import view\"\"\"\n\n    def get(self, request):\n        \"\"\"load import page\"\"\"\n        return TemplateResponse(\n            request,\n            \"import.html\",\n            {\n                \"import_form\": forms.ImportForm(),\n                \"jobs\": models.ImportJob.objects.filter(user=request.user).order_by(\n                    \"-created_date\"\n                ),\n            },\n        )\n\n    def post(self, request):\n        \"\"\"ingest a goodreads csv\"\"\"\n        form = forms.ImportForm(request.POST, request.FILES)\n        if form.is_valid():\n            include_reviews = request.POST.get(\"include_reviews\") == \"on\"\n            privacy = request.POST.get(\"privacy\")\n            source = request.POST.get(\"source\")\n\n            importer = None\n            if source == \"LibraryThing\":\n                importer = LibrarythingImporter()\n            elif source == \"Storygraph\":\n                importer = StorygraphImporter()\n            else:\n                # Default : GoodReads\n                importer = GoodreadsImporter()\n\n            try:\n                job = importer.create_job(\n                    request.user,\n                    TextIOWrapper(\n                        request.FILES[\"csv_file\"], encoding=importer.encoding\n                    ),\n                    include_reviews,\n                    privacy,\n                )\n            except (UnicodeDecodeError, ValueError, KeyError):\n                return HttpResponseBadRequest(_(\"Not a valid csv file\"))\n\n            importer.start_import(job)\n\n            return redirect(\"/import/%d\" % job.id)\n        return HttpResponseBadRequest()\n\n\n@method_decorator(login_required, name=\"dispatch\")\nclass ImportStatus(View):\n    \"\"\"status of an existing import\"\"\"\n\n    def get(self, request, job_id):\n        \"\"\"status of an import job\"\"\"\n        job = get_object_or_404(models.ImportJob, id=job_id)\n        if job.user != request.user:\n            raise PermissionDenied\n\n        try:\n            task = app.AsyncResult(job.task_id)\n            # triggers attribute error if the task won't load\n            task.status  # pylint: disable=pointless-statement\n        except (ValueError, AttributeError):\n            task = None\n\n        items = job.items.order_by(\"index\").all()\n        failed_items = [i for i in items if i.fail_reason]\n        items = [i for i in items if not i.fail_reason]\n        return TemplateResponse(\n            request,\n            \"import_status.html\",\n            {\"job\": job, \"items\": items, \"failed_items\": failed_items, \"task\": task},\n        )\n\n    def post(self, request, job_id):\n        \"\"\"retry lines from an import\"\"\"\n        job = get_object_or_404(models.ImportJob, id=job_id)\n        items = []\n        for item in request.POST.getlist(\"import_item\"):\n            items.append(get_object_or_404(models.ImportItem, id=item))\n\n        importer = Importer()\n        job = importer.create_retry_job(\n            request.user,\n            job,\n            items,\n        )\n        importer.start_import(job)\n        return redirect(\"/import/%d\" % job.id)\n", "path": "bookwyrm/views/import_data.py"}], "after_files": [{"content": "\"\"\" import books from another app \"\"\"\nfrom io import TextIOWrapper\n\nfrom django.contrib.auth.decorators import login_required\nfrom django.core.exceptions import PermissionDenied\nfrom django.http import HttpResponseBadRequest\nfrom django.shortcuts import get_object_or_404, redirect\nfrom django.template.response import TemplateResponse\nfrom django.utils.decorators import method_decorator\nfrom django.utils.translation import gettext_lazy as _\nfrom django.views import View\n\nfrom bookwyrm import forms, models\nfrom bookwyrm.importers import (\n    Importer,\n    LibrarythingImporter,\n    GoodreadsImporter,\n    StorygraphImporter,\n)\nfrom bookwyrm.tasks import app\n\n# pylint: disable= no-self-use\n@method_decorator(login_required, name=\"dispatch\")\nclass Import(View):\n    \"\"\"import view\"\"\"\n\n    def get(self, request):\n        \"\"\"load import page\"\"\"\n        return TemplateResponse(\n            request,\n            \"import/import.html\",\n            {\n                \"import_form\": forms.ImportForm(),\n                \"jobs\": models.ImportJob.objects.filter(user=request.user).order_by(\n                    \"-created_date\"\n                ),\n            },\n        )\n\n    def post(self, request):\n        \"\"\"ingest a goodreads csv\"\"\"\n        form = forms.ImportForm(request.POST, request.FILES)\n        if form.is_valid():\n            include_reviews = request.POST.get(\"include_reviews\") == \"on\"\n            privacy = request.POST.get(\"privacy\")\n            source = request.POST.get(\"source\")\n\n            importer = None\n            if source == \"LibraryThing\":\n                importer = LibrarythingImporter()\n            elif source == \"Storygraph\":\n                importer = StorygraphImporter()\n            else:\n                # Default : GoodReads\n                importer = GoodreadsImporter()\n\n            try:\n                job = importer.create_job(\n                    request.user,\n                    TextIOWrapper(\n                        request.FILES[\"csv_file\"], encoding=importer.encoding\n                    ),\n                    include_reviews,\n                    privacy,\n                )\n            except (UnicodeDecodeError, ValueError, KeyError):\n                return HttpResponseBadRequest(_(\"Not a valid csv file\"))\n\n            importer.start_import(job)\n\n            return redirect(\"/import/%d\" % job.id)\n        return HttpResponseBadRequest()\n\n\n@method_decorator(login_required, name=\"dispatch\")\nclass ImportStatus(View):\n    \"\"\"status of an existing import\"\"\"\n\n    def get(self, request, job_id):\n        \"\"\"status of an import job\"\"\"\n        job = get_object_or_404(models.ImportJob, id=job_id)\n        if job.user != request.user:\n            raise PermissionDenied\n\n        try:\n            task = app.AsyncResult(job.task_id)\n            # triggers attribute error if the task won't load\n            task.status  # pylint: disable=pointless-statement\n        except (ValueError, AttributeError):\n            task = None\n\n        items = job.items.order_by(\"index\").all()\n        failed_items = [i for i in items if i.fail_reason]\n        items = [i for i in items if not i.fail_reason]\n        return TemplateResponse(\n            request,\n            \"import/import_status.html\",\n            {\"job\": job, \"items\": items, \"failed_items\": failed_items, \"task\": task},\n        )\n\n    def post(self, request, job_id):\n        \"\"\"retry lines from an import\"\"\"\n        job = get_object_or_404(models.ImportJob, id=job_id)\n        items = []\n        for item in request.POST.getlist(\"import_item\"):\n            items.append(get_object_or_404(models.ImportItem, id=item))\n\n        importer = Importer()\n        job = importer.create_retry_job(\n            request.user,\n            job,\n            items,\n        )\n        importer.start_import(job)\n        return redirect(\"/import/%d\" % job.id)\n", "path": "bookwyrm/views/import_data.py"}]}