def json_response(f, *args, **kwargs): """Wrap a view in JSON. This decorator runs the given function and looks out for ajax.AJAXError's, which it encodes into a proper HttpResponse object. If an unknown error is thrown it's encoded as a 500. All errors are then packaged up with an appropriate Content-Type and a JSON body that you can inspect in JavaScript on the client. They look like: { "message": "Error message here.", "code": 500 } Please keep in mind that raw exception messages could very well be exposed to the client if a non-AJAXError is thrown. """ try: result = f(*args, **kwargs) if isinstance(result, AJAXError): raise result except AJAXError as e: result = e.get_response() request = args[0] logger.warn('AJAXError: %d %s - %s', e.code, request.path, e.msg, exc_info=True, extra={ 'status_code': e.code, 'request': request } ) except Http404 as e: result = AJAXError(404, e.__str__()).get_response() except Exception as e: import sys exc_info = sys.exc_info() type, message, trace = exc_info if settings.DEBUG: import traceback tb = [{'file': l[0], 'line': l[1], 'in': l[2], 'code': l[3]} for l in traceback.extract_tb(trace)] result = AJAXError(500, message, traceback=tb).get_response() else: result = AJAXError(500, "Internal server error.").get_response() request = args[0] logger.error('Internal Server Error: %s' % request.path, exc_info=exc_info, extra={ 'status_code': 500, 'request': request } ) result['Content-Type'] = 'application/json' return result
def _get_record(self): """Fetch a given record. Handles fetching a record from the database along with throwing an appropriate instance of ``AJAXError`. """ if not self.pk: raise AJAXError(400, _('Invalid request for record.')) try: return self.model.objects.get(pk=self.pk) except self.model.DoesNotExist: raise AJAXError(404, _('%s with id of "%s" not found.') % ( self.model.__name__, self.pk))
def endpoint_loader(request, application, model, **kwargs): """Load an AJAX endpoint. This will load either an ad-hoc endpoint or it will load up a model endpoint depending on what it finds. It first attempts to load ``model`` as if it were an ad-hoc endpoint. Alternatively, it will attempt to see if there is a ``ModelEndpoint`` for the given ``model``. """ if request.method != "POST": raise AJAXError(400, _('Invalid HTTP method used.')) try: module = import_module('%s.endpoints' % application) except ImportError, e: raise AJAXError(404, _('AJAX endpoint does not exist.'))
def delete(self, request): record = self._get_record() if self.can_delete(request.user, record): record.delete() return {'pk': int(self.pk)} else: raise AJAXError(403, _("Access to endpoint is forbidden"))
def json_response(response_type='application/json'): @decorator def inner_response(f, *args, **kwargs): """Wrap a view in JSON. This decorator runs the given function and looks out for ajax.AJAXError's, which it encodes into a proper HttpResponse object. If an unknown error is thrown it's encoded as a 500. All errors are then packaged up with an appropriate Content-Type and a JSON body that you can inspect in JavaScript on the client. They look like: { "message": "Error message here.", "code": 500 } Please keep in mind that raw exception messages could very well be exposed to the client if a non-AJAXError is thrown. """ try: result = f(*args, **kwargs) if isinstance(result, AJAXError): raise result else: if not 'status' in result and isinstance(result, dict): result['status'] = 'ok' result = HttpResponse(json.dumps(result, indent=4)) except AJAXError, e: result = e.get_response() except Http404, e: result = AJAXError(e.__str__()).get_response()
def update(self, request): record = self._get_record() modified = self._get_record() update_record = False for key, val in six.iteritems(self._extract_data(request)): # Only setattr and save the model when a change has happened. if val != getattr(record, key): setattr(modified, key, val) update_record = True if self.can_update(request.user, record, modified=modified): if update_record: self._save(modified) try: tags = self._extract_tags(request) if tags: modified.tags.set(*tags) else: # If tags were in the request and set to nothing, we will # clear them all out. modified.tags.clear() except KeyError: pass ajax_updated.send(sender=record.__class__, instance=record) return encoder.encode(modified) else: raise AJAXError(403, _("Access to endpoint is forbidden"))
def upload_profile_image(request): form = ProfileImageForm(files=request.FILES or None) if form.is_valid(): img = form.save(request.user.get_profile()) return {'thumbnail': get_thumbnail(img, "160").url} else: raise AJAXError(_("Uploaded file is not valid!"))
def delete(self, request): record = self._get_record() if self.can_delete(request.user, record): record.delete() ajax_deleted.send(sender=record.__class__, instance=record) return {'pk': int(self.pk)} else: raise AJAXError(403, _("Access to endpoint is forbidden"))
def create(self, request): record = self.model(**self._extract_data(request)) if self.can_create(request.user, record): record = self._save(record) self._set_tags(request, record) return encoder.encode(record) else: raise AJAXError(403, _("Access to endpoint is forbidden"))
def _save(self, record): try: record.full_clean() record.save() return record except ValidationError, e: raise AJAXError(400, _("Could not save model."), errors=e.message_dict)
def update(self, request): record = self._get_record() if self.can_update(request.user, record): for key, val in self._extract_data(request).iteritems(): setattr(record, key, val) return self._encode_record(self._save(record)) else: raise AJAXError(403, _("Access to endpoint is forbidden"))
def upload_pin(request): form = UploadPinForm(files=request.FILES or None) if form.is_valid(): pin = form.save(commit=False) pin.is_active = False pin.save() return { 'pin_pk': pin.pk, 'thumbnail': get_thumbnail(pin.image, "100x100", crop="center").url } else: raise AJAXError(_("Uploaded file is not valid!"))
def create(self, request): record = self.model(**self._extract_data(request)) if self.can_create(request.user, record): record = self._save(record) try: tags = self._extract_tags(request) record.tags.set(*tags) except KeyError: pass return encoder.encode(record) else: raise AJAXError(403, _("Access to endpoint is forbidden"))
def tags(self, request): cmd = self.options.get('taggit_command', None) if not cmd: raise AJAXError(400, _("Invalid or missing taggit command.")) record = self._get_record() if cmd == 'similar': result = record.tags.similar_objects() else: tags = self._extract_tags(request) getattr(record.tags, cmd)(*tags) result = record.tags.all() return encoder.encode(result)
def like_pin(request): """ AJAX view which increments number of likes for pin and returns the new number of likes. """ form = PinLikeForm(request.POST or None) if form.is_valid(): pin = form.cleaned_data['pin'] Like.objects.like_pin(pin, request.user) pin = Pin.objects.select_related().get(pk=pin.pk) return { 'number_of_likes': pin.get_number_of_likes(), } else: raise AJAXError(_("Could not like the pin!"))
def website_media(request): """ Returns a list of media for given URL (from POST['url']) @TODO: We should be checking dimensions of images in URL and return only those which are larger than n pixels. However, if it needs to be done, it needs to be done in asynchronous/multithreaded fashion. For now, only images larger than 15KiB when lossy and 25KiB when lossless are returned. Returned structure is: { 'images': ['http://example.org/image.jpeg',..], 'videos': [{'thumbnail':'<url of thumbnail shown to user>','parser':'<parser class name>', 'video_id': '<video id>'}, ...] } """ form = WebsiteURLForm(request.POST or None) if form.is_valid(): pool = urllib3.PoolManager( headers={ 'User-Agent': 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)' }) url = form.cleaned_data['url'] images = [] website_request = pool.request('GET', url, timeout=4, retries=3) if website_request.status == 200: content_type = website_request.headers['content-type'].split( '/')[1] if content_type in SIZE_LIMITS.keys(): #the given URL is image images.append(url) else: soup = BeautifulSoup(website_request.data) images.extend(find_images(soup, url)) videos = parser_pool.get_results(url) if len(videos) == 0: videos = parser_pool.get_results(website_request.data) return {'images': images, 'videos': convert_videos_to_json(videos)} else: raise AJAXError(msg=_("Could not fetch images."))
def update(self, request): record = self._get_record() if self.can_update(request.user, record): for key, val in self._extract_data(request).iteritems(): setattr(record, key, val) self._save(record) try: tags = self._extract_tags(request) if tags: record.tags.set(*tags) else: # If tags were in the request and set to nothing, we will # clear them all out. record.tags.clear() except KeyError: pass return encoder.encode(record) else: raise AJAXError(403, _("Access to endpoint is forbidden"))
def list(self, request): """ List objects of a model. By default will show page 1 with 20 objects on it. **Usage**:: params = {"items_per_page":10,"page":2} //all params are optional $.post("/ajax/{app}/{model}/list.json"),params) """ max_items_per_page = getattr( self, 'max_per_page', getattr(settings, 'AJAX_MAX_PER_PAGE', 100)) requested_items_per_page = request.POST.get("items_per_page", 20) items_per_page = min(max_items_per_page, requested_items_per_page) current_page = request.POST.get("current_page", 1) if not self.can_list(request.user): raise AJAXError(403, _("Access to this endpoint is forbidden")) objects = self.get_queryset(request) paginator = Paginator(objects, items_per_page) try: page = paginator.page(current_page) except PageNotAnInteger: # If page is not an integer, deliver first page. page = paginator.page(1) except EmptyPage: # If page is out of range (e.g. 9999), return empty list. page = EmptyPageResult() data = [encoder.encode(record) for record in page.object_list] return EnvelopedResponse(data=data, metadata={'total': paginator.count})
def update(self, request): raise AJAXError(404, _("Endpoint does not exist."))
def login_required(f, *args, **kwargs): if not args[0].user.is_authenticated(): raise AJAXError(403, _('User must be authenticated.')) return f(*args, **kwargs)
{ "message": "Error message here.", "code": 500 } Please keep in mind that raw exception messages could very well be exposed to the client if a non-AJAXError is thrown. """ try: result = f(*args, **kwargs) if isinstance(result, AJAXError): raise result except AJAXError, e: result = e.get_response() except Http404, e: result = AJAXError(404, e.__str__()).get_response() except Exception, e: import sys exc_info = sys.exc_info() type, message, trace = exc_info if settings.DEBUG: import traceback tb = [{'file': l[0], 'line': l[1], 'in': l[2], 'code': l[3]} for l in traceback.extract_tb(trace)] result = AJAXError(500, message, traceback=tb).get_response() else: result = AJAXError(500, "Internal server error.").get_response() request = args[0] logger.error('Internal Server Error: %s' % request.path, exc_info=exc_info,
try: result = f(*args, **kwargs) except AJAXError, e: result = e.get_response() except Exception, e: import sys type, message, trace = sys.exc_info() if settings.DEBUG: import traceback tb = [{ 'file': l[0], 'line': l[1], 'in': l[2], 'code': l[3] } for l in traceback.extract_tb(trace)] result = AJAXError(500, message, traceback=tb).get_response() else: result = AJAXError(500, message).get_response() result['Content-Type'] = 'application/json' return result @json_response def endpoint_loader(request, application, model, **kwargs): """Load an AJAX endpoint. This will load either an ad-hoc endpoint or it will load up a model endpoint depending on what it finds. It first attempts to load ``model`` as if it were an ad-hoc endpoint. Alternatively, it will attempt to see if there is a ``ModelEndpoint`` for the given ``model``.
def parse_tags(tagstring): raise AJAXError(500, 'Taggit required: http://bit.ly/RE0dr9')
def right_back_at_you(request): if len(request.POST): return request.POST else: raise AJAXError(500, 'Nothing to echo back.')
def endpoint_loader(request, application, model, **kwargs): """Load an AJAX endpoint. This will load either an ad-hoc endpoint or it will load up a model endpoint depending on what it finds. It first attempts to load ``model`` as if it were an ad-hoc endpoint. Alternatively, it will attempt to see if there is a ``ModelEndpoint`` for the given ``model``. """ if request.method != "POST": raise AJAXError(400, _('Invalid HTTP method used.')) try: module = import_module('%s.endpoints' % application) except ImportError as e: if settings.DEBUG: raise e else: raise AJAXError(404, _('AJAX endpoint does not exist.')) if hasattr(module, model): # This is an ad-hoc endpoint endpoint = getattr(module, model) else: # This is a model endpoint method = kwargs.get('method', 'create').lower() try: del kwargs['method'] except: pass try: model_endpoint = ajax.endpoint.load(model, application, method, **kwargs) if not model_endpoint.authenticate(request, application, method): raise AJAXError(403, _('User is not authorized.')) endpoint = getattr(model_endpoint, method, False) if not endpoint: raise AJAXError(404, _('Invalid method.')) except NotRegistered: raise AJAXError(500, _('Invalid model.')) data = endpoint(request) if isinstance(data, HttpResponse): return data if isinstance(data, EnvelopedResponse): envelope = data.metadata payload = data.data else: envelope = {} payload = data envelope.update({ 'success': True, 'data': payload, }) return HttpResponse(json.dumps(envelope, cls=DjangoJSONEncoder, separators=(',', ':')))
raise result except AJAXError, e: result = e.get_response() request = args[0] logger.warn('AJAXError: %d %s - %s', e.code, request.path, e.msg, exc_info=True, extra={ 'status_code': e.code, 'request': request }) except Http404, e: result = AJAXError(404, e.__str__()).get_response() except Exception, e: import sys exc_info = sys.exc_info() type, message, trace = exc_info if settings.DEBUG: import traceback tb = [{ 'file': l[0], 'line': l[1], 'in': l[2], 'code': l[3] } for l in traceback.extract_tb(trace)] result = AJAXError(500, message, traceback=tb).get_response() else: result = AJAXError(500, "Internal server error.").get_response()
def inner(request, *args, **kwargs): if request.method not in request_method_list: raise AJAXError(403, _('Access denied.')) return func(request, *args, **kwargs)
if hasattr(module, model): # This is an ad-hoc endpoint endpoint = getattr(module, model) else: # This is a model endpoint method = kwargs.get('method', 'create').lower() try: del kwargs['method'] except: pass try: model_endpoint = ajax.endpoint.load(model, application, method, **kwargs) if not model_endpoint.authenticate(request, application, method): raise AJAXError(403, _('User is not authorized.')) endpoint = getattr(model_endpoint, method, False) if not endpoint: raise AJAXError(404, _('Invalid method.')) except NotRegistered: raise AJAXError(500, _('Invalid model.')) data = endpoint(request) if isinstance(data, HttpResponse): return data else: payload = { 'success': True, 'data': data,
def get(self, request): record = self._get_record() if self.can_get(request.user, record): return encoder.encode(record) else: raise AJAXError(403, _("Access to endpoint is forbidden"))
result = f(*args, **kwargs) if isinstance(result, AJAXError): raise result else: if not 'status' in result and isinstance(result, dict): result['status'] = 'ok' result = HttpResponse(json.dumps(result, indent=4)) except AJAXError, e: result = e.get_response() except Http404, e: result = AJAXError(e.__str__()).get_response() except Exception, e: import sys type, message, trace = sys.exc_info() if settings.DEBUG: import traceback tb = [{ 'file': l[0], 'line': l[1], 'in': l[2], 'code': l[3] } for l in traceback.extract_tb(trace)] result = AJAXError(message, traceback=tb).get_response() else: result = AJAXError(message).get_response() result['Content-Type'] = response_type return result return inner_response