Skip to content

Commit

Permalink
Add custom SecureFileField class in FileField.
Browse files Browse the repository at this point in the history
  • Loading branch information
Rup-Narayan-Rajbanshi committed Sep 10, 2024
1 parent 5cd19b3 commit 1986d35
Show file tree
Hide file tree
Showing 14 changed files with 197 additions and 71 deletions.
30 changes: 30 additions & 0 deletions api/migrations/0214_alter_generaldocument_document_and_more.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Generated by Django 4.2.15 on 2024-09-10 10:12

from django.db import migrations

import api.models
import main.base_class


class Migration(migrations.Migration):

dependencies = [
("api", "0213_merge_20240807_1001"),
]

operations = [
migrations.AlterField(
model_name="generaldocument",
name="document",
field=main.base_class.SecureFileField(
blank=True, null=True, upload_to=api.models.general_document_path, verbose_name="document"
),
),
migrations.AlterField(
model_name="situationreport",
name="document",
field=main.base_class.SecureFileField(
blank=True, null=True, upload_to=api.models.sitrep_document_path, verbose_name="document"
),
),
]
6 changes: 4 additions & 2 deletions api/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
from django.utils.translation import gettext_lazy as _
from tinymce.models import HTMLField

from main.base_class import SecureFileField

from .utils import validate_slug_number # is_user_ifrc,


Expand Down Expand Up @@ -984,7 +986,7 @@ def sitrep_document_path(instance, filename):
class SituationReport(models.Model):
created_at = models.DateTimeField(verbose_name=_("created at"), auto_now_add=True)
name = models.CharField(verbose_name=_("name"), max_length=100)
document = models.FileField(verbose_name=_("document"), null=True, blank=True, upload_to=sitrep_document_path)
document = SecureFileField(verbose_name=_("document"), null=True, blank=True, upload_to=sitrep_document_path)
document_url = models.URLField(verbose_name=_("document url"), blank=True)

event = models.ForeignKey(Event, verbose_name=_("event"), on_delete=models.CASCADE)
Expand Down Expand Up @@ -1287,7 +1289,7 @@ class GeneralDocument(models.Model):
name = models.CharField(verbose_name=_("name"), max_length=100)
# Don't set `auto_now_add` so we can modify it on save
created_at = models.DateTimeField(verbose_name=_("created at"), blank=True)
document = models.FileField(verbose_name=_("document"), null=True, blank=True, upload_to=general_document_path)
document = SecureFileField(verbose_name=_("document"), null=True, blank=True, upload_to=general_document_path)
document_url = models.URLField(verbose_name=_("document url"), blank=True)

class Meta:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Generated by Django 4.2.15 on 2024-09-10 10:12

import django.core.validators
from django.db import migrations

import country_plan.models
import main.base_class


class Migration(migrations.Migration):

dependencies = [
("country_plan", "0007_alter_membershipcoordination_sector_and_more"),
]

operations = [
migrations.AlterField(
model_name="countryplan",
name="internal_plan_file",
field=main.base_class.SecureFileField(
blank=True,
null=True,
upload_to=country_plan.models.pdf_upload_to,
validators=[django.core.validators.FileExtensionValidator(["pdf"])],
verbose_name="Internal Plan",
),
),
]
3 changes: 2 additions & 1 deletion country_plan/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from django.utils.translation import gettext_lazy as _

from api.models import Country
from main.base_class import SecureFileField


def file_upload_to(instance, filename):
Expand Down Expand Up @@ -63,7 +64,7 @@ def save(self, *args, **kwargs):

