Skip to content

Commit

Permalink
Merge pull request #198 from rkshaon/125-add-traffic-record-feature
Browse files Browse the repository at this point in the history
done: #125 - traffic record
  • Loading branch information
rkshaon authored Dec 13, 2024
2 parents 7f326b9 + 3594881 commit c1c7874
Show file tree
Hide file tree
Showing 18 changed files with 268 additions and 25 deletions.
16 changes: 16 additions & 0 deletions backend/BookShelf/global_variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,19 @@
('tablet', 'Tablet'),
('pc', 'PC'),
)

OBJECT_TYPE = [
('book', 'Book'),
('author', 'Author'),
('publisher', 'Publisher'),
('genre', 'Genre'),
('topic', 'Topic'),
]


EVENT_TYPE = [
('retrieve', 'Retrieve'),
('create', 'Create'),
('update', 'Update'),
('delete', 'Delete'),
]
18 changes: 18 additions & 0 deletions backend/activity_api/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from activity_api.models import Device
from activity_api.models import ActivityLog
from activity_api.models import EventLog


@admin.register(Device)
Expand Down Expand Up @@ -38,3 +39,20 @@ class ActivityLogAdmin(admin.ModelAdmin):
)
list_filter = []
date_hierarchy = 'activity_time'


@admin.register(EventLog)
class EventLogAdmin(admin.ModelAdmin):
list_display = [
'id', 'event', 'object', 'user', 'device', 'added_date_time',
]
list_per_page = 10
list_display_links = (
'user', 'device',
)
search_fields = ()
readonly_fields = (
'id', 'added_date_time',
)
list_filter = []
date_hierarchy = 'added_date_time'
1 change: 1 addition & 0 deletions backend/activity_api/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
class ActivityApiConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'activity_api'
verbose_name = 'Activity'
6 changes: 6 additions & 0 deletions backend/activity_api/decorators/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from activity_api.decorators.event import event_logger


__all__ = [
event_logger,
]
Empty file.
33 changes: 33 additions & 0 deletions backend/activity_api/migrations/0006_eventlog.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Generated by Django 5.1.1 on 2024-12-13 06:02

import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('activity_api', '0005_alter_activitylog_user_agent'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

operations = [
migrations.CreateModel(
name='EventLog',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('ip_address', models.GenericIPAddressField(blank=True, null=True, verbose_name='IP Address')),
('object', models.CharField(choices=[('book', 'Book'), ('author', 'Author'), ('publisher', 'Publisher'), ('genre', 'Genre'), ('topic', 'Topic')], max_length=10)),
('event', models.CharField(choices=[('retrieve', 'Retrieve'), ('create', 'Create'), ('update', 'Update'), ('delete', 'Delete')], max_length=10)),
('data', models.JSONField(blank=True, null=True)),
('added_date_time', models.DateTimeField(auto_now_add=True)),
('device', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='activity_api.device')),
('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': 'Event Log',
'verbose_name_plural': 'Event Logs',
},
),
]
41 changes: 41 additions & 0 deletions backend/activity_api/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
from user_api.models import User

from BookShelf.global_variables import DEVICE_TYPE
from BookShelf.global_variables import OBJECT_TYPE
from BookShelf.global_variables import EVENT_TYPE


class Device(models.Model):
Expand Down Expand Up @@ -93,3 +95,42 @@ class Meta:
def __str__(self):
user_info = f"User: {self.user}" if self.user else "Anonymous"
return f"{user_info} - {self.method} - {self.path} - {self.timestamp}"


class EventLog(models.Model):
user = models.ForeignKey(
User,
null=True,
blank=True,
on_delete=models.SET_NULL,
)
device = models.ForeignKey(
Device,
null=True,
blank=True,
on_delete=models.SET_NULL,
)
ip_address = models.GenericIPAddressField(
_('IP Address'),
null=True,
blank=True
)
object = models.CharField(
max_length=10,
choices=OBJECT_TYPE
)
event = models.CharField(
max_length=10,
choices=EVENT_TYPE
)
data = models.JSONField(null=True, blank=True)
added_date_time = models.DateTimeField(auto_now_add=True)

class Meta:
verbose_name = _('Event Log')
verbose_name_plural = _('Event Logs')

def __str__(self):
user_info = f"User: {self.user}" if self.user else "Anonymous"
details = f"{self.object} - {self.event}"
return f"{user_info} - {details} - {self.added_date_time}"
23 changes: 23 additions & 0 deletions backend/activity_api/utilities/event.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from activity_api.models import EventLog


def event_logger(
event,
object,
user,
device,
ip_address,
data=None,
) -> None:
if user.is_anonymous:
user = None

EventLog.objects.create(
event=event,
object=object,
user=user,
device=device,
ip_address=ip_address,
data=data,
)
return None
3 changes: 0 additions & 3 deletions backend/activity_api/views.py
Original file line number Diff line number Diff line change
@@ -1,3 +0,0 @@
from django.shortcuts import render

# Create your views here.
1 change: 1 addition & 0 deletions backend/author_api/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
class AuthorApiConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'author_api'
verbose_name = 'Author'

def ready(self):
# from author_api import signals # noqa
Expand Down
21 changes: 21 additions & 0 deletions backend/author_api/views/v1.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from BookShelf.utilities.pagination import Pagination
from BookShelf.utilities.permissions import IsAdminOrModerator
from BookShelf.utilities.filters import SearchFilter
from activity_api.utilities.event import event_logger

