We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Normalize stored ISNI
The `ISNI` field should always be in the same format (without spaces), but right now sometimes the field is stored with spaces between the digits. There should be validation when the author is saved that cleans this value, similar to how ISBNs are validated

--- 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/models/author.py`
Content:
```
1 """ database schema for info about authors """
2 import re
3 from django.contrib.postgres.indexes import GinIndex
4 from django.core.cache import cache
5 from django.core.cache.utils import make_template_fragment_key
6 from django.db import models
7 
8 from bookwyrm import activitypub
9 from bookwyrm.settings import DOMAIN
10 
11 from .book import BookDataModel
12 from . import fields
13 
14 
15 class Author(BookDataModel):
16     """basic biographic info"""
17 
18     wikipedia_link = fields.CharField(
19         max_length=255, blank=True, null=True, deduplication_field=True
20     )
21     isni = fields.CharField(
22         max_length=255, blank=True, null=True, deduplication_field=True
23     )
24     gutenberg_id = fields.CharField(
25         max_length=255, blank=True, null=True, deduplication_field=True
26     )
27     # idk probably other keys would be useful here?
28     born = fields.DateTimeField(blank=True, null=True)
29     died = fields.DateTimeField(blank=True, null=True)
30     name = fields.CharField(max_length=255)
31     aliases = fields.ArrayField(
32         models.CharField(max_length=255), blank=True, default=list
33     )
34     bio = fields.HtmlField(null=True, blank=True)
35 
36     def save(self, *args, **kwargs):
37         """clear related template caches"""
38         # clear template caches
39         if self.id:
40             cache_keys = [
41                 make_template_fragment_key("titleby", [book])
42                 for book in self.book_set.values_list("id", flat=True)
43             ]
44             cache.delete_many(cache_keys)
45         return super().save(*args, **kwargs)
46 
47     @property
48     def isni_link(self):
49         """generate the url from the isni id"""
50         clean_isni = re.sub(r"\s", "", self.isni)
51         return f"https://isni.org/isni/{clean_isni}"
52 
53     @property
54     def openlibrary_link(self):
55         """generate the url from the openlibrary id"""
56         return f"https://openlibrary.org/authors/{self.openlibrary_key}"
57 
58     def get_remote_id(self):
59         """editions and works both use "book" instead of model_name"""
60         return f"https://{DOMAIN}/author/{self.id}"
61 
62     activity_serializer = activitypub.Author
63 
64     class Meta:
65         """sets up postgres GIN index field"""
66 
67         indexes = (GinIndex(fields=["search_vector"]),)
68
```
--- 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/models/author.py b/bookwyrm/models/author.py
--- a/bookwyrm/models/author.py
+++ b/bookwyrm/models/author.py
@@ -42,6 +42,11 @@
                 for book in self.book_set.values_list("id", flat=True)
             ]
             cache.delete_many(cache_keys)
+
+        # normalize isni format
+        if self.isni:
+            self.isni = re.sub(r"\s", "", self.isni)
+
         return super().save(*args, **kwargs)
 
     @property

{"golden_diff": "diff --git a/bookwyrm/models/author.py b/bookwyrm/models/author.py\n--- a/bookwyrm/models/author.py\n+++ b/bookwyrm/models/author.py\n@@ -42,6 +42,11 @@\n                 for book in self.book_set.values_list(\"id\", flat=True)\n             ]\n             cache.delete_many(cache_keys)\n+\n+        # normalize isni format\n+        if self.isni:\n+            self.isni = re.sub(r\"\\s\", \"\", self.isni)\n+\n         return super().save(*args, **kwargs)\n \n     @property\n", "issue": "Normalize stored ISNI\nThe `ISNI` field should always be in the same format (without spaces), but right now sometimes the field is stored with spaces between the digits. There should be validation when the author is saved that cleans this value, similar to how ISBNs are validated\n", "before_files": [{"content": "\"\"\" database schema for info about authors \"\"\"\nimport re\nfrom django.contrib.postgres.indexes import GinIndex\nfrom django.core.cache import cache\nfrom django.core.cache.utils import make_template_fragment_key\nfrom django.db import models\n\nfrom bookwyrm import activitypub\nfrom bookwyrm.settings import DOMAIN\n\nfrom .book import BookDataModel\nfrom . import fields\n\n\nclass Author(BookDataModel):\n    \"\"\"basic biographic info\"\"\"\n\n    wikipedia_link = fields.CharField(\n        max_length=255, blank=True, null=True, deduplication_field=True\n    )\n    isni = fields.CharField(\n        max_length=255, blank=True, null=True, deduplication_field=True\n    )\n    gutenberg_id = fields.CharField(\n        max_length=255, blank=True, null=True, deduplication_field=True\n    )\n    # idk probably other keys would be useful here?\n    born = fields.DateTimeField(blank=True, null=True)\n    died = fields.DateTimeField(blank=True, null=True)\n    name = fields.CharField(max_length=255)\n    aliases = fields.ArrayField(\n        models.CharField(max_length=255), blank=True, default=list\n    )\n    bio = fields.HtmlField(null=True, blank=True)\n\n    def save(self, *args, **kwargs):\n        \"\"\"clear related template caches\"\"\"\n        # clear template caches\n        if self.id:\n            cache_keys = [\n                make_template_fragment_key(\"titleby\", [book])\n                for book in self.book_set.values_list(\"id\", flat=True)\n            ]\n            cache.delete_many(cache_keys)\n        return super().save(*args, **kwargs)\n\n    @property\n    def isni_link(self):\n        \"\"\"generate the url from the isni id\"\"\"\n        clean_isni = re.sub(r\"\\s\", \"\", self.isni)\n        return f\"https://isni.org/isni/{clean_isni}\"\n\n    @property\n    def openlibrary_link(self):\n        \"\"\"generate the url from the openlibrary id\"\"\"\n        return f\"https://openlibrary.org/authors/{self.openlibrary_key}\"\n\n    def get_remote_id(self):\n        \"\"\"editions and works both use \"book\" instead of model_name\"\"\"\n        return f\"https://{DOMAIN}/author/{self.id}\"\n\n    activity_serializer = activitypub.Author\n\n    class Meta:\n        \"\"\"sets up postgres GIN index field\"\"\"\n\n        indexes = (GinIndex(fields=[\"search_vector\"]),)\n", "path": "bookwyrm/models/author.py"}], "after_files": [{"content": "\"\"\" database schema for info about authors \"\"\"\nimport re\nfrom django.contrib.postgres.indexes import GinIndex\nfrom django.core.cache import cache\nfrom django.core.cache.utils import make_template_fragment_key\nfrom django.db import models\n\nfrom bookwyrm import activitypub\nfrom bookwyrm.settings import DOMAIN\n\nfrom .book import BookDataModel\nfrom . import fields\n\n\nclass Author(BookDataModel):\n    \"\"\"basic biographic info\"\"\"\n\n    wikipedia_link = fields.CharField(\n        max_length=255, blank=True, null=True, deduplication_field=True\n    )\n    isni = fields.CharField(\n        max_length=255, blank=True, null=True, deduplication_field=True\n    )\n    gutenberg_id = fields.CharField(\n        max_length=255, blank=True, null=True, deduplication_field=True\n    )\n    # idk probably other keys would be useful here?\n    born = fields.DateTimeField(blank=True, null=True)\n    died = fields.DateTimeField(blank=True, null=True)\n    name = fields.CharField(max_length=255)\n    aliases = fields.ArrayField(\n        models.CharField(max_length=255), blank=True, default=list\n    )\n    bio = fields.HtmlField(null=True, blank=True)\n\n    def save(self, *args, **kwargs):\n        \"\"\"clear related template caches\"\"\"\n        # clear template caches\n        if self.id:\n            cache_keys = [\n                make_template_fragment_key(\"titleby\", [book])\n                for book in self.book_set.values_list(\"id\", flat=True)\n            ]\n            cache.delete_many(cache_keys)\n\n        # normalize isni format\n        if self.isni:\n            self.isni = re.sub(r\"\\s\", \"\", self.isni)\n\n        return super().save(*args, **kwargs)\n\n    @property\n    def isni_link(self):\n        \"\"\"generate the url from the isni id\"\"\"\n        clean_isni = re.sub(r\"\\s\", \"\", self.isni)\n        return f\"https://isni.org/isni/{clean_isni}\"\n\n    @property\n    def openlibrary_link(self):\n        \"\"\"generate the url from the openlibrary id\"\"\"\n        return f\"https://openlibrary.org/authors/{self.openlibrary_key}\"\n\n    def get_remote_id(self):\n        \"\"\"editions and works both use \"book\" instead of model_name\"\"\"\n        return f\"https://{DOMAIN}/author/{self.id}\"\n\n    activity_serializer = activitypub.Author\n\n    class Meta:\n        \"\"\"sets up postgres GIN index field\"\"\"\n\n        indexes = (GinIndex(fields=[\"search_vector\"]),)\n", "path": "bookwyrm/models/author.py"}]}