prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Return user's geolocalization based on IP
  API should return geolocalization data guessed from users's IP. We already have all the logic in the `saleor.core.middleware.country` function. What needs to be done is to wrap this data in a GraphQL type and tie it up to the API. 
  
  E.g.:
  ```
  shop {
    geolocalization {
      countryCode
    }
  }
  ```
  
  Should it return DEFAULT_COUNTRY from settings as a fallback?
  
  @mociepka Please provide more information about what data you'd need in the storefront.
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `saleor/graphql/shop/types.py`
  Content:
  ```
  1 import graphene
  2 from django.conf import settings
  3 from django_countries import countries
  4 from graphql_jwt.decorators import permission_required
  5 from phonenumbers import COUNTRY_CODE_TO_REGION_CODE
  6 
  7 from ...core.permissions import get_permissions
  8 from ...site import models as site_models
  9 from ..core.types.common import (
  10     CountryDisplay, LanguageDisplay, PermissionDisplay, WeightUnitsEnum)
  11 from ..menu.types import Menu
  12 from ..product.types import Collection
  13 from ..utils import format_permissions_for_display
  14 
  15 
  16 class Navigation(graphene.ObjectType):
  17     main = graphene.Field(Menu, description='Main navigation bar.')
  18     secondary = graphene.Field(Menu, description='Secondary navigation bar.')
  19 
  20     class Meta:
  21         description = 'Represents shop\'s navigation menus.'
  22 
  23 
  24 class AuthorizationKey(graphene.ObjectType):
  25     name = graphene.String(description='Name of the key.', required=True)
  26     key = graphene.String(description='Value of the key.', required=True)
  27 
  28 
  29 class Domain(graphene.ObjectType):
  30     host = graphene.String(
  31         description='The host name of the domain.', required=True)
  32     ssl_enabled = graphene.Boolean(
  33         description='Inform if SSL is enabled.', required=True)
  34     url = graphene.String(
  35         description='Shop\'s absolute URL.', required=True)
  36 
  37     class Meta:
  38         description = 'Represents shop\'s domain.'
  39 
  40 
  41 class Shop(graphene.ObjectType):
  42     authorization_keys = graphene.List(
  43         AuthorizationKey, description='List of configured authorization keys.',
  44         required=True)
  45     countries = graphene.List(
  46         CountryDisplay, description='List of countries available in the shop.',
  47         required=True)
  48     currencies = graphene.List(
  49         graphene.String, description='List of available currencies.',
  50         required=True)
  51     default_currency = graphene.String(
  52         description='Default shop\'s currency.', required=True)
  53     default_country = graphene.Field(
  54         CountryDisplay, description='Default shop\'s country')
  55     description = graphene.String(description='Shop\'s description.')
  56     domain = graphene.Field(
  57         Domain, required=True, description='Shop\'s domain data.')
  58     homepage_collection = graphene.Field(
  59         Collection, description='Collection displayed on homepage')
  60     languages = graphene.List(
  61         LanguageDisplay,
  62         description='List of the shops\'s supported languages.', required=True)
  63     name = graphene.String(description='Shop\'s name.', required=True)
  64     navigation = graphene.Field(
  65         Navigation, description='Shop\'s navigation.')
  66     permissions = graphene.List(
  67         PermissionDisplay, description='List of available permissions.',
  68         required=True)
  69     phone_prefixes = graphene.List(
  70         graphene.String, description='List of possible phone prefixes.',
  71         required=True)
  72     header_text = graphene.String(description='Header text')
  73     include_taxes_in_prices = graphene.Boolean(
  74         description='Include taxes in prices')
  75     display_gross_prices = graphene.Boolean(
  76         description='Display prices with tax in store')
  77     track_inventory_by_default = graphene.Boolean(
  78         description='Enable inventory tracking')
  79     default_weight_unit = WeightUnitsEnum(description='Default weight unit')
  80 
  81     class Meta:
  82         description = '''
  83         Represents a shop resource containing general shop\'s data
  84         and configuration.'''
  85 
  86     @permission_required('site.manage_settings')
  87     def resolve_authorization_keys(self, info):
  88         return site_models.AuthorizationKey.objects.all()
  89 
  90     def resolve_countries(self, info):
  91         return [
  92             CountryDisplay(code=country[0], country=country[1])
  93             for country in countries]
  94 
  95     def resolve_currencies(self, info):
  96         return settings.AVAILABLE_CURRENCIES
  97 
  98     def resolve_domain(self, info):
  99         site = info.context.site
  100         return Domain(
  101             host=site.domain,
  102             ssl_enabled=settings.ENABLE_SSL,
  103             url=info.context.build_absolute_uri('/'))
  104 
  105     def resolve_default_currency(self, info):
  106         return settings.DEFAULT_CURRENCY
  107 
  108     def resolve_description(self, info):
  109         return info.context.site.settings.description
  110 
  111     def resolve_homepage_collection(self, info):
  112         return info.context.site.settings.homepage_collection
  113 
  114     def resolve_languages(self, info):
  115         return [
  116             LanguageDisplay(code=language[0], language=language[1])
  117             for language in settings.LANGUAGES]
  118 
  119     def resolve_name(self, info):
  120         return info.context.site.name
  121 
  122     def resolve_navigation(self, info):
  123         site_settings = info.context.site.settings
  124         return Navigation(
  125             main=site_settings.top_menu, secondary=site_settings.bottom_menu)
  126 
  127     @permission_required('site.manage_settings')
  128     def resolve_permissions(self, info):
  129         permissions = get_permissions()
  130         return format_permissions_for_display(permissions)
  131 
  132     def resolve_phone_prefixes(self, info):
  133         return list(COUNTRY_CODE_TO_REGION_CODE.keys())
  134 
  135     def resolve_header_text(self, info):
  136         return info.context.site.settings.header_text
  137 
  138     def resolve_include_taxes_in_prices(self, info):
  139         return info.context.site.settings.include_taxes_in_prices
  140 
  141     def resolve_display_gross_prices(self, info):
  142         return info.context.site.settings.display_gross_prices
  143 
  144     def resolve_track_inventory_by_default(self, info):
  145         return info.context.site.settings.track_inventory_by_default
  146 
  147     def resolve_default_weight_unit(self, info):
  148         return info.context.site.settings.default_weight_unit
  149 
  150     def resolve_default_country(self, info):
  151         default_country_code = settings.DEFAULT_COUNTRY
  152         default_country_name = countries.countries.get(default_country_code)
  153         if default_country_name:
  154             default_country = CountryDisplay(
  155                 code=default_country_code, country=default_country_name)
  156         else:
  157             default_country = None
  158         return default_country
  159
  ```
  --- 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/saleor/graphql/shop/types.py b/saleor/graphql/shop/types.py
  --- a/saleor/graphql/shop/types.py
  +++ b/saleor/graphql/shop/types.py
  @@ -5,6 +5,7 @@
   from phonenumbers import COUNTRY_CODE_TO_REGION_CODE
   
   from ...core.permissions import get_permissions
  +from ...core.utils import get_client_ip, get_country_by_ip
   from ...site import models as site_models
   from ..core.types.common import (
       CountryDisplay, LanguageDisplay, PermissionDisplay, WeightUnitsEnum)
  @@ -38,7 +39,19 @@
           description = 'Represents shop\'s domain.'
   
   
  +class Geolocalization(graphene.ObjectType):
  +    country = graphene.Field(
  +        CountryDisplay,
  +        description='Country of the user acquired by his IP address.')
  +
  +    class Meta:
  +        description = 'Represents customers\'s geolocalization data.'
  +
  +
   class Shop(graphene.ObjectType):
  +    geolocalization = graphene.Field(
  +        Geolocalization,
  +        description='Customer\'s geolocalization data.')
       authorization_keys = graphene.List(
           AuthorizationKey, description='List of configured authorization keys.',
           required=True)
  @@ -102,6 +115,15 @@
               ssl_enabled=settings.ENABLE_SSL,
               url=info.context.build_absolute_uri('/'))
   
  +    def resolve_geolocalization(self, info):
  +        client_ip = get_client_ip(info.context)
  +        country = get_country_by_ip(client_ip)
  +        if country:
  +            return Geolocalization(
  +                country=CountryDisplay(
  +                    code=country.code, country=country.name))
  +        return Geolocalization(country=None)
  +
       def resolve_default_currency(self, info):
           return settings.DEFAULT_CURRENCY
  
