11from django .contrib .sites .shortcuts import get_current_site
22from django .core .exceptions import BadRequest , ObjectDoesNotExist
3+ from django .core .files .storage import default_storage
34from django .db .models import QuerySet , Subquery
45from django .forms .renderers import DjangoTemplates
5- from django .http import JsonResponse , HttpResponseBadRequest
6+ from django .http import JsonResponse , HttpResponseBadRequest , HttpResponseNotFound
7+ from django .utils .decorators import method_decorator
68from django .utils .html import strip_spaces_between_tags
79from django .utils .safestring import mark_safe
810from django .views import View
11+ from django .views .decorators .http import require_GET , require_http_methods , require_POST
912
1013from finder .lookups import annotate_unified_queryset , lookup_by_label , sort_by_attribute
1114from finder .models .file import FileModel
@@ -30,6 +33,8 @@ class BrowserView(View):
3033 limit = 25
3134
3235 def dispatch (self , request , * args , ** kwargs ):
36+ if self .action is None :
37+ return HttpResponseNotFound ()
3338 action = getattr (self , self .action , None )
3439 if not callable (action ):
3540 return HttpResponseBadRequest (f"Action { self .action } not allowed." )
@@ -62,6 +67,7 @@ def _get_realm(self, request, slug):
6267 except RealmModel .DoesNotExist :
6368 raise ObjectDoesNotExist (f"Realm named { slug } not found for { site .domain } ." )
6469
70+ @method_decorator (require_GET )
6571 def structure (self , request , slug ):
6672 realm = self ._get_realm (request , slug )
6773 root_folder_id = str (realm .root_folder .id )
@@ -100,6 +106,7 @@ def structure(self, request, slug):
100106 ** self .list (request , request .session ['finder.last_folder' ]),
101107 }
102108
109+ @method_decorator (require_GET )
103110 def fetch (self , request , inode_id ):
104111 """
105112 Open the given folder and fetch children data for the folder.
@@ -121,6 +128,7 @@ def fetch(self, request, inode_id):
121128 else :
122129 return inode .as_dict
123130
131+ @method_decorator (require_GET )
124132 def open (self , request , folder_id ):
125133 """
126134 Just open the folder.
@@ -132,6 +140,7 @@ def open(self, request, folder_id):
132140 request .session .modified = True
133141 return {'id' : folder_id }
134142
143+ @method_decorator (require_GET )
135144 def close (self , request , folder_id ):
136145 """
137146 Just close the folder.
@@ -145,6 +154,7 @@ def close(self, request, folder_id):
145154 request .session .modified = True
146155 return {'id' : folder_id }
147156
157+ @method_decorator (require_GET )
148158 def list (self , request , folder_id ):
149159 """
150160 List all the files of the given folder.
@@ -175,6 +185,7 @@ def list(self, request, folder_id):
175185 'search_query' : '' ,
176186 }
177187
188+ @method_decorator (require_GET )
178189 def search (self , request , folder_id ):
179190 """
180191 Search for files in either the descendants of given folder or in all folders.
@@ -207,12 +218,11 @@ def search(self, request, folder_id):
207218 'offset' : next_offset ,
208219 }
209220
221+ @method_decorator (require_POST )
210222 def upload (self , request , folder_id ):
211223 """
212224 Upload a single file into the given folder.
213225 """
214- if request .method != 'POST' :
215- raise BadRequest (f"Method { request .method } not allowed. Only POST requests are allowed." )
216226 if request .content_type != 'multipart/form-data' or 'upload_file' not in request .FILES :
217227 raise BadRequest ("Bad form encoding or missing payload." )
218228 model = FileModel .objects .get_model_for (request .FILES ['upload_file' ].content_type )
@@ -230,22 +240,37 @@ def upload(self, request, folder_id):
230240 }
231241 return response
232242
243+ @method_decorator (require_http_methods (['DELETE' , 'POST' ]))
233244 def change (self , request , file_id ):
234245 """
235246 Change some fields after uploading a single file.
236247 """
237- if request .method not in ['DELETE' , 'POST' ]:
238- raise BadRequest (f"Method { request .method } not allowed. Only POST and DELETE requests are allowed." )
239- if request .method == 'POST' and request .content_type != 'multipart/form-data' :
240- raise BadRequest ("Bad form encoding or missing payload." )
241248 file = FileModel .objects .get_inode (id = file_id )
242249 if request .method == 'DELETE' :
243250 file .delete ()
244251 return {'file_info' : None }
252+ if request .content_type != 'multipart/form-data' :
253+ raise BadRequest ("Bad form encoding or missing payload." )
245254 form_class = file .get_form_class ()
246255 form = form_class (instance = file , data = request .POST , renderer = FormRenderer ())
247256 if form .is_valid ():
248257 file = form .save ()
249258 return {'file_info' : file .as_dict }
250259 else :
251260 return {'form_html' : mark_safe (strip_spaces_between_tags (form .as_div ()))}
261+
262+ @method_decorator (require_POST )
263+ def crop (self , request , image_id ):
264+ image = FileModel .objects .get_inode (id = image_id , mime_types = ['image/*' ], is_folder = False )
265+ width , height = int (request .POST .get ('width' )), int (request .POST .get ('height' ))
266+ cropped_image_path = image .get_cropped_path (width , height )
267+ if not default_storage .exists (cropped_image_path ):
268+ image .crop (cropped_image_path , width , height )
269+ cropped_image_url = default_storage .url (cropped_image_path )
270+ return {
271+ 'image_id' : image_id ,
272+ 'alt_text' : image .meta_data .get ('alt_text' , image .name ),
273+ 'cropped_image_url' : cropped_image_url ,
274+ 'width' : width ,
275+ 'height' : height ,
276+ }
0 commit comments