Skip to content

Commit

Permalink
Renamed request log, added new files log/access record feature
Browse files Browse the repository at this point in the history
  • Loading branch information
RineshRamadhin committed Mar 23, 2022
1 parent 34930dc commit 064d96c
Show file tree
Hide file tree
Showing 9 changed files with 113 additions and 13 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ files

# Editor directories and files
.idea
docker-compose.override.yml
2 changes: 1 addition & 1 deletion config/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@


# Build information of the Web DL API
VERSION = '2.19.0'
VERSION = '2.20.0'
REPOSITORY = 'https://github.com/web-dl-tools/api.git'

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
Expand Down
8 changes: 8 additions & 0 deletions docker-compose.override.yml.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
version: '3.8'

services:
adminer:
image: adminer
restart: always
ports:
- 8002:8080
4 changes: 2 additions & 2 deletions src/download/loggers.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"""
import logging

from .models import BaseRequest, Log
from .models import BaseRequest, RequestLog


class BaseLogger(logging.Logger):
Expand Down Expand Up @@ -56,7 +56,7 @@ def makeRecord(
:return: *
"""
if msg:
Log.objects.create(request=self.request, level=level, message=msg.strip())
RequestLog.objects.create(request=self.request, level=level, message=msg.strip())
return super().makeRecord(
name, level, fn, lno, msg, args, exc_info, func, extra, sinfo
)
35 changes: 35 additions & 0 deletions src/download/migrations/0004_auto_20220323_2016.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Generated by Django 3.2.11 on 2022-03-23 19:16

from django.db import migrations, models
import django.db.models.deletion
import uuid


class Migration(migrations.Migration):

dependencies = [
('download', '0003_auto_20210521_1725'),
]

operations = [
migrations.RenameModel(
old_name='Log',
new_name='RequestLog',
),
migrations.AlterModelTable(
name='requestlog',
table='request_log',
),
migrations.CreateModel(
name='FilesLog',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False, verbose_name='id')),
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='created at')),
('path', models.TextField(verbose_name='path')),
('request', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='download.baserequest', verbose_name='request')),
],
options={
'db_table': 'files_log',
},
),
]
39 changes: 38 additions & 1 deletion src/download/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
This file contains the model object definitions for the polymorphic BaseRequest and custom Log object.
"""
import abc
import os

from typing import Type
from polymorphic.models import PolymorphicModel
Expand Down Expand Up @@ -204,7 +205,7 @@ def get_handler_object() -> "Type[src.download.handlers.BaseHandler]":
pass


class Log(CreatedAtMixin, IdMixin):
class RequestLog(CreatedAtMixin, IdMixin):
"""
A request log model object for storing logging data from the associated BaseHandler when handling the request.
"""
Expand Down Expand Up @@ -235,6 +236,14 @@ class Log(CreatedAtMixin, IdMixin):
level = models.IntegerField(_("level"), choices=LEVELS, default=LEVEL_NOTSET)
message = models.TextField(_("message"), blank=False)

class Meta:
"""
Model metadata.
See https://docs.djangoproject.com/en/3.0/ref/models/options/
"""

db_table = "request_log"

@property
def level_display(self) -> str:
"""
Expand All @@ -243,3 +252,31 @@ def level_display(self) -> str:
:return: A str containing the status display value.
"""
return self.get_level_display()


class FilesLog(CreatedAtMixin, IdMixin):
"""
A files log model object for storing downloading/access data from the associated files of the request.
"""

request = models.ForeignKey(
BaseRequest, verbose_name=_("request"), on_delete=models.CASCADE
)
path = models.TextField(_("path"), blank=False)

class Meta:
"""
Model metadata.
See https://docs.djangoproject.com/en/3.0/ref/models/options/
"""

db_table = "files_log"

@property
def filename(self) -> str:
"""
Get the filename from the file path.
:return: A str containing the filename and extension.
"""
return os.path.basename(self.path)
8 changes: 4 additions & 4 deletions src/download/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from rest_framework import serializers
from rest_polymorphic.serializers import PolymorphicSerializer

from .models import BaseRequest, Log
from .models import BaseRequest, RequestLog


class BaseRequestSerializer(serializers.ModelSerializer):
Expand Down Expand Up @@ -108,9 +108,9 @@ class PolymorphicRequestSerializer(PolymorphicSerializer):
}


class LogSerializer(serializers.ModelSerializer):
class RequestLogSerializer(serializers.ModelSerializer):
"""
A log serializer for the request Log model object.
A request log serializer for the request Log model object.
"""

class Meta:
Expand All @@ -119,5 +119,5 @@ class Meta:
See https://www.django-rest-framework.org/api-guide/serializers/
"""

model = Log
model = RequestLog
fields = ("id", "created_at", "level", "level_display", "message")
21 changes: 19 additions & 2 deletions src/download/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from django.http import FileResponse

from src.user.models import User
from .models import BaseRequest
from .models import BaseRequest, FilesLog


def calculate_storage(path: str) -> int:
Expand Down Expand Up @@ -158,6 +158,23 @@ def validate_for_archive(path: str, user: User) -> bool:
return True


def get_request(path: str) -> BaseRequest:
"""
Get the request entity from a file path. Make sure the filepath is validated before using this method.
:param path: A str containing the relative file path.
:return: A BaseRequest entity containing the linked request.
"""
return BaseRequest.objects.get(id=path.split("/")[2])


def log_file_access(path: str) -> None:
"""
:param path: A str containing the relative file path.
"""
FilesLog.objects.create(request=get_request(path), path=path)


def create_file_streaming_response(path: str) -> FileResponse:
"""
Create a streaming file response to serve the file while
Expand All @@ -167,7 +184,7 @@ def create_file_streaming_response(path: str) -> FileResponse:
the file size exceeds a given limit, else it is up to the
client to decide how to process and view the file.
:param path: A str containing the file path.
:param path: A str containing the relative file path.
:return: A FileResponse containing a streaming file.
"""
filename = os.path.basename(path)
Expand Down
8 changes: 5 additions & 3 deletions src/download/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@
from rest_framework.views import APIView

from .models import BaseRequest
from .serializers import PolymorphicRequestSerializer, LogSerializer
from .serializers import PolymorphicRequestSerializer, RequestLogSerializer
from .tasks import download_request, compress_request
from .utils import list_files, prepare_path, validate_for_request, validate_for_archive, create_file_streaming_response
from .utils import list_files, prepare_path, validate_for_request, validate_for_archive, log_file_access,\
create_file_streaming_response
from src.auth_token.authentication import CookieTokenAuthentication


Expand Down Expand Up @@ -79,7 +80,7 @@ def logs(self, request, pk=None) -> Response:
:return: Response
"""
request_object = self.get_object()
return Response(LogSerializer(request_object.log_set, many=True).data)
return Response(RequestLogSerializer(request_object.requestlog_set, many=True).data)

@action(detail=True)
def files(self, request, pk=None) -> Response:
Expand Down Expand Up @@ -153,6 +154,7 @@ def get(self, request, path, *args, **kwargs):
path = prepare_path(path)

if validate_for_request(path, self.request.user) or validate_for_archive(path, self.request.user):
log_file_access(path)
return create_file_streaming_response(path)

return Response(status=403, data="You're not authorized to access this resource or the resource doesn't exist.")

0 comments on commit 064d96c

Please sign in to comment.