Add support for GeoIP data (#3230)

This commit is contained in:
Raphael Michel
2023-04-17 09:50:46 +02:00
committed by GitHub
parent c890f4cdc0
commit 11e3bd4d39
10 changed files with 55 additions and 8 deletions

View File

@@ -45,6 +45,7 @@ import pytz
from django import forms
from django.conf import settings
from django.contrib import messages
from django.contrib.gis.geoip2 import GeoIP2
from django.core.exceptions import ValidationError
from django.core.files.uploadedfile import SimpleUploadedFile
from django.core.validators import (
@@ -91,6 +92,7 @@ from pretix.helpers.countries import (
CachedCountries, get_phone_prefixes_sorted_and_localized,
)
from pretix.helpers.escapejson import escapejson_attr
from pretix.helpers.http import get_client_ip
from pretix.helpers.i18n import get_format_without_seconds
from pretix.presale.signals import question_form_fields
@@ -351,6 +353,15 @@ class WrappedPhoneNumberPrefixWidget(PhoneNumberPrefixWidget):
return ""
def guess_country_from_request(request, event):
if settings.HAS_GEOIP:
g = GeoIP2()
res = g.country(get_client_ip(request))
if res['country_code'] and len(res['country_code']) == 2:
return Country(res['country_code'])
return guess_country(event)
def guess_country(event):
# Try to guess the initial country from either the country of the merchant
# or the locale. This will hopefully save at least some users some scrolling :)
@@ -382,6 +393,12 @@ def guess_phone_prefix(event):
return get_phone_prefix(country)
def guess_phone_prefix_from_request(request, event):
with language(get_babel_locale()):
country = str(guess_country_from_request(request, event))
return get_phone_prefix(country)
def get_phone_prefix(country):
for prefix, values in _COUNTRY_CODE_TO_REGION_CODE.items():
if country in values:
@@ -564,6 +581,7 @@ class BaseQuestionsForm(forms.Form):
:param cartpos: The cart position the form should be for
:param event: The event this belongs to
"""
request = kwargs.pop('request', None)
cartpos = self.cartpos = kwargs.pop('cartpos', None)
orderpos = self.orderpos = kwargs.pop('orderpos', None)
pos = cartpos or orderpos
@@ -661,7 +679,7 @@ class BaseQuestionsForm(forms.Form):
'autocomplete': 'address-level2',
}),
)
country = (cartpos.country if cartpos else orderpos.country) or guess_country(event)
country = (cartpos.country if cartpos else orderpos.country) or guess_country_from_request(request, event)
add_fields['country'] = CountryField(
countries=CachedCountries
).formfield(
@@ -768,7 +786,7 @@ class BaseQuestionsForm(forms.Form):
help_text=help_text,
widget=forms.Select,
empty_label=' ',
initial=initial.answer if initial else (guess_country(event) if required else None),
initial=initial.answer if initial else (guess_country_from_request(request, event) if required else None),
)
elif q.type == Question.TYPE_CHOICE:
field = forms.ModelChoiceField(
@@ -856,7 +874,7 @@ class BaseQuestionsForm(forms.Form):
initial = None
if not initial:
phone_prefix = guess_phone_prefix(event)
phone_prefix = guess_phone_prefix_from_request(request, event)
if phone_prefix:
initial = "+{}.".format(phone_prefix)
@@ -992,7 +1010,7 @@ class BaseInvoiceAddressForm(forms.ModelForm):
kwargs.setdefault('initial', {})
if not kwargs.get('instance') or not kwargs['instance'].country:
kwargs['initial']['country'] = guess_country(self.event)
kwargs['initial']['country'] = guess_country_from_request(self.request, self.event)
super().__init__(*args, **kwargs)
if not event.settings.invoice_address_vatid:

View File

@@ -71,6 +71,7 @@ class BaseQuestionsViewMixin:
kwargs = self.question_form_kwargs(cr)
form = self.form_class(event=self.request.event,
prefix=cr.id,
request=self.request,
cartpos=cartpos,
orderpos=orderpos,
all_optional=self.all_optional,

View File

@@ -45,7 +45,7 @@ from phonenumber_field.formfields import PhoneNumberField
from pretix.base.forms.questions import (
BaseInvoiceAddressForm, BaseQuestionsForm, WrappedPhoneNumberPrefixWidget,
guess_phone_prefix,
guess_phone_prefix_from_request,
)
from pretix.base.templatetags.rich_text import rich_text
from pretix.base.validators import EmailBanlistValidator
@@ -73,7 +73,7 @@ class ContactForm(forms.Form):
if self.event.settings.order_phone_asked:
if not self.initial.get('phone'):
phone_prefix = guess_phone_prefix(self.event)
phone_prefix = guess_phone_prefix_from_request(self.request, self.event)
if phone_prefix:
# We now exploit an implementation detail in PhoneNumberPrefixWidget to allow us to pass just
# a country code but no number as an initial value. It's a bit hacky, but should be stable for

View File

@@ -25,7 +25,8 @@ from django.utils.translation import gettext_lazy as _
from phonenumber_field.formfields import PhoneNumberField
from pretix.base.forms.questions import (
NamePartsFormField, WrappedPhoneNumberPrefixWidget, guess_phone_prefix,
NamePartsFormField, WrappedPhoneNumberPrefixWidget,
guess_phone_prefix_from_request,
)
from pretix.base.models import Quota, WaitingListEntry
from pretix.base.templatetags.rich_text import rich_text
@@ -40,6 +41,7 @@ class WaitingListForm(forms.ModelForm):
fields = ('name_parts', 'email', 'phone')
def __init__(self, *args, **kwargs):
request = kwargs.pop('request')
self.event = kwargs.pop('event')
self.channel = kwargs.pop('channel')
customer = kwargs.pop('customer')
@@ -93,7 +95,7 @@ class WaitingListForm(forms.ModelForm):
if event.settings.waiting_list_phones_asked:
if not self.initial.get('phone'):
phone_prefix = guess_phone_prefix(event)
phone_prefix = guess_phone_prefix_from_request(request, event)
if phone_prefix:
self.initial['phone'] = "+{}.".format(phone_prefix)

View File

@@ -48,6 +48,7 @@ class WaitingView(EventViewMixin, FormView):
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['request'] = self.request
kwargs['event'] = self.request.event
kwargs['instance'] = WaitingListEntry(
event=self.request.event, locale=get_language_without_region(),

View File

@@ -330,6 +330,12 @@ ENTROPY = {
'giftcard_secret': config.getint('entropy', 'giftcard_secret', fallback=12),
}
HAS_GEOIP = False
if config.has_option('geoip', 'path'):
HAS_GEOIP = True
GEOIP_PATH = config.get('geoip', 'path')
GEOIP_COUNTRY = config.get('geoip', 'filename_country', fallback='GeoLite2-Country.mmdb')
# Internal settings
PRETIX_EMAIL_NONE_VALUE = 'none@well-known.pretix.eu'

View File

@@ -34,6 +34,7 @@ filterwarnings =
ignore:django.contrib.staticfiles.templatetags.static:DeprecationWarning
ignore::django.utils.deprecation.RemovedInDjango41Warning:
ignore::DeprecationWarning:compressor
ignore:pkg_resources is deprecated as an API:
[coverage:run]

View File

@@ -191,6 +191,7 @@ setup(
'djangorestframework==3.14.*',
'dnspython==2.2.*',
'drf_ujson2==1.7.*',
'geoip2==4.*',
'isoweek',
'jsonschema',
'kombu==5.2.*',