Browse Source

feat: user-location

master
alireza 1 year ago
parent
commit
7a22cf99e3
  1. 1
      apps/account/admin/__init__.py
  2. 58
      apps/account/admin/location.py
  3. 4
      apps/account/admin/user.py
  4. 30
      apps/account/migrations/0003_locationhistory.py
  5. 13
      apps/account/models/user.py
  6. 1
      apps/account/serializers/__init__.py
  7. 10
      apps/account/serializers/location_history.py
  8. 1
      apps/account/urls.py
  9. 1
      apps/account/views/__init__.py
  10. 36
      apps/account/views/location_history.py
  11. 4
      sshs

1
apps/account/admin/__init__.py

@ -4,6 +4,7 @@ from django.template.loader import render_to_string
from .user import *
from .professor import *
from .student import *
from .location import *
@register_component

58
apps/account/admin/location.py

@ -0,0 +1,58 @@
from django.contrib import admin
from django.utils.translation import gettext_lazy as _
from unfold.admin import ModelAdmin, TabularInline
from unfold.decorators import display
from unfold.contrib.filters.admin import (
RangeDateTimeFilter,
TextFilter,
AutocompleteSelectFilter,
)
from apps.account.models import LocationHistory, User
from utils.admin import project_admin_site
class LocationHistoryInline(TabularInline):
model = LocationHistory
extra = 0
tab = True
fields = ('lat', 'lon', 'country', 'city', 'selected_manually', 'ip', 'timezone', 'at_time')
readonly_fields = ('lat', 'lon', 'country', 'city', 'selected_manually', 'ip', 'timezone', 'at_time',)
verbose_name = _("Location History")
verbose_name_plural = _("Location History")
can_delete = False
show_change_link = True
class LocationHistoryAdmin(ModelAdmin):
list_display = ('user', 'display_location', 'country', 'city', 'selected_manually', 'ip', 'display_at_time')
list_filter = [
('user', AutocompleteSelectFilter),
'country',
'city',
'selected_manually',
('at_time', RangeDateTimeFilter),
]
search_fields = ('user__email', 'user__fullname', 'country', 'city', 'ip')
readonly_fields = ('at_time',)
fieldsets = (
(None, {
'fields': ('user', ('lat', 'lon'), ('country', 'city'))
}),
(_('Additional Information'), {
'fields': ('selected_manually', 'ip', 'timezone', 'at_time'),
'classes': ('tab',),
}),
)
@display(description=_("Location"))
def display_location(self, instance: LocationHistory):
return f"{instance.lat}, {instance.lon}"
@display(description=_("Date & Time"))
def display_at_time(self, instance: LocationHistory):
return instance.at_time.strftime("%Y-%m-%d %H:%M") if instance.at_time else "-"
# Register with project admin site
project_admin_site.register(LocationHistory, LocationHistoryAdmin)

4
apps/account/admin/user.py

@ -7,7 +7,7 @@ from django.utils.translation import gettext_lazy as _
from rest_framework.authtoken.models import TokenProxy
from ajaxdatatable.admin import AjaxDatatable
from apps.account.models import User, Notification
from apps.account.models import User, Notification, LocationHistory
from django import forms
from django.contrib import admin
from django.urls import path, reverse
@ -34,6 +34,7 @@ from unfold.contrib.filters.admin import (
SingleNumericFilter,
TextFilter,
)
from apps.account.admin.location import LocationHistoryInline
@ -56,6 +57,7 @@ class UserAdmin(BaseUserAdmin, ModelAdmin):
("last_login", RangeDateTimeFilter),
("date_joined", RangeDateTimeFilter),
]
inlines = [LocationHistoryInline]
add_fieldsets = (
(None, {
'classes': ('wide',),

30
apps/account/migrations/0003_locationhistory.py

@ -0,0 +1,30 @@
# Generated by Django 5.1.8 on 2025-05-01 15:54
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('account', '0002_alter_user_phone_number'),
]
operations = [
migrations.CreateModel(
name='LocationHistory',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('lat', models.FloatField(verbose_name='lat')),
('lon', models.FloatField(verbose_name='lon')),
('country', models.CharField(blank=True, max_length=255, null=True, verbose_name='country')),
('city', models.CharField(blank=True, max_length=255, null=True, verbose_name='city')),
('selected_manually', models.BooleanField(blank=True, null=True)),
('ip', models.CharField(blank=True, max_length=255, null=True)),
('timezone', models.CharField(blank=True, max_length=60, null=True)),
('at_time', models.DateTimeField(auto_now_add=True)),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='location_history', to=settings.AUTH_USER_MODEL)),
],
),
]

