Detected path traversal attempt - Django/Heroku(Bucketeer) - django

I'm getting this error when trying to upload using FileField. I'm using Bucketeer on Heroku to upload to an AWS bucket. I've seen a few threads on this issue but haven't been able to figure it out.
The file upload view:
class UploadTicketAttachment(APIView):
permission_classes = []
parser_classes = (MultiPartParser, FormParser)
def post(self, request, format=None):
user = request.user
serializer = AttachmentSerialiazer(data=request.data)
if serializer.is_valid(raise_exception=True):
serializer.validated_data['uploaded_by'] = user
serializer.save()
return Response(serializer.data['id'])
else:
return Response(f'{serializer.errors}, attachment upload failed')
The model:
class Attachment(models.Model):
file = models.FileField(upload_to="/ticket_attachments", blank=True, null=True)
created_on = models.CharField(max_length=20, null=True)
uploaded_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True, related_name="uploaded_by")
parent_ticket = models.ForeignKey(Ticket, on_delete=models.CASCADE, null=True, related_name="attachment")
def __str__(self):
return self.file.name
For the settings/bucketeer configuration I followed which uses django-storages:
https://dev.to/heroku/properly-managing-django-media-static-files-on-heroku-o2l
I don't think the issue is on that end since I set it up the exact same way in another project and it works fine with the only difference being that the other project uses ImageField instead of FileField.
Django version is 4.0.2. Any ideas? Thanks

Related

Django Rest Framework - overriding save in backend is not creating custom id

I am working on a project. I have Django for my backend and Vue for my front end. When using the templates and saving in the Django project I have no issues.
However, when I POST to my projects API the following save from my modal is not being created.
models.py
class DevProjects(models.Model):
PROJECT_TYPE = [
('New Application', 'New Application'),
('Update Application', 'Update Application'),
('Bug Fixes', 'Bug Fixes')
]
PROJECT_STATUS = [
('New', 'New'),
('In Progress', 'In Progress'),
('Complete', 'Complete'),
]
project_id = models.CharField(max_length=15, editable=False, unique=True)
project_title = models.CharField(max_length=100)
project_desc = models.CharField(max_length=500)
project_category = models.CharField(max_length=25, choices=PROJECT_TYPE, null=True, blank=True)
project_status = models.CharField(max_length=25, choices=PROJECT_STATUS, default='New')
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateField(auto_now=True)
created_by = models.ForeignKey(User, related_name='projects', on_delete=models.CASCADE)
def save(self, *args, **kwargs):
super(DevProjects, self).save(**kwargs)
self.project_id = 'PROJ-' + str(self.id)
super(DevProjects, self).save(**kwargs)
def __str__(self):
return self.project_title
I have the project_id being created on save which gets the original ID but just adds 'PROJ-' in front. Whenever I submit the form from my frontend, that save definition is not being called, thus not creating the project_id.
Project ID is what I use to send a GET request to get the projects.
serailizers.py
class DevProjectSerializer(serializers.ModelSerializer):
class Meta:
model = DevProjects
fields = ("project_id", "project_title", "project_desc", "project_category", "project_status")
views.py
class DevProjectViewSet(viewsets.ModelViewSet):
serializer_class = DevProjectSerializer
queryset = DevProjects.objects.all()
def perform_create(self, serializer):
serializer.save(created_by=self.request.user)
Whenever I post, I get the following error:
IntegrityError: UNIQUE constraint failed: ckcSupportWeb_devprojects.project_id
What do I need to do for the project_id to generate when POSTing from DRF? Any and all help is appreciated.
UPDATE
I can try to use the following code in my viewset:
def create(self, *args, **kwargs):
self.project_id = 'PROJ-' + str(self.id)
super(DevProjectViewSet, self).save(**kwargs)
But, I get the following error:
self.project_id = 'PROJ-' + str(self.id)
AttributeError: 'DevProjectViewSet' object has no attribute 'id'
I am truly stuck on how to handle this for API post requests.
From what I can understand, you can relax the unique constraint on the project_id and your previous code should work fine.
Since the project code is not editable, it won't be updated from a POST API call.
I was able to get rid of all of these issues with writing a simple function in utils.py that gets the latest ID created, adds 1 and then sets the new project_id.
Try with this code snippet
def save(self, *args, **kwargs)
self.project_id = 'PROJ-' + str(self.id)
super(DevProjects, self).save(**kwargs)

