Repository: saleor/saleor

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.


Discussion:
I think it's not necessary to automatically default to DEFAULT_COUNTRY. Let the client handle the case where the country is not possible to determine. I think we ought to return more than the country code though. There's #2745 for displaying richer representations (so you don't need to fetch the full list of countries). There's also the problem of knowing which currency to default to for the given country.

Resolving patch:
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 @@ class Meta:
         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 @@ def resolve_domain(self, info):
             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
 


Test patch:
diff --git a/tests/api/test_shop.py b/tests/api/test_shop.py
--- a/tests/api/test_shop.py
+++ b/tests/api/test_shop.py
@@ -281,3 +281,31 @@ def test_query_default_country(user_api_client, settings):
     data = content['data']['shop']['defaultCountry']
     assert data['code'] == settings.DEFAULT_COUNTRY
     assert data['country'] == 'United States of America'
+
+
+def test_query_geolocalization(user_api_client):
+    query = """
+        query {
+            shop {
+                geolocalization {
+                    country {
+                        code
+                    }
+                }
+            }
+        }
+    """
+    GERMAN_IP = '79.222.222.22'
+    response = user_api_client.post(
+        reverse('api'), {'query': query}, HTTP_X_FORWARDED_FOR=GERMAN_IP)
+    content = get_graphql_content(response)
+    assert 'errors' not in content
+    data = content['data']['shop']['geolocalization']
+    assert data['country']['code'] == 'DE'
+
+    response = user_api_client.post(
+        reverse('api'), {'query': query})
+    content = get_graphql_content(response)
+    assert 'errors' not in content
+    data = content['data']['shop']['geolocalization']
+    assert data['country'] is None