0

I'm having a terrible issue. I want to upload 2 images and get a result after running them through a lot of code. However, when I choose the path (on the server) as to where to upload these files, I always get a "SuspiciousFileOperation" error.

api view

import json
import os
from rest_framework import generics
from rest_framework.response import Response
from rest_framework import permissions
from .ProcessData.FaceRecognition import FaceRecognition
from .ProcessData.OCR import OCR
from .ProcessData.Wanted import Wanted
from identity.models import IdentityCheck
from .serializers import IdentityCheckSerializer
from rest_framework.generics import CreateAPIView
from django.core.files.storage import FileSystemStorage
from django.conf import settings

class IdentityCheckView(CreateAPIView, generics.ListAPIView):

    serializer_class = IdentityCheckSerializer
    permission_classes = [permissions.IsAuthenticated]

    def get_queryset(self):
        request = self.request
        qs = IdentityCheck.objects.all()
        query = self.request.GET.get('q')
        if query is not None:
            qs = qs.filter(name__icontains=query)
        return qs

    def save_fss(self, filename, file):
        mediaRoot = os.path.join(settings.MEDIA_ROOT, 'media/tmp/')
        filename = filename + ".jpg"
        fs = FileSystemStorage(location=mediaRoot)
        if fs.exists(filename):
            os.remove(mediaRoot + filename)
        newFile = fs.save(filename, file)
        uploaded_file_url = mediaRoot + fs.url(newFile)
        return uploaded_file_url

    def post(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        if(serializer.is_valid()):
            data = serializer.validated_data
            passPhoto = request.FILES['passengerPhoto']
            uploaded_file_url_pass_photo = self.save_fss("passPhoto", passPhoto)

            passPassport = request.FILES['passengerPassport']
            uploaded_file_url_pass_passport = self.save_fss("passPassport", passPassport)


            image = FaceRecognition.imageMatch(uploaded_file_url_pass_photo, uploaded_file_url_pass_passport)
            wanted = Wanted.criminalMatch(uploaded_file_url_pass_photo)
            passport_json = OCR.passportMatch(uploaded_file_url_pass_passport)
            image_json = json.loads(image)

            firstName      = passport_json['names']
            lastName       = passport_json['surname']
            nationality    = passport_json['country']
            birthDate      = passport_json['date_of_birth']
            gender         = passport_json['sex']

            ableToBoard = (wanted==0) and (int(image_json['match'])==1) and passport_json['valid_expiration_date'] and passport_json['valid_date_of_birth']
            serializer.save(agent=self.request.user, firstName=firstName, lastName=lastName, nationality=nationality, birthDate=birthDate, gender=gender, ableToBoard=ableToBoard)
        else:
            return Response({"image": "-1", "passport": "-1", "wanted": "-1"}, status=500)

        return Response({"image": image_json, "passport": passport_json, "wanted": wanted}, status=200)

settings.py

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

DEBUG = True

ALLOWED_HOSTS = ['*']

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'django.contrib.postgres',
    'django_postgres_extensions',

    'rest_framework',
    'corsheaders',

    'identity',
    'models',
    'admincp',
    'abnormal',
    'language'
]

MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'IBCS.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]
...
STATIC_URL = '/static/'

MEDIA_ROOT = os.path.dirname(BASE_DIR)
MEDIA_URL = '/'

from IBCS.restconf.main import *
from IBCS.apps import *

The error showed:

The joined path (C:\Users\Kyoko\Desktop\IBCS\server\media\tmp\passPhoto.jpg) is located outside of the base path component (C:\Users\Kyoko\Desktop\IBCS\server\media\tmp\)
Bad Request: /api/check/
"POST /api/check/ HTTP/1.1" 400 20335

This code was running fine before reinstalling Django and Python due to some tensorflow issues, but reinstalled all needed packages.

Thank you for your help!

Django version: 2.2.2 Python version: 3.6.7 (64-bits)

Ivan Starostin
  • 8,798
  • 5
  • 21
  • 39
Kyoko
  • 65
  • 1
  • 2
  • 6

1 Answers1

0

too long for comment

1

MEDIA_ROOT = os.path.dirname(BASE_DIR)
MEDIA_URL = '/'
...
os.path.join(settings.MEDIA_ROOT, 'media/tmp/')

Nope, you should not set MEDIA_ROOT = BASEDIR, you should set

MEDIA_ROOT = os.path.join(os.path.dirname(BASE_DIR), 'media')
MEDIA_URL = '/media/'

and avoid concatenating media everywhere you want to work with these files. Note, on prod you should choose some other root folder for media files - outside of project directory.

Also you should set STATIC_ROOT which is not configured in your settings.py

2

mediaRoot = os.path.join(settings.MEDIA_ROOT, 'media/tmp/')
mediaRoot + filename

Don't mix path.join with simple concatenation. In this example you're mixing \ and / separators (since you are on windows). It will work but is not a good style; URLs would fail. Here - always use os.path.join. Note, it can have more than two arguments.

3

uploaded_file_url = mediaRoot + fs.url(newFile)

medirRoot is a folder, which in your case is using \ as path separator whereas fs.url is an URL with / separator. So you won't get neither URL nor full path to the file here. Yes, it should work by the reason that fs.url will return partial URL and it replicates the partial path to the file... However, a) fs has path method b) why would you do this concatenation at all if you're uploading to the constant path?

4

if fs.exists(filename):
        os.remove(mediaRoot + filename)

fs can do delete() so don't mix approaches to handle files. Note, you will be always overwriting files no matter who and when uploads them.

5

You should show full error traceback. However, my guess is: you should not return full path from save_fss. Try returning fs.path(), configure MEDIA_ROOT properly and perhaps it should work.

Ivan Starostin
  • 8,798
  • 5
  • 21
  • 39