├── .gitignore ├── LICENSE ├── README.md └── backend └── src ├── accounts ├── __init__.py ├── admin.py ├── apps.py ├── forms.py ├── migrations │ └── __init__.py ├── models.py ├── templates │ └── registration │ │ └── login.html ├── tests.py └── views.py ├── analytics ├── __init__.py ├── admin.py ├── apps.py ├── migrations │ ├── 0001_initial.py │ └── __init__.py ├── models.py ├── signals.py ├── tests.py ├── utils.py └── views.py ├── db.sqlite3 ├── geo2 ├── __init__.py ├── settings.py ├── urls.py └── wsgi.py ├── geoip └── note.txt ├── manage.py ├── requirements.txt ├── search ├── __init__.py ├── admin.py ├── apps.py ├── migrations │ └── __init__.py ├── models.py ├── templates │ └── search │ │ └── home.html ├── tests.py ├── utils.py └── views.py └── templates └── base.html /.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | include/ 3 | pip-selfcheck.json 4 | .DS_Store 5 | 6 | backend/src/geoip/GeoLite2-City.mmdb 7 | backend/src/geoip/GeoLite2-Country.mmdb 8 | 9 | 10 | # Byte-compiled / optimized / DLL files 11 | __pycache__/ 12 | *.py[cod] 13 | *$py.class 14 | 15 | # C extensions 16 | *.so 17 | 18 | # Distribution / packaging 19 | .Python 20 | env/ 21 | build/ 22 | develop-eggs/ 23 | dist/ 24 | downloads/ 25 | eggs/ 26 | .eggs/ 27 | lib/ 28 | lib64/ 29 | parts/ 30 | sdist/ 31 | var/ 32 | *.egg-info/ 33 | .installed.cfg 34 | *.egg 35 | 36 | # PyInstaller 37 | # Usually these files are written by a python script from a template 38 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 39 | *.manifest 40 | *.spec 41 | 42 | # Installer logs 43 | pip-log.txt 44 | pip-delete-this-directory.txt 45 | 46 | # Unit test / coverage reports 47 | htmlcov/ 48 | .tox/ 49 | .coverage 50 | .coverage.* 51 | .cache 52 | nosetests.xml 53 | coverage.xml 54 | *,cover 55 | .hypothesis/ 56 | 57 | # Translations 58 | *.mo 59 | *.pot 60 | 61 | # Django stuff: 62 | *.log 63 | local_settings.py 64 | 65 | # Flask stuff: 66 | instance/ 67 | .webassets-cache 68 | 69 | # Scrapy stuff: 70 | .scrapy 71 | 72 | # Sphinx documentation 73 | docs/_build/ 74 | 75 | # PyBuilder 76 | target/ 77 | 78 | # IPython Notebook 79 | .ipynb_checkpoints 80 | 81 | # pyenv 82 | .python-version 83 | 84 | # celery beat schedule file 85 | celerybeat-schedule 86 | 87 | # dotenv 88 | .env 89 | 90 | # virtualenv 91 | venv/ 92 | ENV/ 93 | 94 | # Spyder project settings 95 | .spyderproject 96 | 97 | # Rope project settings 98 | .ropeproject -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Coding For Entrepreneurs 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |  2 | 3 | # Geolocator 2 4 | Learn how to find and work with locations in Django, the Yelp API, and Google Maps api. 5 | 6 | Watch it [here](https://www.codingforentrepreneurs.com/projects/geolocator-2/) 7 | 8 | 9 | 10 | Add them to the same directory where this note is. 11 | 12 | 13 | ===== 14 | 15 | ### Lecture Code 16 | 17 | 1. Welcome 18 | 19 | 2. Overview 20 | 21 | [4 - Getting Started](../../tree/ffefb5f9dfed4be24af4dca6fccbafcc33dd43be) 22 | 23 | [5 - Analytics, Session Keys, & IP Address Storage](../../tree/00cd5213ee75faf976c9804803cd4c38f7bd0de9) 24 | 25 | [6 - Custom Signal](../../tree/a7429fe2f48c27629c70d63daf2c9f4ed4acf21e) 26 | 27 | [7 - Built In Login View & Auth Form](../../tree/3b1eb0da6b8d6cf8ed08629930bbb3ff7a34672c) 28 | 29 | [8 - Setup Templates](../../tree/460d93311e251b99c535a2d35181a9abad421f7b) 30 | 31 | [9 - Send & Handle the Signal](../../tree/3bfcf05a50b753dd8be814f3f059cdccd0d70d12) 32 | 33 | [10 - Logout View](../../tree/93b108987957a4f9538931d9f2cb0dca95089926) 34 | 35 | [11 - Setup GeoIP2](../../tree/332f6b51e6bd67cce80d721ee45f49be57c7bed6) 36 | 37 | - **GeoLite2-city.mmdb** and **GeoLite2-country.mmdb** get the [binary downloads here](https://kirr.co/zq1ajh) 38 | 39 | [12 - Get IP Address & City Data](../../tree/a344582fb7043a72afd4def012b8188ad77db52a) 40 | 41 | [13 - Default IP Address & Model Manager](../../tree/e141bc61cdd6c341884cdecdd99e61b26503a8ac) 42 | 43 | [14 - Setup the Yelp API](../../tree/64f8a92f2af4eb6b73eb077a0c7b5872efe6e00e) 44 | 45 | [15 - Search into the API with Django](../../tree/399016a062d5d442f62d514f82aaa2b5bf6bcfb2) 46 | 47 | [16 - Handle Token Expiration](../../tree/f34e2ba58b11c8de8d03cf35cedd501134bc211e) 48 | 49 | [17 Google Maps API](../../tree/11030639e059f9d69155bf8434afe4eb92898c72) 50 | 51 | [18 - Multiple Markers on a Google Map](../../tree/d6914b992a51928e5e5f85b63242bb7c1a002a40) 52 | 53 | [19 - Click, Pan, and Zoom to Item in Google Map](../../tree/e28a8f8850874f47c52fef4ffe0eff0845d0b3f9) 54 | 55 | [20 - New Results on Map Move](../../tree/77ac14543e686edd963b8728992407a28f180462) 56 | -------------------------------------------------------------------------------- /backend/src/accounts/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codingforentrepreneurs/Geolocator-2/d4c2410301aa2497816e7ed2ec1890bc9be2e8fd/backend/src/accounts/__init__.py -------------------------------------------------------------------------------- /backend/src/accounts/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /backend/src/accounts/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class AccountsConfig(AppConfig): 5 | name = 'accounts' 6 | -------------------------------------------------------------------------------- /backend/src/accounts/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | from django.contrib.auth.forms import AuthenticationForm 3 | 4 | class LoginForm(AuthenticationForm): 5 | def confirm_login_allowed(self, user): 6 | if not user.is_active: 7 | raise forms.ValidationError('This account is inactive', code='inactive') 8 | 9 | -------------------------------------------------------------------------------- /backend/src/accounts/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codingforentrepreneurs/Geolocator-2/d4c2410301aa2497816e7ed2ec1890bc9be2e8fd/backend/src/accounts/migrations/__init__.py -------------------------------------------------------------------------------- /backend/src/accounts/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /backend/src/accounts/templates/registration/login.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block content %} 4 | 5 |
Your username and password didn't match. Please try again.
9 | {% endif %} 10 | 11 | 27 | 28 | 29 | {% endblock %} -------------------------------------------------------------------------------- /backend/src/accounts/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /backend/src/accounts/views.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth.views import LogoutView as DefaultLogoutView, LoginView as DefaultLoginView 2 | from django.shortcuts import render 3 | 4 | 5 | from analytics.signals import user_logged_in 6 | 7 | from .forms import LoginForm 8 | 9 | 10 | class LoginView(DefaultLoginView): # FormView 11 | authentication_form = LoginForm 12 | 13 | def form_valid(self, form): 14 | done_ = super(LoginView, self).form_valid(form) 15 | if self.request.user.is_authenticated(): 16 | user_logged_in.send(self.request.user, request=self.request) 17 | return done_ 18 | 19 | 20 | class LogoutView(DefaultLogoutView): 21 | pass -------------------------------------------------------------------------------- /backend/src/analytics/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codingforentrepreneurs/Geolocator-2/d4c2410301aa2497816e7ed2ec1890bc9be2e8fd/backend/src/analytics/__init__.py -------------------------------------------------------------------------------- /backend/src/analytics/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | from .models import UserSession 5 | 6 | admin.site.register(UserSession) -------------------------------------------------------------------------------- /backend/src/analytics/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class AnalyticsConfig(AppConfig): 5 | name = 'analytics' 6 | -------------------------------------------------------------------------------- /backend/src/analytics/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11 on 2017-04-27 16:52 3 | from __future__ import unicode_literals 4 | 5 | from django.conf import settings 6 | from django.db import migrations, models 7 | import django.db.models.deletion 8 | 9 | 10 | class Migration(migrations.Migration): 11 | 12 | initial = True 13 | 14 | dependencies = [ 15 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 16 | ] 17 | 18 | operations = [ 19 | migrations.CreateModel( 20 | name='UserSession', 21 | fields=[ 22 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 23 | ('session_key', models.CharField(blank=True, max_length=60, null=True)), 24 | ('ip_address', models.GenericIPAddressField(blank=True, null=True)), 25 | ('city_data', models.TextField(blank=True, null=True)), 26 | ('city', models.CharField(blank=True, max_length=120, null=True)), 27 | ('country', models.CharField(blank=True, max_length=120, null=True)), 28 | ('active', models.BooleanField(default=True)), 29 | ('timestamp', models.DateTimeField(auto_now_add=True)), 30 | ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), 31 | ], 32 | ), 33 | ] 34 | -------------------------------------------------------------------------------- /backend/src/analytics/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codingforentrepreneurs/Geolocator-2/d4c2410301aa2497816e7ed2ec1890bc9be2e8fd/backend/src/analytics/migrations/__init__.py -------------------------------------------------------------------------------- /backend/src/analytics/models.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.db import models 3 | 4 | from .signals import user_logged_in 5 | from .utils import get_client_city_data, get_client_ip 6 | 7 | 8 | class UserSessionManager(models.Manager): 9 | def create_new(self, user, session_key=None, ip_address=None, city_data=None): 10 | session_new = self.model() 11 | session_new.user = user 12 | session_new.session_key = session_key 13 | if ip_address is not None: 14 | session_new.ip_address = ip_address 15 | if city_data: 16 | session_new.city_data = city_data 17 | try: 18 | city = city_data['city'] 19 | except: 20 | city = None 21 | session_new.city = city 22 | try: 23 | country = city_data['country_name'] 24 | except: 25 | country = None 26 | session_new.country = country 27 | session_new.save() 28 | return session_new 29 | return None 30 | 31 | class UserSession(models.Model): 32 | user = models.ForeignKey(settings.AUTH_USER_MODEL) 33 | session_key = models.CharField(max_length=60, null=True, blank=True) 34 | ip_address = models.GenericIPAddressField(null=True, blank=True) 35 | city_data = models.TextField(null=True, blank=True) 36 | city = models.CharField(max_length=120, null=True, blank=True) 37 | country = models.CharField(max_length=120, null=True, blank=True) 38 | active = models.BooleanField(default=True) 39 | timestamp = models.DateTimeField(auto_now_add=True) 40 | 41 | objects = UserSessionManager() 42 | 43 | def __str__(self): 44 | city = self.city 45 | country = self.country 46 | if city and country: 47 | return f"{city}, {country}" 48 | elif city and not country: 49 | return f"{city}" 50 | elif country and not city: 51 | return f"{country}" 52 | return self.user.username 53 | 54 | 55 | def user_logged_in_receiver(sender, request, *args, **kwargs): 56 | user = sender 57 | ip_address = get_client_ip(request) 58 | city_data = get_client_city_data(ip_address) 59 | request.session['CITY'] = str(city_data.get('city', 'New York')) 60 | session_key = request.session.session_key 61 | UserSession.objects.create_new( 62 | user=user, 63 | session_key=session_key, 64 | ip_address=ip_address, 65 | city_data=city_data 66 | ) 67 | 68 | 69 | 70 | user_logged_in.connect(user_logged_in_receiver) -------------------------------------------------------------------------------- /backend/src/analytics/signals.py: -------------------------------------------------------------------------------- 1 | from django.dispatch import Signal 2 | 3 | 4 | user_logged_in = Signal(providing_args=['request']) -------------------------------------------------------------------------------- /backend/src/analytics/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /backend/src/analytics/utils.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.contrib.gis.geoip2 import GeoIP2 3 | 4 | GEO_DEFAULT_IP = getattr(settings, 'GEO_DEFAULT_IP', '72.14.207.99') 5 | 6 | def get_client_ip(request): 7 | x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') 8 | if x_forwarded_for is not None: 9 | ip = x_forwarded_for.split(',')[0] 10 | else: 11 | ip = request.META.get('REMOTE_ADDR') 12 | ip_address = ip or GEO_DEFAULT_IP 13 | if str(ip_address) == '127.0.0.1': 14 | ip_address = GEO_DEFAULT_IP 15 | return ip_address 16 | 17 | 18 | def get_client_city_data(ip_address): 19 | g = GeoIP2() 20 | try: 21 | return g.city(ip_address) 22 | except: 23 | return None -------------------------------------------------------------------------------- /backend/src/analytics/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | 3 | # Create your views here. 4 | -------------------------------------------------------------------------------- /backend/src/db.sqlite3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codingforentrepreneurs/Geolocator-2/d4c2410301aa2497816e7ed2ec1890bc9be2e8fd/backend/src/db.sqlite3 -------------------------------------------------------------------------------- /backend/src/geo2/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codingforentrepreneurs/Geolocator-2/d4c2410301aa2497816e7ed2ec1890bc9be2e8fd/backend/src/geo2/__init__.py -------------------------------------------------------------------------------- /backend/src/geo2/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for geo2 project. 3 | 4 | Generated by 'django-admin startproject' using Django 1.11. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.11/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/1.11/ref/settings/ 11 | """ 12 | 13 | import os 14 | 15 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 16 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 17 | 18 | 19 | # Quick-start development settings - unsuitable for production 20 | # See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/ 21 | 22 | # SECURITY WARNING: keep the secret key used in production secret! 23 | SECRET_KEY = 'qcy32l2m9g*+wzdur$v*c#4)ai222c%246*r&4eghn30(se19+' 24 | 25 | # SECURITY WARNING: don't run with debug turned on in production! 26 | DEBUG = True 27 | 28 | ALLOWED_HOSTS = [] 29 | 30 | 31 | GEOIP_PATH = os.path.join(BASE_DIR, 'geoip') 32 | 33 | YELP_CLIENT_ID = 'ZWcWfw0GR2iFNbSVrZtxyg' # os.environ.get('YELP_CLIENT_ID') 34 | YELP_CLIENT_SECRET = 'TATGfe5b9QUcd2ckuDxWUGH8f7YkDUeRe7cWlnYbwXNppOM8hdyhnTYSYakQCAKz' # os.environ.get('YELP_CLIENT_SECRET') 35 | GOOGLE_MAPS_API_KEY = 'AIzaSyAqOazqPcP8E-_s-Vp7MRbP3UMUgS2xfQw' 36 | 37 | LOGOUT_REDIRECT_URL = '/login/' 38 | LOGIN_REDIRECT_URL = '/' 39 | LOGIN_URL = '/login/' 40 | 41 | INSTALLED_APPS = [ 42 | 'django.contrib.admin', 43 | 'django.contrib.auth', 44 | 'django.contrib.contenttypes', 45 | 'django.contrib.sessions', 46 | 'django.contrib.messages', 47 | 'django.contrib.staticfiles', 48 | 'accounts', 49 | 'analytics', 50 | 'search', 51 | ] 52 | 53 | MIDDLEWARE = [ 54 | 'django.middleware.security.SecurityMiddleware', 55 | 'django.contrib.sessions.middleware.SessionMiddleware', 56 | 'django.middleware.common.CommonMiddleware', 57 | 'django.middleware.csrf.CsrfViewMiddleware', 58 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 59 | 'django.contrib.messages.middleware.MessageMiddleware', 60 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 61 | ] 62 | 63 | ROOT_URLCONF = 'geo2.urls' 64 | 65 | TEMPLATES = [ 66 | { 67 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 68 | 'DIRS': [os.path.join(BASE_DIR, 'templates')], 69 | 'APP_DIRS': True, 70 | 'OPTIONS': { 71 | 'context_processors': [ 72 | 'django.template.context_processors.debug', 73 | 'django.template.context_processors.request', 74 | 'django.contrib.auth.context_processors.auth', 75 | 'django.contrib.messages.context_processors.messages', 76 | ], 77 | }, 78 | }, 79 | ] 80 | 81 | WSGI_APPLICATION = 'geo2.wsgi.application' 82 | 83 | 84 | # Database 85 | # https://docs.djangoproject.com/en/1.11/ref/settings/#databases 86 | 87 | DATABASES = { 88 | 'default': { 89 | 'ENGINE': 'django.db.backends.sqlite3', 90 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 91 | } 92 | } 93 | 94 | 95 | # Password validation 96 | # https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators 97 | 98 | AUTH_PASSWORD_VALIDATORS = [ 99 | { 100 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 101 | }, 102 | { 103 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 104 | }, 105 | { 106 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 107 | }, 108 | { 109 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 110 | }, 111 | ] 112 | 113 | 114 | # Internationalization 115 | # https://docs.djangoproject.com/en/1.11/topics/i18n/ 116 | 117 | LANGUAGE_CODE = 'en-us' 118 | 119 | TIME_ZONE = 'UTC' 120 | 121 | USE_I18N = True 122 | 123 | USE_L10N = True 124 | 125 | USE_TZ = True 126 | 127 | 128 | # Static files (CSS, JavaScript, Images) 129 | # https://docs.djangoproject.com/en/1.11/howto/static-files/ 130 | 131 | STATIC_URL = '/static/' 132 | -------------------------------------------------------------------------------- /backend/src/geo2/urls.py: -------------------------------------------------------------------------------- 1 | """geo2 URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/1.11/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.conf.urls import url, include 14 | 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) 15 | """ 16 | from django.conf.urls import url 17 | from django.contrib import admin 18 | 19 | from accounts.views import LoginView, LogoutView 20 | from search.views import SearchView 21 | 22 | urlpatterns = [ 23 | url(r'^admin/', admin.site.urls), 24 | url(r'^login/$', LoginView.as_view(), name='login'), 25 | url(r'^logout/$', LogoutView.as_view(), name='logout'), 26 | url(r'^search/$', SearchView.as_view(), name='search'), 27 | ] 28 | -------------------------------------------------------------------------------- /backend/src/geo2/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for geo2 project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.11/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "geo2.settings") 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /backend/src/geoip/note.txt: -------------------------------------------------------------------------------- 1 | Download the binaries of 'GeoLite2-city.mmdb' and 'GeoLite2-country.mmdb' on https://kirr.co/zq1ajh 2 | 3 | Add them to the same directory where this note is. -------------------------------------------------------------------------------- /backend/src/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "geo2.settings") 7 | try: 8 | from django.core.management import execute_from_command_line 9 | except ImportError: 10 | # The above import may fail for some other reason. Ensure that the 11 | # issue is really that Django is missing to avoid masking other 12 | # exceptions on Python 2. 13 | try: 14 | import django 15 | except ImportError: 16 | raise ImportError( 17 | "Couldn't import Django. Are you sure it's installed and " 18 | "available on your PYTHONPATH environment variable? Did you " 19 | "forget to activate a virtual environment?" 20 | ) 21 | raise 22 | execute_from_command_line(sys.argv) 23 | -------------------------------------------------------------------------------- /backend/src/requirements.txt: -------------------------------------------------------------------------------- 1 | appdirs==1.4.3 2 | Django==1.11 3 | geoip2==2.4.2 4 | maxminddb==1.3.0 5 | packaging==16.8 6 | pyparsing==2.2.0 7 | pytz==2017.2 8 | requests==2.13.0 9 | six==1.10.0 10 | -------------------------------------------------------------------------------- /backend/src/search/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codingforentrepreneurs/Geolocator-2/d4c2410301aa2497816e7ed2ec1890bc9be2e8fd/backend/src/search/__init__.py -------------------------------------------------------------------------------- /backend/src/search/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /backend/src/search/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class SearchConfig(AppConfig): 5 | name = 'search' 6 | -------------------------------------------------------------------------------- /backend/src/search/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codingforentrepreneurs/Geolocator-2/d4c2410301aa2497816e7ed2ec1890bc9be2e8fd/backend/src/search/migrations/__init__.py -------------------------------------------------------------------------------- /backend/src/search/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /backend/src/search/templates/search/home.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block content %} 4 |