def _api_name_from_headers(self, request): self._accept_range = request.META.get('HTTP_ACCEPT', '*/*') # Accepts header can look like: # text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 # So we need to split it apart for use with parse_media_range. ranges = self._accept_range.split(',') try: ranges = [mimeparse.parse_media_range(m) for m in ranges] except ValueError: raise BadRequest('Incorrect accept header') # Then sort the accepted types by their quality, best first. ranges.sort( lambda x, y: cmp(float(y[2].get('q')), float(x[2].get('q')))) for range in ranges: subtype = range[1] for api_name in self._registry.keys(): # We enforce the vnd.api.<api_name>+<type> convention to keep # things simple. E.g. vnd.api.myapi-v2+json or # vnd.api.djangoappv3+xml api_subtype = '{}+'.format( self.api_subtype.format(api_name=api_name)) if subtype.startswith(api_subtype): # This is our match. # Rewrite the Accepts header, removing our # vendor-specific api name so that the rest of our logic # works the same way. request.META['HTTP_ACCEPT'] = self._accept_range.replace( api_subtype, '') return api_name return self._default_api_name
def obj_create(self, bundle, **kwargs): try: # make sure the image is in the request img = Image.open(StringIO(bundle.data['image'].read())) snapimg = SnapImage(img) except KeyError as key: raise BadRequest('Missing field: ' + str(key)) bundle = super(PhotoResource, self).obj_create(bundle, **kwargs) photo = bundle.obj # set the value of the event streamable value photo.is_streamable = photo.event.are_photos_streamable photo.save() # try and watermark if photo.event.are_photos_watermarked == True: try: # save the image to cloudfiles watermark = photo.event.get_watermark() photo.save_image(snapimg, True, watermark=watermark) except Exception as e: # save the image to cloudfiles photo.save_image(snapimg, True) else: # save the image to cloudfiles photo.save_image(snapimg, True) return bundle
def obj_get_list(self, request=None, **kwargs): """overridden just to pass the `request` to build_filters""" filters = request.GET.copy() if hasattr(request, 'GET') else dict() # Update with the provided kwargs. filters.update(kwargs) # Drop request's user into filters filters['_user'] = request.user applicable_filters = self.build_filters(filters=filters) try: qs = self.get_object_list(request).filter(**applicable_filters) q_filter = filters.get('q', None) if q_filter: qs = qs.ft_search(q_filter) if filters.get('place'): qs = qs.order_by('event__occurrences__start_datetime') qs = self.apply_authorization_limits(request, qs) # FIXME somehow, running __str__ on this query fixes it, otherwise broken _ = str(qs.query) return OrderedDict( (event_summary, None) for event_summary in qs).keys() except ValueError: raise BadRequest( "Invalid resource lookup data provided (mismatched type).")
def get_dataset_from_kwargs(self, bundle, **kwargs): """ Extract a dataset from one of the variety of places it might be hiding. """ kwargs_slug = kwargs['dataset_slug'] bundle_uri = None bundle_slug = None if bundle: bundle_uri = bundle.data.pop('dataset', None) if bundle_uri: prefix = get_script_prefix() if prefix and bundle_uri.startswith(prefix): bundle_uri = bundle_uri[len(prefix) - 1:] view, args, kwargs = resolve(bundle_uri) bundle_slug = kwargs['slug'] if bundle_slug and bundle_slug != kwargs_slug: raise BadRequest( 'Dataset specified in request body does not agree with dataset API endpoint used.' ) return Dataset.objects.get(slug=kwargs_slug)
def apply_filters(self, request, applicable_filters): """ Instead of overriding prepend_url() method, we added a new filter "genes" to retrieve the edges whose "gene1" or "gene2" field is on the list of genes in a URL like this: api/v0/edge/?genes=id1,id2,...&... """ object_list = super(EdgeResource, self).apply_filters(request, applicable_filters) genes = request.GET.get('genes', None) if genes: # Instead of relying on tastypie/resources.py to catch the # ValueError exception that may be raised in this function, # we catch the one that may be raised by int() below and # raise a customized BadRequest exception with more details. try: # Convert genes to a set of integers so that the # duplicate(s) will be removed implicitly. ids = {int(id) for id in genes.split(',')} except ValueError: raise BadRequest("Invalid gene IDs: %s" % genes) # "in" operator in Django supports both list and set. qset = Q(gene1__in=ids) | Q(gene2__in=ids) direct_edges = object_list.filter(qset).distinct() related_genes = set() for e in direct_edges: related_genes.add(e.gene1) related_genes.add(e.gene2) object_list = object_list.filter( gene1__in=related_genes, gene2__in=related_genes).distinct() return object_list
def obj_get(self, bundle, **kwargs): domain = kwargs['domain'] location_id = kwargs['pk'] if not user_can_access_location_id(domain, bundle.request.couch_user, location_id): raise BadRequest(LOCATION_ACCESS_DENIED) return get_location_or_not_exist(location_id, domain)
def obj_create(self, bundle, **kwargs): try: template_id = bundle.data.pop('template_id', '') biz_cc_id = bundle.data.pop('biz_cc_id') template = TaskTemplate.objects.get(pk=template_id, business__cc_id=biz_cc_id) except Exception: raise BadRequest('template[id=%s] in business[%s] does not exist' % (template_id, biz_cc_id)) business = get_business_for_user(bundle.request.user, ['view_business']) if not business.filter(cc_id=biz_cc_id).exists(): raise ImmediateHttpResponse(HttpResponseForbidden('you have no permission to make such operation')) bundle.data['name'] = name_handler(bundle.data['name'], TEMPLATE_NODE_NAME_MAX_LENGTH) kwargs['unique_id'] = '%s-%s' % (template_id, bundle.data['name']) if TemplateScheme.objects.filter(unique_id=kwargs['unique_id']).exists(): raise BadRequest('template scheme name has existed, please change the name') kwargs['template'] = template.pipeline_template return super(TemplateSchemeResource, self).obj_create(bundle, **kwargs)
def obj_create(self, bundle, request=None, **kwargs): # create a new File bundle.obj = FileItem() # full_hydrate does the heavy lifting mapping the # POST-ed payload key/values to object attribute/values bundle = self.full_hydrate(bundle) filename_name, file_extension = os.path.splitext( bundle.data[u'file'].name) # -- only allow uploading of files of types specified in FILESERVICE_CONFIG.types_allowed types_allowed = helpers.get_fileservice_whitelist() if '*' not in types_allowed and file_extension.lower( ) not in types_allowed: raise BadRequest( 'file type is not whitelisted in FILESERVICE_CONFIG.types_allowed' ) file_data = bundle.data[u'file'].read() # TODO: support optional unique name generation from sha1 and uuid. # file_sha1 = hashlib.sha1(file_data).hexdigest() # is file_data only the bytes without filename etc? # if file_extension: # filename_name = '{}{}'.format(file_sha1, file_extension) # else: # filename_name = file_sha1 # TODO: if the filename uploaded is not a valid sha1, warn that it should at least be unique. bundle.obj.name = bundle.data[u'file'].name with open(helpers.get_filename_absolute(bundle.data[u'file'].name), 'wb+') as destination_file: destination_file.write(file_data) # remove the file object passed in so that the response is more concise about what this file will be referred to bundle.data.pop(u'file', None) return bundle
def apply_filters(self, request, applicable_filters): one_of = ['contest_id__exact', 'account_id__exact', 'coder_id'] for k in one_of: if applicable_filters.get(f'{k}'): break else: raise BadRequest( f'One of {[k.split("__")[0] for k in one_of]} is required') rating_change_isnull = applicable_filters.pop('rating_change__isnull', None) new_rating_isnull = applicable_filters.pop('new_rating__isnull', None) coder_id = applicable_filters.pop('coder_id', None) qs = super().apply_filters(request, applicable_filters) qs = qs.select_related('account', 'contest') if rating_change_isnull: qs = qs.filter( addition__rating_change__isnull=rating_change_isnull[0] in ['true', '1', 'yes']) if new_rating_isnull: qs = qs.filter(addition__new_rating__isnull=new_rating_isnull[0] in ['true', '1', 'yes']) if coder_id: qs = qs.filter(account__coders=coder_id[0]) qs = qs \ .annotate(new_rating=Cast(KeyTextTransform('new_rating', 'addition'), IntegerField())) \ .annotate(old_rating=Cast(KeyTextTransform('old_rating', 'addition'), IntegerField())) \ .annotate(rating_change=Cast(KeyTextTransform('rating_change', 'addition'), IntegerField())) return qs
def from_xml(self, content, forbid_dtd=True, forbid_entities=True): """ Given some XML data, returns a Python dictionary of the decoded data. By default XML entity declarations and DTDs will raise a BadRequest exception content but subclasses may choose to override this if necessary. """ if lxml is None: raise ImproperlyConfigured( "Usage of the XML aspects requires lxml and defusedxml.") try: # Stripping the encoding declaration. Because lxml. # See http://lxml.de/parsing.html, "Python unicode strings". content = XML_ENCODING.sub('', content) parsed = parse_xml( six.StringIO(content), forbid_dtd=forbid_dtd, forbid_entities=forbid_entities ) except (LxmlError, DefusedXmlException): raise BadRequest() return self.from_etree(parsed.getroot())
def preprocess_filters(self, filters, for_cache_key=False): ret = {} for filter_expr, value in list(filters.items()): filter_bits = filter_expr.split(LOOKUP_SEP) if filter_expr == 'similarity': continue if len(filter_bits) and filter_bits[-1] == 'flexmatch': if not value.strip(): raise BadRequest("Input string is empty") if value.upper().startswith('CHEMBL'): try: mol = MoleculeDictionary.objects.get( chembl_id=value.upper()) smiles = mol.compoundstructures.canonical_smiles value = smiles except ObjectDoesNotExist: raise ImmediateHttpResponse( response=http.HttpNotFound()) if not for_cache_key: molecule_chembl_ids_flexmatch = self.elastic_search_flexmatch( value) ret["molecule_chembl_id__in"] = molecule_chembl_ids_flexmatch continue ret[filter_expr] = value return ret
def login_help(self, request, **kwargs): """ Set the status of the "show_login_help" flag. """ self.method_check(request, allowed=['post']) self.is_authenticated(request) self.throttle_check(request) if 'pk' in kwargs: get_id = int(kwargs['pk']) else: get_id = int(request.GET.get('id', '')) # CHECK AUTHORIZATION if request and not request.user.is_superuser and get_id != request.user.id: raise ImmediateHttpResponse(response=http.HttpUnauthorized()) deserialized = self.deserialize(request, request.raw_post_data, format=request.META.get( 'CONTENT_TYPE', 'application/json')) deserialized = self.alter_deserialized_list_data(request, deserialized) if not 'show_login_help' in deserialized: raise BadRequest(_("Invalid data sent.")) user = UserProxy.objects.get(id=get_id) profile = user.get_profile() profile.show_login_help = deserialized['show_login_help'] profile.save() return self.create_response(request, {}, response_class=http.HttpAccepted)
def get_object_class(self, bundle=None, **kwargs): if bundle.data.get('file', None): return LocalDataSet elif bundle.data.get('url', None): return ExternalDataSet else: raise BadRequest("You must provide either a file or URL when creating a data set")
def hydrate_image(self, bundle): if bundle.obj.asset_id and hasattr(bundle.obj, 'image'): try: image = Image.objects.get(localimageassettranslation__asset__asset_id=bundle.obj.asset_id) if image.file.url == bundle.data['image']: bundle.data["image"] = image return bundle except Exception: pass if ('image' in bundle.data and isinstance(bundle.data['image'], UploadedFile)): # The image data is an uploaded file # Make sure the file format is supported if not image_type_supported(bundle.data['image']): raise BadRequest("Unsupported image format") # Create an image object and add it to the bundle image = Image.objects.create(file=bundle.data['image']) bundle.data['image'] = image return bundle else: # Treat the image data as data-url-encoded # file return self._hydrate_file(bundle, Image, 'image', 'filename')
def obj_get_list(self, bundle, **kwargs): domain = kwargs['domain'] project = getattr(bundle.request, 'project', self.domain_obj(domain)) parent_id = bundle.request.GET.get('parent_id', None) include_inactive = json.loads(bundle.request.GET.get('include_inactive', 'false')) user = bundle.request.couch_user if not parent_id: if not user.has_permission(domain, 'access_all_locations'): raise BadRequest(LOCATION_ACCESS_DENIED) return SQLLocation.root_locations(domain, include_inactive) else: if not user_can_access_location_id(kwargs['domain'], user, parent_id): raise BadRequest(LOCATION_ACCESS_DENIED) parent = get_location_or_not_exist(parent_id, domain) return self.child_queryset(domain, include_inactive, parent)
def dispatch(self, request_type, request, **kwargs): """ Override dispatch to check for proper params for user create : role and admin permissions """ if request.method == 'POST': details = self._meta.serializer.deserialize(request.body) if details.get('is_admin', False): if self._admin_assigned_another_role(details): raise BadRequest("An admin can have only one role : Admin") else: if not details.get('role', None): raise BadRequest("Please assign role for non admin user") elif self._invalid_user_role(request, details): raise BadRequest("Invalid User Role %s" % details.get('role', None)) return super(WebUserResource, self).dispatch(request_type, request, **kwargs)
def obj_update(self, bundle, skip_errors=False, **kwargs): from django.db import transaction SetTopBox = apps.get_model('client', 'SetTopBox') log.debug( 'Update key:%s=%s (%s)', bundle.data.get('key'), bundle.data.get('value'), bundle.data.get('value_type') ) if bundle.request.user.is_anonymous() is False: user = bundle.request.user serial = user.username.replace(settings.STB_USER_PREFIX, '') stb = SetTopBox.objects.get(serial_number=serial) self._meta.queryset.filter(settopbox=stb) log.debug('User:%s, SetTopBox:%s', user, stb) # TODO: Não deixar um STB moduficar as configs de outro STB # if bundle.obj.settopbox_id != stb.id: # raise BadRequest('') with transaction.atomic(): try: # print(dir(bundle.obj)) bundle = super(SetTopBoxConfigResource, self).obj_update( bundle, **kwargs ) except IntegrityError as e: log.error('%s', e) raise BadRequest(e) return bundle
def patch_list(self, request=None, **kwargs): """ Exactly copied from https://github.com/toastdriven/django-tastypie/blob/v0.9.14/tastypie/resources.py#L1466 (BSD licensed) and modified to pass the kwargs to `obj_create` and support only create method """ request = convert_post_to_patch(request) deserialized = self.deserialize(request, request.body, format=request.META.get('CONTENT_TYPE', 'application/json')) collection_name = self._meta.collection_name if collection_name not in deserialized: raise BadRequest("Invalid data sent: missing '%s'" % collection_name) if len(deserialized[collection_name]) and 'put' not in self._meta.detail_allowed_methods: raise ImmediateHttpResponse(response=http.HttpMethodNotAllowed()) bundles_seen = [] status = http.HttpAccepted for data in deserialized[collection_name]: data = self.alter_deserialized_detail_data(request, data) bundle = self.build_bundle(data=dict_strip_unicode_keys(data), request=request) try: self.obj_create(bundle=bundle, **self.remove_api_resource_names(kwargs)) except AssertionError as ex: status = http.HttpBadRequest bundle.data['_id'] = ex.message bundles_seen.append(bundle) to_be_serialized = [bundle.data['_id'] for bundle in bundles_seen] return self.create_response(request, to_be_serialized, response_class=status)
def obj_get_list(self, bundle, domain, **kwargs): include_archived = 'include_archived' in bundle.request.GET try: es_query = es_search(bundle.request, domain, ['include_archived']) except Http400 as e: raise BadRequest(e.message) if include_archived: es_query['filter']['and'].append({ 'or': [ { 'term': { 'doc_type': 'xforminstance' } }, { 'term': { 'doc_type': 'xformarchived' } }, ] }) else: es_query['filter']['and'].append( {'term': { 'doc_type': 'xforminstance' }}) # Note that XFormES is used only as an ES client, for `run_query` against the proper index return ElasticAPIQuerySet( payload=es_query, model=ESXFormInstance, es_client=self.xform_es(domain)).order_by('-received_on')
def apply_sorting(self, obj_list, options=None): global FACES_LEN if options.get("order_by") in ["random", "-random"]: # Pseudorandom ordering because mysql random is inefficent limit = int(options.get("limit", 1)) if limit > 5: raise BadRequest("at most 5 randoms at a time") obj_list = obj_list.all() if options.get("tags__all") or options.get("tags__any"): faces_len = len(obj_list) else: if FACES_LEN == -1 or random.randint(0, 1000) > 999: FACES_LEN = len(obj_list) faces_len = FACES_LEN if limit >= faces_len: return obj_list else: i = random.randint(0, faces_len - 1 - limit) orders = [ "id", "-id", "source", "-source", "md5", "-md5", "width", "-width", "height", "-height", "hotness", "-hotness", "views", "-views" ] ordered_list = obj_list.order_by(random.choice(orders)) return ordered_list[i:i + limit + 1] return super(FaceResource, self).apply_sorting(obj_list, options)
def obj_delete(self, bundle, **kwargs): try: task_tmpl = TaskTemplate.objects.get(id=kwargs['pk']) except TaskTemplate.DoesNotExist: raise BadRequest('template does not exist') referencer = task_tmpl.referencer() if referencer: flat = ','.join( ['%s:%s' % (item['id'], item['name']) for item in referencer]) raise BadRequest( 'flow template are referenced by other templates[%s], please delete them first' % flat) result = super(TaskTemplateResource, self).obj_delete(bundle, **kwargs) if result: task_tmpl.set_deleted() return result
def get_list(self, request=None, **kwargs): filename = request.GET.get("filename") if filename: source, tags = models._detectSource(filename) else: raise BadRequest("'filename' is required parameter") return self.create_response(request, {"source": source, "tags": tags})
def apply_filters(self, request, applicable_filters): object_list = super(SignatureResource, self).apply_filters(request, applicable_filters) heavy_genes = request.GET.get('heavy_genes', None) if heavy_genes: # Instead of relying on tastypie/resources.py to catch the # ValueError exception that may be raised in this function, # we catch the one that may be raised by int() below and # raise a customized BadRequest exception with more details. try: # Convert genes to a set of integers so that the # duplicate(s) will be removed implicitly. query_genes = {int(id) for id in heavy_genes.split(',')} except ValueError: raise BadRequest("Invalid gene IDs: %s" % heavy_genes) for (i, q) in enumerate(query_genes): q_signatures = { p.signature.id for p in Participation.objects.filter(gene=q) } if i == 0: related_signatures = q_signatures else: related_signatures = related_signatures & q_signatures object_list = object_list.filter(id__in=related_signatures) return object_list
def generic_xls_write_workbook(file, data): ''' Writes a dict of iterables to a workbook, where key=sheet name, value=iterable that is ready to write (e.g. a list) ''' wb = xlsxwriter.Workbook(file, {'constant_memory': True}) if isinstance(data, dict): logger.info('generic_xls_write_workbook for data: %r', data.keys()) for key, sheet_rows in data.items(): sheet_name = default_converter(key) logger.info('writing sheet %r...', sheet_name) sheet = wb.add_worksheet(sheet_name) if isinstance(sheet_rows, dict): for i, row in enumerate(csvutils.dict_to_rows(sheet_rows)): sheet.write_row(i, 0, row) elif isinstance(sheet_rows, basestring): sheet.write_string(0, 0, sheet_rows) else: generic_write_rows_to_sheet(sheet_rows, sheet) else: raise BadRequest('unknown data for generic xls serialization: %r' % type(data)) logger.info('save to file; %r', file.name) wb.close()
def obj_create(self, bundle, **kwargs): required = [ 'username', ] check_required_params(bundle, required) bundle.obj.username = bundle.data['username'] try: user = User.objects.get(username__exact=bundle.obj.username) except User.DoesNotExist: try: user = User.objects.get(email__exact=bundle.obj.username) except User.DoesNotExist: raise BadRequest(_(u'Username/email not found')) newpass = User.objects.make_random_password(length=8) user.set_password(newpass) user.save() if bundle.request.is_secure(): prefix = 'https://' else: prefix = 'http://' emailer.send_oppia_email( template_html='profile/email/password_reset.html', template_text='profile/email/password_reset.txt', subject="Password reset", fail_silently=False, recipients=[user.email], new_password=newpass, site=prefix + bundle.request.META['SERVER_NAME']) return bundle
def obj_update(self, bundle, **kwargs): if 'data_type_id' not in bundle.data: raise BadRequest("data_type_id must be specified") try: bundle.obj = FixtureDataItem.get(kwargs['pk']) except ResourceNotFound: raise NotFound('Lookup table item not found') if bundle.obj.domain != kwargs['domain']: raise NotFound('Lookup table item not found') save = False if 'fields' in bundle.data: save = True bundle.obj.fields = { field_name: FieldList.wrap(field_list) for field_name, field_list in bundle.data['fields'].items() } if 'item_attributes' in bundle.data: save = True bundle.obj.item_attributes = bundle.data['item_attributes'] if save: bundle.obj.save() return bundle
def get_search(self, request, **kwargs): self.method_check(request, allowed=['get']) self.is_authenticated(request) self.throttle_check(request) print request.GET query = request.GET.get('q', None) if not query: raise BadRequest( 'Please supply the search parameter (e.g. "/api/v1/notes/search/?q=css")' ) # results = SearchQuerySet().models(Note).filter(user=request.user).auto_query(query) results = SearchQuerySet().models(Donate).auto_query(query) if not results: results = EmptySearchQuerySet() paginator = Paginator(request.GET, results, resource_uri='/api/v1/notes/search/') bundles = [] for result in paginator.page()['objects']: bundle = self.build_bundle(obj=result.object, request=request) bundles.append(self.full_dehydrate(bundle)) object_list = {'meta': paginator.page()['meta'], 'objects': bundles} object_list['meta']['search_query'] = query self.log_throttled_access(request) return self.create_response(request, object_list)
def is_authenticated(self, request, **kwargs): # check for the environment variable to skip auth if not SNAP_AUTHENTICATION: return True try: # get the Authorization header auth = request.META['HTTP_AUTHORIZATION'].strip().split(' ') auth_snap = auth[0].lower() # get signature info from the Authorization header auth_params = api.auth.get_auth_params(request) # add the parts to proper varibles for signature api_key = get_api_key(auth_params['key']) signature = auth_params['signature'] snap_nonce = auth_params['nonce'] snap_timestamp = auth_params['timestamp'] # create the raw string to hash and calculate hashed value raw = api_key.key + request.method + request.path + snap_nonce + snap_timestamp hashed = hmac.new(str(api_key.secret), raw, hashlib.sha1) # calculate time differences snap_datetime = datetime.fromtimestamp( int(snap_timestamp), tz=pytz.utc) # parse the date header now_datetime = datetime.now(pytz.utc) # current time on server pre_now_datetime = now_datetime + timedelta( 0, -300) # 5 minutes in the past post_now_datetime = now_datetime + timedelta( 0, 300) # 5 minutes in the future # time check if snap_datetime < pre_now_datetime or snap_datetime > post_now_datetime: raise BadRequest( 'Timestamp must be within +/- 5mins from Snapable API server clock.' ) # if all conditions pass, return true if auth_snap == 'snap' and signature == hashed.hexdigest(): return True else: return False # we failed, return false except KeyError: raise BadRequest('Missing authentication param') except ApiKey.DoesNotExist: raise BadRequest('The API key does not exist')
def _get_start_param(self, bundle): try: start = int(bundle.request.GET.get('offset', 0)) if start < 0: raise ValueError except (ValueError, TypeError): raise BadRequest("start must be a positive integer.") return start
def obj_create(self, bundle, **kwargs): try: bundle = super(UserResource, self).obj_create(bundle, **kwargs) bundle.obj.set_password(bundle.data.get('password1')) bundle.obj.save() except IntegrityError: raise BadRequest('That username already exists') return bundle