Django REST throwing a 404 error on DetailView

I am trying to create a RetrieveUpdateDestroyAPIView in my DJango REST application but I get a 404 error when I try to visit the URL.
Here is urlpattern in my urls.py file which maps to the views.py file below
re_path(r'^snippets/(?P<username>.+)/(?P<snippet_id>\d+)/$',
views.SnippetDetailView.as_view(), name="snippet-detail"),
Here is my views.py code.
class SnippetDetailView(generics.RetrieveUpdateDestroyAPIView):
"""
Retrieve, update or delete a snippet.
"""
permission_classes = [IsOwnerOrReadOnly]
serializer_class = SnippetSerializer
lookup_url_kwarg = 'snippet_id'
def get_queryset(self):
self.user = get_object_or_404(User, username=self.kwargs['username'])
return Snippet.objects.filter(owner__username=self.user.username)
And this is my models.py code
class Snippet(models.Model):
owner = models.ForeignKey('auth.User', related_name='snippets',
on_delete=models.CASCADE)
highlighted = models.TextField() # to store representation of code
created = models.DateTimeField(auto_now_add=True)
title = models.CharField(max_length=100, default="", blank=True)
code = models.TextField()
linenos = models.BooleanField(default=False)
language = models.CharField(choices=LANGUAGE_CHOICES, default='python',
max_length=100)
style = models.CharField(choices=STYLE_CHOICES, default='friendly',
max_length=100)
class Meta:
ordering = ["created"]
I've been trying to understand what could be wrong with it but am relatively new and I have no idea as to why this is not working. Looked up the documentation and a few examples but I don't see any one of them having multiple named parameters in their urls.py file. I would appreciate any help a lot.

How to get file name for uploading image into s3 bucket?

Hello I am facing an issue while adding a file in to s3 bucket....
I am sharing my model
class UserProfile(SoftDeletionModel, BaseModel):
user = models.ForeignKey(User, on_delete=models.CASCADE)
first_name = models.CharField(max_length=100, blank=True)
contact_number = models.CharField(max_length=20, blank=True)
profile_pic=models.TextField(blank=True, null=True)
Here is my serializer class
class UserprofileSerializer(ModelSerializer):
class Meta:
model = UserProfile
exclude = ['deleted_at','created_date','modified_date']
extra_kwargs = {'user': {'required': False}}
Here is my view
class UserProfileUpdateView(UpdateAPIView):
def get_queryset(self, *args, **kwargs):
queryset_list = UserProfile.objects.filter(
user=self.request.user)
return queryset_list
serializer_class = UserprofileSerializer
The issue I am facing is..... THe profile pic uploaded as a image.... But in my model it created as a textfield , for saving the s3 bucket proxy url.....
I need to get the file name for creating a path in s3 bucket ......
So how can I do that ?
You can use request.FILES['profile_pic'] here 'profile_pic' is the input field name where you are uploading.
image = request.FILES['profile_pic']
then you can use image object as Body parameter of S3.
Suppose you have written a function upload_to_s3 which uploads image to S3 using boto3.
Exclude profile_pic from serializer.
Change your code as following:
def upload_to_s3(image_object):
// upload to s3 and get url using boto3
return url
class UserProfileUpdateView(UpdateAPIView):
serializer_class = UserprofileSerializer
def perform_update(self, serializer):
image = request.FILES['profile_pic']
serializer.validated_data['profile_pic'] = upload_to_s3(image)
serializer.save()
Convert profile_pic field type to URLField()

Always getting {"detail":"Unsupported media type \"application/json\" in request."} error when I try to post data on postman

