Skip to content

Commit

Permalink
Save files in the private-media folder
Browse files Browse the repository at this point in the history
  • Loading branch information
katsufumi shibata committed Mar 7, 2024
1 parent e1b9325 commit f1ff11a
Show file tree
Hide file tree
Showing 7 changed files with 233 additions and 24 deletions.
17 changes: 16 additions & 1 deletion mooringlicensing/components/approvals/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
from mooringlicensing.helpers import is_customer
from mooringlicensing.settings import PROPOSAL_TYPE_RENEWAL, PROPOSAL_TYPE_AMENDMENT, PROPOSAL_TYPE_NEW
from ledger_api_client.utils import calculate_excl_gst
from mooringlicensing.components.proposals.models import private_storage

# logger = logging.getLogger('mooringlicensing')
logger = logging.getLogger(__name__)
Expand All @@ -65,8 +66,22 @@ def update_approval_comms_log_filename(instance, filename):


class WaitingListOfferDocument(Document):
@staticmethod
def relative_path_to_file(approval_id, filename):
return f'approval/{approval_id}/waiting_list_offer_documents/{filename}'

def upload_to(self, filename):
approval_id = self.approval.id
return self.relative_path_to_file(approval_id, filename)

approval = models.ForeignKey('Approval',related_name='waiting_list_offer_documents', on_delete=models.CASCADE)
_file = models.FileField(max_length=512)
# _file = models.FileField(max_length=512)
_file = models.FileField(
null=True,
max_length=512,
storage=private_storage,
upload_to=upload_to
)
input_name = models.CharField(max_length=255,null=True,blank=True)
can_delete = models.BooleanField(default=True) # after initial submit prevent document from being deleted
can_hide= models.BooleanField(default=False) # after initial submit, document cannot be deleted but can be hidden
Expand Down
28 changes: 22 additions & 6 deletions mooringlicensing/components/main/process_document.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,22 @@
from django.core.files.base import ContentFile
import traceback
from django.conf import settings
from django.core.files.storage import FileSystemStorage

from mooringlicensing.components.proposals.models import (
ProposalMooringReportDocument, ProposalWrittenProofDocument, ProposalSignedLicenceAgreementDocument,
ProposalProofOfIdentityDocument
)
from mooringlicensing.settings import PRIVATE_MEDIA_BASE_URL, PRIVATE_MEDIA_STORAGE_LOCATION

logger = logging.getLogger(__name__)

# private_storage = FileSystemStorage( # We want to store files in secure place (outside of the media folder)
# location=PRIVATE_MEDIA_STORAGE_LOCATION,
# base_url=PRIVATE_MEDIA_BASE_URL,
# )
from mooringlicensing.components.proposals.models import private_storage

