prompt: 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()
  
  ```
  
golden_diff: 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
  
verification_info: {"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"}]}