I am working on a project that requires me to upload an image. However when I am trying to upload one and posting I ma getting the above error. I have no clue what to do anymore.
I have already tried using FileUploadParser and creating class Base64ImageField too. Please Help.
models
class UserProfile(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE, default=None, null=True)
avatar = models.ImageField(upload_to='', blank=True, null=True)
code = models.CharField(max_length=8, unique=True, default=unique_rand)
emailVerified = models.NullBooleanField(null=True, default=None)
facebookId = models.CharField( null=True,unique=True, default=None,max_length=255)
googleId = models.CharField(null=True,unique=True,default=None,max_length=255)
phone_regex = RegexValidator(regex=r'^\+?1?\d{9,15}$')
mobile = models.CharField(validators=[phone_regex, MinLengthValidator(10)], max_length=10, null=True, default=None)
mobileVerified = models.NullBooleanField(null=True,default=None)
status = models.BooleanField(default=False)
serializers
class UserProfileSerializer(serializers.ModelSerializer):
user = UserSerializer()
avatar = Base64ImageField(required=False)
code = serializers.CharField(read_only=True)
serializers.FileField(use_url=False)
class Meta:
model = UserProfile
fields = '__all__'
extra_kwargs = {'user': {'required': False}}
def create(self, validated_data):
user_data = validated_data.pop('user')
user = User.objects.create(**user_data)
image = validated_data.pop('avatar')
upr=UserProfile.objects.create(user=user,image=image,**validated_data)
return upr
views
class UserCreate(generics.ListCreateAPIView):
serializer_class = UserProfileSerializer
user_serializer = UserSerializer
queryset = UserProfile.objects.all()
parser_classes = (FormParser,MultiPartParser)
def pre_save(self, request):
request.avatar = self.request.FILES.get('file')
def post(self, request):
print(request.data)
serializer= UserProfileSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Maybe try using "multipart form" instead of JSON as your POST payload type. For the value (I am using Insomnia), select the dropdown on the right and select "File" instead of "Text". Then upload a file.
That worked for me, not sure if it's the same problem. Hope that helps!
Here's a post that has the answer you're looking for.
Posting a File and Associated Data to a RESTful WebService preferably as JSON

Display IntegrityError when trying to validate CreateView based on ModelForm using unique_together

How would I display an integrity error when using class based view's CreateView.
My current Model looks like this :
class Delivery(models.Model):
created_date = models.DateTimeField('date created', editable=False)
modified_date = models.DateTimeField('modified', editable=False)
user_name = models.ForeignKey(User, null=False)
stream_name = models.CharField(max_length=50, null=False)
view_name = models.CharField(max_length=100, null=False, blank=True)
activity_name = models.CharField(max_length=100, null=False, blank=True)
jira = models.URLField()
codereview = models.URLField()
related_streams = models.CharField(max_length=100, choices=sorted(streams()),blank=True)
description = models.TextField(null=False,blank=True)
status = models.BooleanField(default=False, blank=False)
And the corresponding view is :
class CreateEntryView(CreateView):
template_name = 'tracker/entry.html'
model = Delivery
success_url = reverse_lazy('table_view')
status = StreamStatus()
fields = ['stream_name','view_name','activity_name','jira','codereview','related_streams','description','status']
def get_initial(self):
if 'codereview-get' in self.request.GET:
parsedDict = codereviewParser(self.request.GET['codereview-get'])
return {'stream_name':parsedDict['stream'].split('_')[1:2][0],
'view_name':parsedDict['view'],
'activity_name':parsedDict['name'],
'jira':parsedDict['jira'],
'codereview':self.request.GET['codereview-get'],
'description':parsedDict['description'],
'status':parsedDict['status']}
else:
return self.initial.copy()
def form_valid(self, form):
form.instance.user_name = self.request.user
try:
return super(CreateEntryView, self).form_valid(form)
except IntegrityError as e:
messages.error(self.request, "Your data has not been saved!")
return HttpResponseRedirect(self.request.path)
return super(CreateEntryView, self).form_valid(form)
def get_context_data(self, **kwargs):
ctx = super(CreateEntryView, self).get_context_data(**kwargs)
ctx['locked'] = self.status.getLocked()
ctx['unlocked'] = self.status.getUnlocked()
return ctx
I tried a couple of techniques by passing a new context to render_to_response() but then I need to pass the entire context again. Also tried HttpResponse() which I dont like since it directs me to a blank page with a message. I would like to use an alert message to show the error to the user.
What about doing what form_invalid does, but adding your info to the context:
return self.render_to_response(self.get_context_data(form=form, integritymsg='Your data has not been saved!', reason=whatever))
And of course check and show integritymsg/reason in the template.
One thing not immediately obvious is that the arguments passed to get_context_data are added to the context. All the get_context_data being called along the MRO chain add their bit to the context.
ccbv.co.uk is a great tool. Unfortunately you need to inspect the code and find out the flow of execution yourself. It's not complicated, but yes, a diagram would help.
In general, start from as_view, dispatch, get, etc...