from author_api.models import Author

Expand All @@ -36,6 +37,18 @@ def get(self, request, *args, **kwargs):
except Author.DoesNotExist:
raise NotFound(detail='Author not found.')

event_logger(
event='retrieve',
object='author',
user=request.user,
device=request.device,
ip_address=request.ip_address,
data={
'model': 'Author',
'id': author.id
}
)

return Response(
AuthorSerializer(
author, context={'include_books': True}
Expand All @@ -55,6 +68,14 @@ def get(self, request, *args, **kwargs):
page = paginator.paginate_queryset(authors, request)
serializer = AuthorSerializer(page, many=True)

event_logger(
event='retrieve',
object='author',
user=request.user,
device=request.device,
ip_address=request.ip_address,
)

return paginator.get_paginated_response(serializer.data)

def post(self, request, *args, **kwargs):
Expand Down
1 change: 1 addition & 0 deletions backend/book_api/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
class BookApiConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'book_api'
verbose_name = 'Book'

def ready(self) -> None:
import book_api.signals # noqa
Expand Down
22 changes: 22 additions & 0 deletions backend/book_api/views/v1/book.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from BookShelf.utilities.pagination import Pagination
from BookShelf.utilities.permissions import IsAdminOrModerator
from activity_api.utilities.event import event_logger

from book_api.models import Book

Expand All @@ -29,6 +30,18 @@ def get(self, request, *args, **kwargs):
except Book.DoesNotExist:
raise NotFound(detail="Book not found.")

event_logger(
event='retrieve',
object='book',
user=request.user,
device=request.device,
ip_address=request.ip_address,
data={
'model': 'Book',
'id': book.id
}
)

return Response(BookSerializer(book).data)

books = Book.objects.filter(
Expand All @@ -44,6 +57,15 @@ def get(self, request, *args, **kwargs):
books = books.order_by('-id')
paginator = Pagination()
page = paginator.paginate_queryset(books, request)

event_logger(
event='retrieve',
object='book',
user=request.user,
device=request.device,
ip_address=request.ip_address,
)

return paginator.get_paginated_response(
BookSerializer(page, many=True).data
)
Expand Down
50 changes: 28 additions & 22 deletions backend/book_api/views/v1/genre.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from BookShelf.utilities.permissions import IsAdminOrModerator
from BookShelf.utilities.filters import SearchFilter
from activity_api.utilities.event import event_logger

from book_api.models import Genre

Expand Down Expand Up @@ -37,28 +38,33 @@ def destroy(self, request, *args, **kwargs):
status=status.HTTP_200_OK,
)

# @method_decorator(cache_page(60*15), name='get')
# class GenreView(APIView):
# permission_classes = [AllowAny]

# def get(self, request, *args, **kwargs):
# pk = kwargs.get('pk', None)
def retrieve(self, request, *args, **kwargs):
"""Log the event when retrieving a single item."""
response = super().retrieve(request, *args, **kwargs)
instance = self.get_object()
event_logger(
event='retrieve',
object='genre',
user=request.user,
device=request.device,
ip_address=request.ip_address,
data={
'model': 'Genre',
'id': instance.id
}
)

# if pk:
# try:
# genre = Genre.objects.get(
# pk=pk, is_deleted=False
# )
# except Genre.DoesNotExist:
# raise NotFound(detail='Genre not found.')
return response

# return Response(GenreSerializer(genre).data)
def list(self, request, *args, **kwargs):
"""Log the event when retrieving a list of items."""
response = super().list(request, *args, **kwargs)
event_logger(
event='retrieve',
object='genre',
user=request.user,
device=request.device,
ip_address=request.ip_address,
)

# genres = Genre.objects.filter(
# is_deleted=False
# ).order_by('-id')
# paginator = Pagination()
# page = paginator.paginate_queryset(genres, request)
# return paginator.get_paginated_response(
# GenreSerializer(page, many=True).data
# )
return response
28 changes: 28 additions & 0 deletions backend/book_api/views/v1/topic.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from BookShelf.utilities.permissions import IsAdminOrModerator
from BookShelf.utilities.filters import SearchFilter
from activity_api.utilities.event import event_logger

from book_api.models import Topic

Expand Down Expand Up @@ -36,3 +37,30 @@ def destroy(self, request, *args, **kwargs):
{"message": f"Topic '{instance.name}' has been successfully deleted."}, # noqa
status=status.HTTP_200_OK,
)

def retrieve(self, request, *args, **kwargs):
response = super().retrieve(request, *args, **kwargs)
instance = self.get_object()
event_logger(
event='retrieve',
object='topic',
user=request.user,
device=request.device,
ip_address=request.ip_address,
data={
'model': 'Topic',
'id': instance.id
}
)
return response

def list(self, request, *args, **kwargs):
response = super().list(request, *args, **kwargs)
event_logger(
event='retrieve',
object='topic',
user=request.user,
device=request.device,
ip_address=request.ip_address,
)
return response
1 change: 1 addition & 0 deletions backend/publisher_api/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
class PublisherApiConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'publisher_api'
verbose_name = 'Publisher'
Loading

0 comments on commit c1c7874

Please sign in to comment.