verification_info: {"golden_diff": "diff --git a/saleor/graphql/shop/types.py b/saleor/graphql/shop/types.py\n--- a/saleor/graphql/shop/types.py\n+++ b/saleor/graphql/shop/types.py\n@@ -5,6 +5,7 @@\n from phonenumbers import COUNTRY_CODE_TO_REGION_CODE\n \n from ...core.permissions import get_permissions\n+from ...core.utils import get_client_ip, get_country_by_ip\n from ...site import models as site_models\n from ..core.types.common import (\n     CountryDisplay, LanguageDisplay, PermissionDisplay, WeightUnitsEnum)\n@@ -38,7 +39,19 @@\n         description = 'Represents shop\\'s domain.'\n \n \n+class Geolocalization(graphene.ObjectType):\n+    country = graphene.Field(\n+        CountryDisplay,\n+        description='Country of the user acquired by his IP address.')\n+\n+    class Meta:\n+        description = 'Represents customers\\'s geolocalization data.'\n+\n+\n class Shop(graphene.ObjectType):\n+    geolocalization = graphene.Field(\n+        Geolocalization,\n+        description='Customer\\'s geolocalization data.')\n     authorization_keys = graphene.List(\n         AuthorizationKey, description='List of configured authorization keys.',\n         required=True)\n@@ -102,6 +115,15 @@\n             ssl_enabled=settings.ENABLE_SSL,\n             url=info.context.build_absolute_uri('/'))\n \n+    def resolve_geolocalization(self, info):\n+        client_ip = get_client_ip(info.context)\n+        country = get_country_by_ip(client_ip)\n+        if country:\n+            return Geolocalization(\n+                country=CountryDisplay(\n+                    code=country.code, country=country.name))\n+        return Geolocalization(country=None)\n+\n     def resolve_default_currency(self, info):\n         return settings.DEFAULT_CURRENCY\n", "issue": "Return user's geolocalization based on IP\nAPI should return geolocalization data guessed from users's IP. We already have all the logic in the `saleor.core.middleware.country` function. What needs to be done is to wrap this data in a GraphQL type and tie it up to the API. \r\n\r\nE.g.:\r\n```\r\nshop {\r\n  geolocalization {\r\n    countryCode\r\n  }\r\n}\r\n```\r\n\r\nShould it return DEFAULT_COUNTRY from settings as a fallback?\r\n\r\n@mociepka Please provide more information about what data you'd need in the storefront.\n", "before_files": [{"content": "import graphene\nfrom django.conf import settings\nfrom django_countries import countries\nfrom graphql_jwt.decorators import permission_required\nfrom phonenumbers import COUNTRY_CODE_TO_REGION_CODE\n\nfrom ...core.permissions import get_permissions\nfrom ...site import models as site_models\nfrom ..core.types.common import (\n    CountryDisplay, LanguageDisplay, PermissionDisplay, WeightUnitsEnum)\nfrom ..menu.types import Menu\nfrom ..product.types import Collection\nfrom ..utils import format_permissions_for_display\n\n\nclass Navigation(graphene.ObjectType):\n    main = graphene.Field(Menu, description='Main navigation bar.')\n    secondary = graphene.Field(Menu, description='Secondary navigation bar.')\n\n    class Meta:\n        description = 'Represents shop\\'s navigation menus.'\n\n\nclass AuthorizationKey(graphene.ObjectType):\n    name = graphene.String(description='Name of the key.', required=True)\n    key = graphene.String(description='Value of the key.', required=True)\n\n\nclass Domain(graphene.ObjectType):\n    host = graphene.String(\n        description='The host name of the domain.', required=True)\n    ssl_enabled = graphene.Boolean(\n        description='Inform if SSL is enabled.', required=True)\n    url = graphene.String(\n        description='Shop\\'s absolute URL.', required=True)\n\n    class Meta:\n        description = 'Represents shop\\'s domain.'\n\n\nclass Shop(graphene.ObjectType):\n    authorization_keys = graphene.List(\n        AuthorizationKey, description='List of configured authorization keys.',\n        required=True)\n    countries = graphene.List(\n        CountryDisplay, description='List of countries available in the shop.',\n        required=True)\n    currencies = graphene.List(\n        graphene.String, description='List of available currencies.',\n        required=True)\n    default_currency = graphene.String(\n        description='Default shop\\'s currency.', required=True)\n    default_country = graphene.Field(\n        CountryDisplay, description='Default shop\\'s country')\n    description = graphene.String(description='Shop\\'s description.')\n    domain = graphene.Field(\n        Domain, required=True, description='Shop\\'s domain data.')\n    homepage_collection = graphene.Field(\n        Collection, description='Collection displayed on homepage')\n    languages = graphene.List(\n        LanguageDisplay,\n        description='List of the shops\\'s supported languages.', required=True)\n    name = graphene.String(description='Shop\\'s name.', required=True)\n    navigation = graphene.Field(\n        Navigation, description='Shop\\'s navigation.')\n    permissions = graphene.List(\n        PermissionDisplay, description='List of available permissions.',\n        required=True)\n    phone_prefixes = graphene.List(\n        graphene.String, description='List of possible phone prefixes.',\n        required=True)\n    header_text = graphene.String(description='Header text')\n    include_taxes_in_prices = graphene.Boolean(\n        description='Include taxes in prices')\n    display_gross_prices = graphene.Boolean(\n        description='Display prices with tax in store')\n    track_inventory_by_default = graphene.Boolean(\n        description='Enable inventory tracking')\n    default_weight_unit = WeightUnitsEnum(description='Default weight unit')\n\n    class Meta:\n        description = '''\n        Represents a shop resource containing general shop\\'s data\n        and configuration.'''\n\n    @permission_required('site.manage_settings')\n    def resolve_authorization_keys(self, info):\n        return site_models.AuthorizationKey.objects.all()\n\n    def resolve_countries(self, info):\n        return [\n            CountryDisplay(code=country[0], country=country[1])\n            for country in countries]\n\n    def resolve_currencies(self, info):\n        return settings.AVAILABLE_CURRENCIES\n\n    def resolve_domain(self, info):\n        site = info.context.site\n        return Domain(\n            host=site.domain,\n            ssl_enabled=settings.ENABLE_SSL,\n            url=info.context.build_absolute_uri('/'))\n\n    def resolve_default_currency(self, info):\n        return settings.DEFAULT_CURRENCY\n\n    def resolve_description(self, info):\n        return info.context.site.settings.description\n\n    def resolve_homepage_collection(self, info):\n        return info.context.site.settings.homepage_collection\n\n    def resolve_languages(self, info):\n        return [\n            LanguageDisplay(code=language[0], language=language[1])\n            for language in settings.LANGUAGES]\n\n    def resolve_name(self, info):\n        return info.context.site.name\n\n    def resolve_navigation(self, info):\n        site_settings = info.context.site.settings\n        return Navigation(\n            main=site_settings.top_menu, secondary=site_settings.bottom_menu)\n\n    @permission_required('site.manage_settings')\n    def resolve_permissions(self, info):\n        permissions = get_permissions()\n        return format_permissions_for_display(permissions)\n\n    def resolve_phone_prefixes(self, info):\n        return list(COUNTRY_CODE_TO_REGION_CODE.keys())\n\n    def resolve_header_text(self, info):\n        return info.context.site.settings.header_text\n\n    def resolve_include_taxes_in_prices(self, info):\n        return info.context.site.settings.include_taxes_in_prices\n\n    def resolve_display_gross_prices(self, info):\n        return info.context.site.settings.display_gross_prices\n\n    def resolve_track_inventory_by_default(self, info):\n        return info.context.site.settings.track_inventory_by_default\n\n    def resolve_default_weight_unit(self, info):\n        return info.context.site.settings.default_weight_unit\n\n    def resolve_default_country(self, info):\n        default_country_code = settings.DEFAULT_COUNTRY\n        default_country_name = countries.countries.get(default_country_code)\n        if default_country_name:\n            default_country = CountryDisplay(\n                code=default_country_code, country=default_country_name)\n        else:\n            default_country = None\n        return default_country\n", "path": "saleor/graphql/shop/types.py"}], "after_files": [{"content": "import graphene\nfrom django.conf import settings\nfrom django_countries import countries\nfrom graphql_jwt.decorators import permission_required\nfrom phonenumbers import COUNTRY_CODE_TO_REGION_CODE\n\nfrom ...core.permissions import get_permissions\nfrom ...core.utils import get_client_ip, get_country_by_ip\nfrom ...site import models as site_models\nfrom ..core.types.common import (\n    CountryDisplay, LanguageDisplay, PermissionDisplay, WeightUnitsEnum)\nfrom ..menu.types import Menu\nfrom ..product.types import Collection\nfrom ..utils import format_permissions_for_display\n\n\nclass Navigation(graphene.ObjectType):\n    main = graphene.Field(Menu, description='Main navigation bar.')\n    secondary = graphene.Field(Menu, description='Secondary navigation bar.')\n\n    class Meta:\n        description = 'Represents shop\\'s navigation menus.'\n\n\nclass AuthorizationKey(graphene.ObjectType):\n    name = graphene.String(description='Name of the key.', required=True)\n    key = graphene.String(description='Value of the key.', required=True)\n\n\nclass Domain(graphene.ObjectType):\n    host = graphene.String(\n        description='The host name of the domain.', required=True)\n    ssl_enabled = graphene.Boolean(\n        description='Inform if SSL is enabled.', required=True)\n    url = graphene.String(\n        description='Shop\\'s absolute URL.', required=True)\n\n    class Meta:\n        description = 'Represents shop\\'s domain.'\n\n\nclass Geolocalization(graphene.ObjectType):\n    country = graphene.Field(\n        CountryDisplay,\n        description='Country of the user acquired by his IP address.')\n\n    class Meta:\n        description = 'Represents customers\\'s geolocalization data.'\n\n\nclass Shop(graphene.ObjectType):\n    geolocalization = graphene.Field(\n        Geolocalization,\n        description='Customer\\'s geolocalization data.')\n    authorization_keys = graphene.List(\n        AuthorizationKey, description='List of configured authorization keys.',\n        required=True)\n    countries = graphene.List(\n        CountryDisplay, description='List of countries available in the shop.',\n        required=True)\n    currencies = graphene.List(\n        graphene.String, description='List of available currencies.',\n        required=True)\n    default_currency = graphene.String(\n        description='Default shop\\'s currency.', required=True)\n    default_country = graphene.Field(\n        CountryDisplay, description='Default shop\\'s country')\n    description = graphene.String(description='Shop\\'s description.')\n    domain = graphene.Field(\n        Domain, required=True, description='Shop\\'s domain data.')\n    homepage_collection = graphene.Field(\n        Collection, description='Collection displayed on homepage')\n    languages = graphene.List(\n        LanguageDisplay,\n        description='List of the shops\\'s supported languages.', required=True)\n    name = graphene.String(description='Shop\\'s name.', required=True)\n    navigation = graphene.Field(\n        Navigation, description='Shop\\'s navigation.')\n    permissions = graphene.List(\n        PermissionDisplay, description='List of available permissions.',\n        required=True)\n    phone_prefixes = graphene.List(\n        graphene.String, description='List of possible phone prefixes.',\n        required=True)\n    header_text = graphene.String(description='Header text')\n    include_taxes_in_prices = graphene.Boolean(\n        description='Include taxes in prices')\n    display_gross_prices = graphene.Boolean(\n        description='Display prices with tax in store')\n    track_inventory_by_default = graphene.Boolean(\n        description='Enable inventory tracking')\n    default_weight_unit = WeightUnitsEnum(description='Default weight unit')\n\n    class Meta:\n        description = '''\n        Represents a shop resource containing general shop\\'s data\n        and configuration.'''\n\n    @permission_required('site.manage_settings')\n    def resolve_authorization_keys(self, info):\n        return site_models.AuthorizationKey.objects.all()\n\n    def resolve_countries(self, info):\n        return [\n            CountryDisplay(code=country[0], country=country[1])\n            for country in countries]\n\n    def resolve_currencies(self, info):\n        return settings.AVAILABLE_CURRENCIES\n\n    def resolve_domain(self, info):\n        site = info.context.site\n        return Domain(\n            host=site.domain,\n            ssl_enabled=settings.ENABLE_SSL,\n            url=info.context.build_absolute_uri('/'))\n\n    def resolve_geolocalization(self, info):\n        client_ip = get_client_ip(info.context)\n        country = get_country_by_ip(client_ip)\n        if country:\n            return Geolocalization(\n                country=CountryDisplay(\n                    code=country.code, country=country.name))\n        return Geolocalization(country=None)\n\n    def resolve_default_currency(self, info):\n        return settings.DEFAULT_CURRENCY\n\n    def resolve_description(self, info):\n        return info.context.site.settings.description\n\n    def resolve_homepage_collection(self, info):\n        return info.context.site.settings.homepage_collection\n\n    def resolve_languages(self, info):\n        return [\n            LanguageDisplay(code=language[0], language=language[1])\n            for language in settings.LANGUAGES]\n\n    def resolve_name(self, info):\n        return info.context.site.name\n\n    def resolve_navigation(self, info):\n        site_settings = info.context.site.settings\n        return Navigation(\n            main=site_settings.top_menu, secondary=site_settings.bottom_menu)\n\n    @permission_required('site.manage_settings')\n    def resolve_permissions(self, info):\n        permissions = get_permissions()\n        return format_permissions_for_display(permissions)\n\n    def resolve_phone_prefixes(self, info):\n        return list(COUNTRY_CODE_TO_REGION_CODE.keys())\n\n    def resolve_header_text(self, info):\n        return info.context.site.settings.header_text\n\n    def resolve_include_taxes_in_prices(self, info):\n        return info.context.site.settings.include_taxes_in_prices\n\n    def resolve_display_gross_prices(self, info):\n        return info.context.site.settings.display_gross_prices\n\n    def resolve_track_inventory_by_default(self, info):\n        return info.context.site.settings.track_inventory_by_default\n\n    def resolve_default_weight_unit(self, info):\n        return info.context.site.settings.default_weight_unit\n\n    def resolve_default_country(self, info):\n        default_country_code = settings.DEFAULT_COUNTRY\n        default_country_name = countries.countries.get(default_country_code)\n        if default_country_name:\n            default_country = CountryDisplay(\n                code=default_country_code, country=default_country_name)\n        else:\n            default_country = None\n        return default_country\n", "path": "saleor/graphql/shop/types.py"}]}