class CountryPlan(CountryPlanAbstract):
country = models.OneToOneField(Country, on_delete=models.CASCADE, related_name="country_plan", primary_key=True)
internal_plan_file = models.FileField(
internal_plan_file = SecureFileField(
verbose_name=_("Internal Plan"),
upload_to=pdf_upload_to,
validators=[FileExtensionValidator(["pdf"])],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Generated by Django 4.2.15 on 2024-09-10 10:12

from django.db import migrations

import main.base_class


class Migration(migrations.Migration):

dependencies = [
("dref", "0074_auto_20240129_0909"),
]

operations = [
migrations.AlterField(
model_name="dref",
name="budget_file_preview",
field=main.base_class.SecureFileField(
blank=True, null=True, upload_to="dref/images/", verbose_name="budget file preview"
),
),
migrations.AlterField(
model_name="dreffile",
name="file",
field=main.base_class.SecureFileField(upload_to="dref/images/", verbose_name="file"),
),
migrations.AlterField(
model_name="dreffinalreport",
name="financial_report_preview",
field=main.base_class.SecureFileField(
blank=True, null=True, upload_to="dref/images/", verbose_name="financial preview"
),
),
migrations.AlterField(
model_name="drefoperationalupdate",
name="budget_file_preview",
field=main.base_class.SecureFileField(
blank=True, null=True, upload_to="dref-op-update/images/", verbose_name="budget file preview"
),
),
]
9 changes: 5 additions & 4 deletions dref/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from pdf2image import convert_from_bytes

from api.models import Country, DisasterType, District, FieldReport
from main.base_class import SecureFileField


@reversion.register()
Expand Down Expand Up @@ -536,7 +537,7 @@ class Status(models.IntegerChoices):
verbose_name=_("budget file"),
related_name="budget_file_dref",
)
budget_file_preview = models.FileField(verbose_name=_("budget file preview"), null=True, blank=True, upload_to="dref/images/")
budget_file_preview = SecureFileField(verbose_name=_("budget file preview"), null=True, blank=True, upload_to="dref/images/")
assessment_report = models.ForeignKey(
"DrefFile",
on_delete=models.SET_NULL,
Expand Down Expand Up @@ -648,7 +649,7 @@ def get_for(user):


class DrefFile(models.Model):
file = models.FileField(
file = SecureFileField(
verbose_name=_("file"),
upload_to="dref/images/",
)
Expand Down Expand Up @@ -750,7 +751,7 @@ class DrefOperationalUpdate(models.Model):
verbose_name=_("budget file"),
related_name="budget_file_dref_operational_update",
)
budget_file_preview = models.FileField(
budget_file_preview = SecureFileField(
verbose_name=_("budget file preview"), null=True, blank=True, upload_to="dref-op-update/images/"
)
assessment_report = models.ForeignKey(
Expand Down Expand Up @@ -1316,7 +1317,7 @@ class DrefFinalReport(models.Model):
verbose_name=_("financial report"),
related_name="financial_report_dref_final_report",
)
financial_report_preview = models.FileField(
financial_report_preview = SecureFileField(
verbose_name=_("financial preview"), null=True, blank=True, upload_to="dref/images/"
)
num_assisted = models.IntegerField(verbose_name=_("number of assisted"), blank=True, null=True)
Expand Down
19 changes: 0 additions & 19 deletions flash_update/migrations/0013_alter_flashgraphicmap_file.py

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Generated by Django 4.2.15 on 2024-09-10 10:12

from django.db import migrations

import main.base_class


class Migration(migrations.Migration):

dependencies = [
("flash_update", "0012_auto_20230410_0720"),
]

operations = [
migrations.AlterField(
model_name="flashgraphicmap",
name="file",
field=main.base_class.SecureFileField(upload_to="flash_update/images", verbose_name="file"),
),
migrations.AlterField(
model_name="flashupdate",
name="extracted_file",
field=main.base_class.SecureFileField(
blank=True, null=True, upload_to="flash_update/pdf/", verbose_name="extracted file"
),
),
]
19 changes: 0 additions & 19 deletions flash_update/migrations/0014_alter_flashupdate_extracted_file.py

This file was deleted.

11 changes: 3 additions & 8 deletions flash_update/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
from django.utils.translation import gettext_lazy as _
from tinymce.models import HTMLField

from main.utils import custom_upload_to
from api.models import (
ActionCategory,
ActionOrg,
Expand All @@ -17,16 +16,12 @@
DisasterType,
District,
)
from main.base_class import SecureFileField

def flash_map_upload_to(instance, filename):
return custom_upload_to('flash_update/images/')(instance, filename)

def flash_extracted_file_upload_to(instance, filename):
return custom_upload_to('flash_update/pdf/')(instance, filename)

@reversion.register()
class FlashGraphicMap(models.Model):
file = models.FileField(verbose_name=_("file"), upload_to=flash_map_upload_to)
file = SecureFileField(verbose_name=_("file"), upload_to="flash_update/images")
caption = models.CharField(max_length=225, blank=True, null=True)
created_by = models.ForeignKey(
settings.AUTH_USER_MODEL,
Expand Down Expand Up @@ -124,7 +119,7 @@ class FlashShareWith(models.TextChoices):
verbose_name=_("share with"),
)
references = models.ManyToManyField(FlashReferences, blank=True, verbose_name=_("references"))
extracted_file = models.FileField(verbose_name=_("extracted file"), upload_to=flash_extracted_file_upload_to, blank=True, null=True)
extracted_file = SecureFileField(verbose_name=_("extracted file"), upload_to="flash_update/pdf/", blank=True, null=True)
extracted_at = models.DateTimeField(verbose_name=_("extracted at"), blank=True, null=True)

class Meta:
Expand Down
29 changes: 29 additions & 0 deletions main/base_class.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import datetime
import posixpath
from uuid import uuid4

from django.core.files.utils import validate_file_name
from django.db.models.fields.files import FileField


class SecureFileField(FileField):
def generate_filename(self, instance, filename):
"""
Apply (if callable) or prepend (if a string) upload_to to the filename,
then delegate further processing of the name to the storage backend.
Until the storage layer, all file paths are expected to be Unix style
(with forward slashes).
"""
extension = filename.split(".")[-1]
old_file_name = filename.split(".")[0]
# Create a unique filename using uuid4
filename = f"{old_file_name}-{uuid4().hex}.{extension}"

if callable(self.upload_to):
filename = self.upload_to(instance, filename)
else:
dirname = datetime.datetime.now().strftime(str(self.upload_to))
filename = posixpath.join(dirname, filename)
filename = validate_file_name(filename, allow_relative_path=True)

return self.storage.generate_filename(filename)
16 changes: 0 additions & 16 deletions main/utils.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import os
import datetime
import json
import typing
from uuid import uuid4
from collections import defaultdict
from tempfile import NamedTemporaryFile, _TemporaryFileWrapper

Expand All @@ -17,20 +15,6 @@
from reversion.revisions import _get_options


def custom_upload_to(directory):
"""
Rename file name with adding uuid
"""
def upload_to(instance, filename):
# Get the file extension
extension = filename.split('.')[-1]
old_file_name = filename.split('.')[0]
# Create a unique filename using uuid4
new_filename = f"{old_file_name}-{uuid4().hex}.{extension}"
# Return the new file path
return os.path.join(directory, new_filename)
return upload_to

def is_tableau(request):
"""Checking the request for the 'tableau' parameter
(used mostly for switching to the *TableauSerializers)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Generated by Django 4.2.15 on 2024-09-10 10:12

from django.db import migrations

import main.base_class


class Migration(migrations.Migration):

dependencies = [
("per", "0120_alter_formcomponent_status"),
]

operations = [
migrations.AlterField(
model_name="perdocumentupload",
name="file",
field=main.base_class.SecureFileField(upload_to="per/documents/", verbose_name="file"),
),
migrations.AlterField(
model_name="perfile",
name="file",
field=main.base_class.SecureFileField(upload_to="per/images/", verbose_name="file"),
),
]
Loading

0 comments on commit 1986d35

Please sign in to comment.