def process_generic_document(request, instance, document_type=None, *args, **kwargs):
logger.info(f'Processing document... Data: [{request.data}] ...')
try:
Expand Down Expand Up @@ -202,20 +210,28 @@ def save_document(request, instance, comms_instance, document_type, input_name=N
# elif document_type == 'mooring_report_document':
if document_type == 'mooring_report_document':
document = instance.mooring_report_documents.get_or_create(input_name=input_name, name=filename)[0]
path_format_string = '{}/proposals/{}/mooring_report_documents/{}'
# path_format_string = '{}/proposals/{}/mooring_report_documents/{}'
path_format_string = 'proposal/{}/mooring_report_documents/{}'
elif document_type == 'written_proof_document':
document = instance.written_proof_documents.get_or_create(input_name=input_name, name=filename)[0]
path_format_string = '{}/proposals/{}/written_proof_documents/{}'
# path_format_string = '{}/proposals/{}/written_proof_documents/{}'
path_format_string = 'proposal/{}/written_proof_documents/{}'
elif document_type == 'signed_licence_agreement_document':
document = instance.signed_licence_agreement_documents.get_or_create(input_name=input_name, name=filename)[0]
path_format_string = '{}/proposals/{}/signed_licence_agreement_documents/{}'
# path_format_string = '{}/proposals/{}/signed_licence_agreement_documents/{}'
path_format_string = 'proposal/{}/signed_licence_agreement_documents/{}'
elif document_type == 'proof_of_identity_document':
document = instance.proof_of_identity_documents.get_or_create(input_name=input_name, name=filename)[0]
path_format_string = '{}/proposals/{}/proof_of_identity_documents/{}'
# path_format_string = '{}/proposals/{}/proof_of_identity_documents/{}'
path_format_string = 'proposal/{}/proof_of_identity_documents/{}'
elif document_type == 'waiting_list_offer_document':
document = instance.waiting_list_offer_documents.get_or_create(input_name=input_name, name=filename)[0]
path_format_string = '{}/approvals/{}/waiting_list_offer_documents/{}'
path = default_storage.save(path_format_string.format(settings.MEDIA_APP_DIR, instance.id, filename), ContentFile(_file.read()))
# path_format_string = '{}/approvals/{}/waiting_list_offer_documents/{}'
path_format_string = 'approval/{}/waiting_list_offer_documents/{}'
# path = default_storage.save(path_format_string.format(settings.MEDIA_APP_DIR, instance.id, filename), ContentFile(_file.read()))
# path = private_storage.save(path_format_string.format(settings.MEDIA_APP_DIR, instance.id, filename), ContentFile(_file.read()))
path = private_storage.save(path_format_string.format(instance.id, filename), ContentFile(_file.read()))
# path = default_storage.save(path_format_string.format(instance.id, filename), ContentFile(_file.read()))

# comms_log doc store save
elif comms_instance and 'filename' in request.data:
Expand Down
66 changes: 59 additions & 7 deletions mooringlicensing/components/proposals/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
from mooringlicensing.components.proposals.utils import (
construct_dict_from_docs, save_proponent_data, update_proposal_applicant, make_ownership_ready,
)
from mooringlicensing.components.proposals.models import ElectoralRollDocument, HullIdentificationNumberDocument, InsuranceCertificateDocument, VesselOwnershipCompanyOwnership, searchKeyWords, search_reference, ProposalUserAction, \
from mooringlicensing.components.proposals.models import ElectoralRollDocument, HullIdentificationNumberDocument, InsuranceCertificateDocument, MooringReportDocument, VesselOwnershipCompanyOwnership, searchKeyWords, search_reference, ProposalUserAction, \
ProposalType, ProposalApplicant, VesselRegistrationDocument
from mooringlicensing.components.main.utils import (
get_bookings, calculate_max_length,
Expand Down Expand Up @@ -783,13 +783,65 @@ def get_object(self):
@detail_route(methods=['POST'], detail=True)
@renderer_classes((JSONRenderer,))
@basic_exception_handler
def process_mooring_report_document(self, request, *args, **kwargs):
# def process_mooring_report_document(self, request, *args, **kwargs):
def mooring_report_document(self, request, *args, **kwargs):
instance = self.get_object()
returned_data = process_generic_document(request, instance, document_type='mooring_report_document')
if returned_data:
return Response(returned_data)
else:
return Response()
action = request.data.get('action')

# returned_data = process_generic_document(request, instance, document_type='mooring_report_document')
# if returned_data:
# return Response(returned_data)
# else:
# return Response()

if action == 'list':
pass
elif action == 'delete':
document_id = request.data.get('document_id')
document = MooringReportDocument.objects.get(
# proposal=instance,
id=document_id,
)
if document._file and os.path.isfile(document._file.path):
os.remove(document._file.path)
if document:
# original_file_name = document.original_file_name
# original_file_ext = document.original_file_ext
original_file_name = document.name
document.delete()
# logger.info(f'VesselRegistrationDocument file: {original_file_name}{original_file_ext} has been deleted.')
logger.info(f'MooringReportDocument file: {original_file_name} has been deleted.')
elif action == 'cancel':
pass
elif action == 'save':
filename = request.data.get('filename')
_file = request.data.get('_file')

filepath = pathlib.Path(filename)

# Calculate a new unique filename
if MAKE_PRIVATE_MEDIA_FILENAME_NON_GUESSABLE:
unique_id = uuid.uuid4()
new_filename = unique_id.hex + filepath.suffix
else:
new_filename = filepath.stem + filepath.suffix

document = MooringReportDocument.objects.create(
# proposal=instance,
name=filepath.stem + filepath.suffix
)
instance.mooring_report_documents.add(document)
document._file.save(new_filename, ContentFile(_file.read()))

logger.info(f'MooringReportDocument file: {filename} has been saved as {document._file.url}')

# returned_file_data = []
docs_in_limbo = instance.mooring_report_documents.all() # Files uploaded when vessel_ownership is unknown
all_the_docs = docs_in_limbo

returned_file_data = construct_dict_from_docs(all_the_docs)

return Response({'filedata': returned_file_data})

@detail_route(methods=['POST'], detail=True)
@renderer_classes((JSONRenderer,))
Expand Down
69 changes: 63 additions & 6 deletions mooringlicensing/components/proposals/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,6 @@
logger_for_payment = logging.getLogger(__name__)

private_storage = FileSystemStorage( # We want to store files in secure place (outside of the media folder)
# location=os.path.join(BASE_DIR, PRIVATE_MEDIA_DIR_NAME),
# base_url=f'/{PRIVATE_MEDIA_DIR_NAME}/'
location=PRIVATE_MEDIA_STORAGE_LOCATION,
base_url=PRIVATE_MEDIA_BASE_URL,
)
Expand Down Expand Up @@ -4891,8 +4889,23 @@ class Meta:


class MooringReportDocument(Document):
@staticmethod
def relative_path_to_file(proposal_id, filename):
return f'proposal/{proposal_id}/mooring_report_documents/{filename}'

def upload_to(self, filename):
# proposal_id = self.proposal.id
proposal = self.proposal_set.first()
return self.relative_path_to_file(proposal.id, filename)

# proposal = models.ForeignKey(Proposal, related_name='mooring_report_documents', on_delete=models.CASCADE)
_file = models.FileField(max_length=512)
# _file = models.FileField(max_length=512)
_file = models.FileField(
null=True,
max_length=512,
storage=private_storage,
upload_to=upload_to
)
input_name = models.CharField(max_length=255, null=True, blank=True)
can_delete = models.BooleanField(default=True) # after initial submit prevent document from being deleted
can_hide = models.BooleanField(default=False) # after initial submit, document cannot be deleted but can be hidden
Expand All @@ -4905,7 +4918,22 @@ class Meta:

class WrittenProofDocument(Document):
# proposal = models.ForeignKey(Proposal, related_name='written_proof_documents', on_delete=models.CASCADE)
_file = models.FileField(max_length=512)
# _file = models.FileField(max_length=512)
@staticmethod
def relative_path_to_file(proposal_id, filename):
return f'proposal/{proposal_id}/written_proof_documents/{filename}'

def upload_to(self, filename):
# proposal_id = self.proposal.id
proposal = self.proposal_set.first()
return self.relative_path_to_file(proposal.id, filename)

_file = models.FileField(
null=True,
max_length=512,
storage=private_storage,
upload_to=upload_to
)
input_name = models.CharField(max_length=255, null=True, blank=True)
can_delete = models.BooleanField(default=True) # after initial submit prevent document from being deleted
can_hide = models.BooleanField(default=False) # after initial submit, document cannot be deleted but can be hidden
Expand All @@ -4917,8 +4945,23 @@ class Meta:


class SignedLicenceAgreementDocument(Document):
@staticmethod
def relative_path_to_file(proposal_id, filename):
return f'proposal/{proposal_id}/signed_licence_agreement_documents/{filename}'

def upload_to(self, filename):
# proposal_id = self.proposal.id
proposal = self.proposal_set.first()
return self.relative_path_to_file(proposal.id, filename)

# proposal = models.ForeignKey(Proposal, related_name='signed_licence_agreement_documents', on_delete=models.CASCADE)
_file = models.FileField(max_length=512)
# _file = models.FileField(max_length=512)
_file = models.FileField(
null=True,
max_length=512,
storage=private_storage,
upload_to=upload_to
)
input_name = models.CharField(max_length=255, null=True, blank=True)
can_delete = models.BooleanField(default=True)
can_hide = models.BooleanField(default=False)
Expand All @@ -4930,8 +4973,22 @@ class Meta:


class ProofOfIdentityDocument(Document):
@staticmethod
def relative_path_to_file(proposal_id, filename):
return f'proposal/{proposal_id}/proof_of_identity_documents/{filename}'

def upload_to(self, filename):
# proposal_id = self.proposal.id
proposal = self.proposal_set.first()
return self.relative_path_to_file(proposal.id, filename)
# proposal = models.ForeignKey(Proposal, related_name='proof_of_identity_documents', on_delete=models.CASCADE)
_file = models.FileField(max_length=512)
# _file = models.FileField(max_length=512)
_file = models.FileField(
null=True,
max_length=512,
storage=private_storage,
upload_to=upload_to
)
input_name = models.CharField(max_length=255, null=True, blank=True)
can_delete = models.BooleanField(default=True)
can_hide = models.BooleanField(default=False)
Expand Down
70 changes: 67 additions & 3 deletions mooringlicensing/components/proposals/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@
from django.views.generic import View, TemplateView
from django.db.models import Q
from mooringlicensing import settings
from mooringlicensing.components.proposals.models import (ElectoralRollDocument, HullIdentificationNumberDocument, InsuranceCertificateDocument, Proposal,
from mooringlicensing.components.proposals.models import (ElectoralRollDocument, HullIdentificationNumberDocument, InsuranceCertificateDocument, ProofOfIdentityDocument, Proposal,
HelpPage, AuthorisedUserApplication, Mooring,
MooringLicenceApplication, VesselRegistrationDocument
MooringLicenceApplication, SignedLicenceAgreementDocument, VesselRegistrationDocument, WrittenProofDocument
)
from mooringlicensing.components.approvals.models import Approval
from mooringlicensing.components.approvals.models import Approval, WaitingListOfferDocument
from mooringlicensing.components.compliances.models import Compliance
import json,traceback
from reversion_compare.views import HistoryCompareDetailView
Expand Down Expand Up @@ -244,3 +244,67 @@ def get(self, request, proposal_id, filename):
response = get_file_content_http_response(file_path)

return response

class WrittenProofDocumentView(APIView):

def get(self, request, proposal_id, filename):
response = None

### Permission rules
allow_access = True
###

if allow_access:
file_path = WrittenProofDocument.relative_path_to_file(proposal_id, filename)
file_path = os.path.join(PRIVATE_MEDIA_STORAGE_LOCATION, file_path)
response = get_file_content_http_response(file_path)

return response

class SignedLicenceAgreementDocumentView(APIView):

def get(self, request, proposal_id, filename):
response = None

### Permission rules
allow_access = True
###

if allow_access:
file_path = SignedLicenceAgreementDocument.relative_path_to_file(proposal_id, filename)
file_path = os.path.join(PRIVATE_MEDIA_STORAGE_LOCATION, file_path)
response = get_file_content_http_response(file_path)

return response

class ProofOfIdentityDocumentView(APIView):

def get(self, request, proposal_id, filename):
response = None

### Permission rules
allow_access = True
###

if allow_access:
file_path = ProofOfIdentityDocument.relative_path_to_file(proposal_id, filename)
file_path = os.path.join(PRIVATE_MEDIA_STORAGE_LOCATION, file_path)
response = get_file_content_http_response(file_path)

return response

class WaitingListOfferDocumentView(APIView):

def get(self, request, approval_id, filename):
response = None

### Permission rules
allow_access = True
###

if allow_access:
file_path = WaitingListOfferDocument.relative_path_to_file(approval_id, filename)
file_path = os.path.join(PRIVATE_MEDIA_STORAGE_LOCATION, file_path)
response = get_file_content_http_response(file_path)

return response
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,8 @@ export default {
if (this.unique_id){
url = helpers.add_endpoint_join(
api_endpoints.proposal_by_uuid,
this.unique_id + '/process_mooring_report_document/'
// this.unique_id + '/process_mooring_report_document/'
this.unique_id + '/mooring_report_document/'
)
}
return url;
Expand Down
4 changes: 4 additions & 0 deletions mooringlicensing/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,10 @@
url(r'^' + PRIVATE_MEDIA_DIR_NAME + '/proposal/(?P<proposal_id>\d+)/hull_identification_number_documents/(?P<filename>.+)$', proposal_views.HullIdentificationNumberDocumentView.as_view(), name='serve_hull_identification_number_documents'),
url(r'^' + PRIVATE_MEDIA_DIR_NAME + '/proposal/(?P<proposal_id>\d+)/electoral_roll_documents/(?P<filename>.+)$', proposal_views.ElectoralRollDocumentView.as_view(), name='serve_electoral_roll_documents'),
url(r'^' + PRIVATE_MEDIA_DIR_NAME + '/proposal/(?P<proposal_id>\d+)/insurance_certificate_documents/(?P<filename>.+)$', proposal_views.InsuranceCertificateDocumentView.as_view(), name='serve_insurance_certificate_documents'),
url(r'^' + PRIVATE_MEDIA_DIR_NAME + '/proposal/(?P<proposal_id>\d+)/written_proof_documents/(?P<filename>.+)$', proposal_views.WrittenProofDocumentView.as_view(), name='serve_written_proof_documents'),
url(r'^' + PRIVATE_MEDIA_DIR_NAME + '/proposal/(?P<proposal_id>\d+)/signed_licence_agreement_documents/(?P<filename>.+)$', proposal_views.SignedLicenceAgreementDocumentView.as_view(), name='serve_signed_licence_agreement_documents'),
url(r'^' + PRIVATE_MEDIA_DIR_NAME + '/proposal/(?P<proposal_id>\d+)/proof_of_identity_documents/(?P<filename>.+)$', proposal_views.ProofOfIdentityDocumentView.as_view(), name='serve_proof_of_identity_documents'),
url(r'^' + PRIVATE_MEDIA_DIR_NAME + '/approval/(?P<approval_id>\d+)/waiting_list_offer_documents/(?P<filename>.+)$', proposal_views.WaitingListOfferDocumentView.as_view(), name='serve_waiting_list_offer_documents'),

# Intercept the request to update the account details before reaching the ledger_api_client
url(r'^ledger-ui/api/update-account-details/(?P<user_id>[0-9]+)/', update_personal_details, name='update-account-details'),
Expand Down

0 comments on commit f1ff11a

Please sign in to comment.