13
apps/account/models/user.py

@ -123,3 +123,16 @@ class LoginHistory(models.Model):
ip = models.CharField(max_length=255, null=True)
timezone = models.CharField(max_length=100, null=True, blank=True)
at_time = models.DateTimeField(auto_now_add=True)
class LocationHistory(models.Model):
user = models.ForeignKey("account.User", on_delete=models.CASCADE, related_name='location_history')
lat = models.FloatField(verbose_name=_('lat'))
lon = models.FloatField(verbose_name=_('lon'))
country = models.CharField(max_length=255, verbose_name=_('country'), null=True, blank=True)
city = models.CharField(max_length=255, verbose_name=_('city'), null=True, blank=True)
selected_manually = models.BooleanField(null=True, blank=True)
ip = models.CharField(max_length=255, null=True, blank=True)
timezone = models.CharField(null=True, blank=True, max_length=60)
at_time = models.DateTimeField(auto_now_add=True)

1
apps/account/serializers/__init__.py

@ -1,2 +1,3 @@
from .user import *
from .notification import *
from .location_history import *

10
apps/account/serializers/location_history.py

@ -0,0 +1,10 @@
from rest_framework import serializers
from apps.account.models import LocationHistory
class LocationHistorySerializer(serializers.ModelSerializer):
user = serializers.HiddenField(default=serializers.CurrentUserDefault())
class Meta:
model = LocationHistory
exclude = ('at_time',)

1
apps/account/urls.py

@ -14,6 +14,7 @@ urlpatterns = [
path('verify/', views.UserVerifyView.as_view(), name='user-verify'),
path('login/', views.UserLoginView.as_view(), name='user-login'),
path('guest/', views.UserGuestView.as_view(), name='user-guest'),
path('location-update/', views.LocationHistoryView.as_view(), name='user-location-history'),
# path('notif/', views.NotificationListView.as_view(), name='user-notif'),

1
apps/account/views/__init__.py

@ -1,4 +1,5 @@
from .user import *
from .notification import *
from .location_history import *

36
apps/account/views/location_history.py

@ -0,0 +1,36 @@
from rest_framework.mixins import CreateModelMixin
from rest_framework.permissions import IsAuthenticated
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
from rest_framework import status
from apps.account.models import LocationHistory
from apps.account.serializers import LocationHistorySerializer
class LocationHistoryView(GenericAPIView, CreateModelMixin):
permission_classes = [IsAuthenticated]
serializer_class = LocationHistorySerializer
def post(self, request, *args, **kwargs):
ip = self.get_client_ip()
data = request.data.copy()
data['ip'] = ip
serializer = self.get_serializer(data=data)
if serializer.is_valid():
serializer.save(user=request.user)
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def get_queryset(self):
return LocationHistory.objects.filter(user=self.request.user)
def get_client_ip(self):
# Retrieve the client's IP address from the request headers
x_forwarded_for = self.request.META.get('HTTP_X_FORWARDED_FOR')
if x_forwarded_for:
ip = x_forwarded_for.split(',')[0]
else:
ip = self.request.META.get('REMOTE_ADDR')
return ip

4
sshs

@ -1,3 +1,7 @@
Host 62.60.197.179
HostName 62.60.197.179
User ubuntu
Host 88.99.212.243
HostName 88.99.212.243
User nwhco
Loading…
Cancel
Save