class ExerciseResource(Resource): ancestor_ids = fields.CharField(attribute='ancestor_ids') lang = fields.CharField(attribute='lang', default='en') kind = fields.CharField(attribute='kind') all_assessment_items = fields.ListField(attribute='all_assessment_items') display_name = fields.CharField(attribute='display_name') description = fields.CharField(attribute='description') y_pos = fields.IntegerField(attribute='y_pos', default=0) title = fields.CharField(attribute='title') prerequisites = fields.ListField(attribute='prerequisites') name = fields.CharField(attribute='name') id = fields.CharField(attribute='id') seconds_per_fast_problem = fields.CharField( attribute='seconds_per_fast_problem') parent_id = fields.CharField(attribute='parent_id', null=True) template = fields.CharField(attribute='template') path = fields.CharField(attribute='path') x_pos = fields.IntegerField(attribute='x_pos', default=0) slug = fields.CharField(attribute='slug') exercise_id = fields.CharField(attribute='exercise_id') uses_assessment_items = fields.BooleanField( attribute='uses_assessment_items') class Meta: resource_name = 'exercise' object_class = Exercise def prepend_urls(self): return [ url(r"^(?P<resource_name>%s)/(?P<id>[\w\d_.-]+)/$" % self._meta.resource_name, self.wrap_view('dispatch_detail'), name="api_dispatch_detail"), ] def detail_uri_kwargs(self, bundle_or_obj): kwargs = {} if getattr(bundle_or_obj, 'obj', None): kwargs['pk'] = bundle_or_obj.obj.id else: kwargs['pk'] = bundle_or_obj.id return kwargs def obj_get_list(self, bundle, **kwargs): """ Get the list of exercises. """ raise NotImplemented("Operation not implemented yet for videos.") def obj_get(self, bundle, **kwargs): id = kwargs.get("id", None) exercise = get_exercise_data(bundle.request, id) if exercise: return Exercise(**exercise) else: raise NotFound('Exercise with id %s not found' % id) def obj_create(self, bundle, **kwargs): raise NotImplemented("Operation not implemented yet for exercises.") def obj_update(self, bundle, **kwargs): raise NotImplemented("Operation not implemented yet for exercises.") def obj_delete_list(self, bundle, **kwargs): raise NotImplemented("Operation not implemented yet for exercises.") def obj_delete(self, bundle, **kwargs): raise NotImplemented("Operation not implemented yet for exercises.") def rollback(self, bundles): raise NotImplemented("Operation not implemented yet for exercises.")
class BaseJobResource(ModelResource): tags = fields.ListField() def obj_delete(self, bundle, **kwargs): bundle.data['status'] = 'removed' return super(BaseJobResource, self).obj_update(bundle, **kwargs) def authorized_read_detail(self, object_list, bundle): """ Handles checking of permissions to see if the user has authorization to GET this resource. Over-riding version from parent class because we want to allow raising NotFound errors. """ try: auth_result = self._meta.authorization.read_detail( object_list, bundle) if not auth_result is True: raise Unauthorized() except Unauthorized as e: self.unauthorized_result(e) except NotFound as e: raise ImmediateHttpResponse(response=HttpResponseNotFound()) return auth_result def authorized_update_detail(self, object_list, bundle): """ Handles checking of permissions to see if the user has authorization to PUT this resource. Over-riding version from parent class because we want to allow raising NotFound errors. """ try: auth_result = self._meta.authorization.update_detail( object_list, bundle) if auth_result is not True: raise Unauthorized() except Unauthorized as e: #self.unauthorized_result(e) raise ImmediateHttpResponse(response=HttpResponseForbidden()) except NotFound as e: raise ImmediateHttpResponse(response=HttpResponseNotFound()) return auth_result def dehydrate_tags(self, bundle): """ Extract tags to display them as a list of strings """ return [tag.name for tag in bundle.obj.tags.all()] def save_m2m(self, bundle): """ Save tags """ tags = bundle.data.get('tags', []) bundle.obj.tags.set(*tags) return super(BaseJobResource, self).save_m2m(bundle)
class MediatorResource(BaseResource): mediator_label = fields.CharField() assigned_villages = fields.ListField() partner = fields.ForeignKey('coco.api.PartnerResource', 'partner') district = fields.ForeignKey('coco.api.DistrictResource', 'district', null=True) class Meta: max_limit = None authentication = SessionAuthentication() queryset = Animator.objects.prefetch_related('assigned_villages', 'district', 'partner').all() resource_name = 'mediator' authorization = MediatorAuthorization() validation = ModelFormValidation(form_class=AnimatorForm) always_return_data = True excludes = ['time_created', 'time_modified'] dehydrate_partner = partial(foreign_key_to_id, field_name='partner', sub_field_names=['id', 'partner_name']) dehydrate_district = partial(foreign_key_to_id, field_name='district', sub_field_names=['id', 'district_name']) hydrate_assigned_villages = partial(dict_to_foreign_uri_m2m, field_name='assigned_villages', resource_name='village') hydrate_district = partial(dict_to_foreign_uri, field_name='district') def dehydrate_assigned_villages(self, bundle): return [{ 'id': vil.id, 'village_name': vil.village_name } for vil in set(bundle.obj.assigned_villages.all())] def dehydrate_mediator_label(self, bundle): #for sending out label incase of dropdowns return ','.join([ vil.village_name for vil in set(bundle.obj.assigned_villages.all()) ]) def obj_create(self, bundle, **kwargs): bundle = super(MediatorResource, self).obj_create(bundle, **kwargs) vil_list = bundle.data.get('assigned_villages') for vil in vil_list: vil = Village.objects.get(id=int(vil.split('/')[-2])) u = AnimatorAssignedVillage(animator=bundle.obj, village=vil) u.save() bundle.obj.role = 0 return bundle def obj_update(self, bundle, **kwargs): #Edit case many to many handling. First clear out the previous related objects and create new objects bundle = super(MediatorResource, self).obj_update(bundle, **kwargs) mediator_id = bundle.data.get('id') vil_id_list = [] for vil_resource in bundle.data.get('assigned_villages'): vil_id_list.append(int(vil_resource.split('/')[-2])) existing_vil_ids = AnimatorAssignedVillage.objects.filter( animator__id=mediator_id).values_list('village__id', flat=True) #delete only if assigned villages are different if len(list(set(vil_id_list) & set(existing_vil_ids))) != len(vil_id_list): #first delete the old associations del_objs = AnimatorAssignedVillage.objects.filter( animator__id=mediator_id).delete() #add new villages again vil_list = bundle.data.get('assigned_villages') for vil in vil_list: vil = Village.objects.get(id=int(vil.split('/')[-2])) u = AnimatorAssignedVillage(animator=bundle.obj, village=vil) u.save() bundle.obj.role = 0 return bundle def hydrate_partner(self, bundle): partner_id = get_user_partner_id(bundle.request.user.id) if partner_id: bundle.data['partner'] = "/coco/api/v2/partner/" + str( partner_id) + "/" return bundle
class LayerResource(CommonModelApi): """Layer API""" links = fields.ListField( attribute='links', null=True, use_in='all', default=[]) if check_ogc_backend(qgis_server.BACKEND_PACKAGE): default_style = fields.ForeignKey( 'geonode.api.api.StyleResource', attribute='qgis_default_style', null=True) styles = fields.ManyToManyField( 'geonode.api.api.StyleResource', attribute='qgis_styles', null=True, use_in='detail') elif check_ogc_backend(geoserver.BACKEND_PACKAGE): default_style = fields.ForeignKey( 'geonode.api.api.StyleResource', attribute='default_style', null=True) styles = fields.ManyToManyField( 'geonode.api.api.StyleResource', attribute='styles', null=True, use_in='detail') def format_objects(self, objects): """ Formats the object. """ formatted_objects = [] for obj in objects: # convert the object to a dict using the standard values. # includes other values values = self.VALUES + [ 'alternate', 'name' ] formatted_obj = model_to_dict(obj, fields=values) username = obj.owner.get_username() full_name = (obj.owner.get_full_name() or username) formatted_obj['owner__username'] = username formatted_obj['owner_name'] = full_name if obj.category: formatted_obj['category__gn_description'] = obj.category.gn_description if obj.group: formatted_obj['group'] = obj.group try: formatted_obj['group_name'] = GroupProfile.objects.get(slug=obj.group.name) except GroupProfile.DoesNotExist: formatted_obj['group_name'] = obj.group formatted_obj['keywords'] = [k.name for k in obj.keywords.all()] if obj.keywords else [] formatted_obj['regions'] = [r.name for r in obj.regions.all()] if obj.regions else [] # provide style information bundle = self.build_bundle(obj=obj) formatted_obj['default_style'] = self.default_style.dehydrate( bundle, for_list=True) # Add resource uri formatted_obj['resource_uri'] = self.get_resource_uri(bundle) formatted_obj['links'] = self.dehydrate_ogc_links(bundle) if 'site_url' not in formatted_obj or len(formatted_obj['site_url']) == 0: formatted_obj['site_url'] = settings.SITEURL # Probe Remote Services formatted_obj['store_type'] = 'dataset' formatted_obj['online'] = True if hasattr(obj, 'storeType'): formatted_obj['store_type'] = obj.storeType if obj.storeType == 'remoteStore' and hasattr(obj, 'remote_service'): if obj.remote_service: formatted_obj['online'] = (obj.remote_service.probe == 200) else: formatted_obj['online'] = False formatted_obj['gtype'] = self.dehydrate_gtype(bundle) # replace thumbnail_url with curated_thumbs if hasattr(obj, 'curatedthumbnail'): formatted_obj['thumbnail_url'] = obj.curatedthumbnail.img_thumbnail.url # put the object on the response stack formatted_objects.append(formatted_obj) return formatted_objects def _dehydrate_links(self, bundle, link_types=None): """Dehydrate links field.""" dehydrated = [] obj = bundle.obj link_fields = [ 'extension', 'link_type', 'name', 'mime', 'url' ] links = obj.link_set.all() if link_types: links = links.filter(link_type__in=link_types) for l in links: formatted_link = model_to_dict(l, fields=link_fields) dehydrated.append(formatted_link) return dehydrated def dehydrate_links(self, bundle): return self._dehydrate_links(bundle) def dehydrate_ogc_links(self, bundle): return self._dehydrate_links(bundle, ['OGC:WMS', 'OGC:WFS', 'OGC:WCS']) def dehydrate_gtype(self, bundle): return bundle.obj.gtype def populate_object(self, obj): """Populate results with necessary fields :param obj: Layer obj :type obj: Layer :return: """ if check_ogc_backend(qgis_server.BACKEND_PACKAGE): # Provides custom links for QGIS Server styles info # Default style try: obj.qgis_default_style = obj.qgis_layer.default_style except BaseException: obj.qgis_default_style = None # Styles try: obj.qgis_styles = obj.qgis_layer.styles except BaseException: obj.qgis_styles = [] return obj def build_bundle( self, obj=None, data=None, request=None, **kwargs): """Override build_bundle method to add additional info.""" if obj is None and self._meta.object_class: obj = self._meta.object_class() elif obj: obj = self.populate_object(obj) return Bundle( obj=obj, data=data, request=request, **kwargs) def patch_detail(self, request, **kwargs): """Allow patch request to update default_style. Request body must match this: { 'default_style': <resource_uri_to_style> } """ reason = 'Can only patch "default_style" field.' try: body = json.loads(request.body) if 'default_style' not in body: return http.HttpBadRequest(reason=reason) match = resolve(body['default_style']) style_id = match.kwargs['id'] api_name = match.kwargs['api_name'] resource_name = match.kwargs['resource_name'] if not (resource_name == 'styles' and api_name == 'api'): raise Exception() from geonode.qgis_server.models import QGISServerStyle style = QGISServerStyle.objects.get(id=style_id) layer_id = kwargs['id'] layer = Layer.objects.get(id=layer_id) except BaseException: return http.HttpBadRequest(reason=reason) from geonode.qgis_server.views import default_qml_style request.method = 'POST' response = default_qml_style( request, layername=layer.name, style_name=style.name) if isinstance(response, TemplateResponse): if response.status_code == 200: return HttpResponse(status=200) return self.error_response(request, response.content) # copy parent attribute before modifying VALUES = CommonModelApi.VALUES[:] VALUES.append('typename') class Meta(CommonMetaApi): paginator_class = CrossSiteXHRPaginator queryset = Layer.objects.distinct().order_by('-date') resource_name = 'layers' detail_uri_name = 'id' include_resource_uri = True allowed_methods = ['get', 'patch'] excludes = ['csw_anytext', 'metadata_xml'] authentication = MultiAuthentication(SessionAuthentication(), OAuthAuthentication(), GeonodeApiKeyAuthentication()) filtering = CommonMetaApi.filtering # Allow filtering using ID filtering.update({ 'id': ALL, 'name': ALL, 'alternate': ALL, })
class LayerResource(CommonModelApi): """Dataset API""" links = fields.ListField(attribute='links', null=True, use_in='all', default=[]) if check_ogc_backend(geoserver.BACKEND_PACKAGE): default_style = fields.ForeignKey('geonode.api.api.StyleResource', attribute='default_style', null=True) styles = fields.ManyToManyField('geonode.api.api.StyleResource', attribute='styles', null=True, use_in='detail') def build_filters(self, filters=None, ignore_bad_filters=False, **kwargs): _filters = filters.copy() metadata_only = _filters.pop('metadata_only', False) orm_filters = super().build_filters(_filters) orm_filters[ 'metadata_only'] = False if not metadata_only else metadata_only[0] return orm_filters def format_objects(self, objects): """ Formats the object. """ formatted_objects = [] for obj in objects: # convert the object to a dict using the standard values. # includes other values values = self.VALUES + ['alternate', 'name'] formatted_obj = model_to_dict(obj, fields=values) username = obj.owner.get_username() full_name = (obj.owner.get_full_name() or username) formatted_obj['owner__username'] = username formatted_obj['owner_name'] = full_name if obj.category: formatted_obj['category__gn_description'] = _( obj.category.gn_description) if obj.group: formatted_obj['group'] = obj.group try: formatted_obj['group_name'] = GroupProfile.objects.get( slug=obj.group.name) except GroupProfile.DoesNotExist: formatted_obj['group_name'] = obj.group formatted_obj['keywords'] = [k.name for k in obj.keywords.all() ] if obj.keywords else [] formatted_obj['regions'] = [r.name for r in obj.regions.all() ] if obj.regions else [] # provide style information bundle = self.build_bundle(obj=obj) formatted_obj['default_style'] = self.default_style.dehydrate( bundle, for_list=True) # Add resource uri formatted_obj['resource_uri'] = self.get_resource_uri(bundle) formatted_obj['links'] = self.dehydrate_ogc_links(bundle) if 'site_url' not in formatted_obj or len( formatted_obj['site_url']) == 0: formatted_obj['site_url'] = settings.SITEURL # Probe Remote Services formatted_obj['store_type'] = 'dataset' formatted_obj['online'] = True if hasattr(obj, 'subtype'): formatted_obj['store_type'] = obj.subtype if obj.subtype in ['tileStore', 'remote'] and hasattr( obj, 'remote_service'): if obj.remote_service: formatted_obj['online'] = ( obj.remote_service.probe == 200) else: formatted_obj['online'] = False formatted_obj['gtype'] = self.dehydrate_gtype(bundle) # replace thumbnail_url with curated_thumbs if hasattr(obj, 'curatedthumbnail'): try: if hasattr(obj.curatedthumbnail.img_thumbnail, 'url'): formatted_obj[ 'thumbnail_url'] = obj.curatedthumbnail.thumbnail_url except Exception as e: logger.exception(e) formatted_obj['processed'] = obj.instance_is_processed # put the object on the response stack formatted_objects.append(formatted_obj) return formatted_objects def _dehydrate_links(self, bundle, link_types=None): """Dehydrate links field.""" dehydrated = [] obj = bundle.obj link_fields = ['extension', 'link_type', 'name', 'mime', 'url'] links = obj.link_set.all() if link_types: links = links.filter(link_type__in=link_types) for lnk in links: formatted_link = model_to_dict(lnk, fields=link_fields) dehydrated.append(formatted_link) return dehydrated def dehydrate_links(self, bundle): return self._dehydrate_links(bundle) def dehydrate_ogc_links(self, bundle): return self._dehydrate_links(bundle, ['OGC:WMS', 'OGC:WFS', 'OGC:WCS']) def dehydrate_gtype(self, bundle): return bundle.obj.gtype def build_bundle(self, obj=None, data=None, request=None, **kwargs): """Override build_bundle method to add additional info.""" if obj is None and self._meta.object_class: obj = self._meta.object_class() elif obj: obj = self.populate_object(obj) return Bundle(obj=obj, data=data, request=request, **kwargs) def populate_object(self, obj): """Populate results with necessary fields :param obj: Dataset obj :type obj: Dataset :return: """ return obj # copy parent attribute before modifying VALUES = CommonModelApi.VALUES[:] VALUES.append('typename') class Meta(CommonMetaApi): paginator_class = CrossSiteXHRPaginator queryset = Dataset.objects.distinct().order_by('-date') resource_name = 'datasets' detail_uri_name = 'id' include_resource_uri = True allowed_methods = ['get', 'patch'] excludes = ['csw_anytext', 'metadata_xml'] authentication = MultiAuthentication(SessionAuthentication(), OAuthAuthentication(), GeonodeApiKeyAuthentication()) filtering = CommonMetaApi.filtering # Allow filtering using ID filtering.update({ 'id': ALL, 'name': ALL, 'alternate': ALL, 'metadata_only': ALL })
class PackageSourceResource(Resource): id = fields.IntegerField(attribute='id', readonly=True) name = fields.CharField(attribute='name') desc = fields.CharField(attribute='desc') category = fields.CharField(attribute='category') type = fields.CharField(attribute='type') base_source_id = fields.IntegerField(attribute='base_source_id', null=True) details = fields.DictField(attribute='details', readonly=True) imported_plugins = fields.ListField(attribute='imported_plugins', readonly=True, null=True) packages = fields.DictField(attribute='packages') class Meta: resource_name = 'package_source' authorization = Authorization() limit = 0 @staticmethod def get_source_models(): origin_models = source_cls_factory.values() source_models = origin_models + [CachePackageSource] return source_models @staticmethod def get_all_source_objects(): return list( chain(*[ source.objects.all() for source in PackageSourceResource.get_source_models() ])) def get_object_list(self, request): return self.get_all_source_objects() def apply_filters(self, request, applicable_filters): source_models = self.get_source_models() return list( chain(*[ source.objects.filter(**applicable_filters) for source in source_models ])) def build_filters(self, filters=None, ignore_bad_filters=False): if 'types' in filters: filters['types'] = json.loads(filters['types']) elif 'type' in filters: filters['types'] = [filters.pop('type')] return filters def obj_get_list(self, bundle, **kwargs): filters = {} if hasattr(bundle.request, 'GET'): # Grab a mutable copy. filters = bundle.request.GET.copy() # Update with the provided kwargs. filters.update(kwargs) applicable_filters = self.build_filters(filters=filters) try: objects = self.apply_filters(bundle.request, applicable_filters) return self.authorized_read_list(objects, bundle) except ValueError: raise BadRequest('Invalid resource lookup params provided') def obj_create(self, bundle, **kwargs): try: origins = bundle.data.pop('origins') caches = bundle.data.pop('caches') except KeyError: raise BadRequest('Invalid params, please check origins and caches') with transaction.atomic(): # collect packages of all origin to cache cache_packages = {} for origin in origins: try: jsonschema.validate(origin, ADD_SOURCE_SCHEMA) except jsonschema.ValidationError as e: message = 'Invalid origin source params: %s' % e logger.error(message) raise BadRequest(message) cache_packages.update(origin['packages']) # create cache first if caches exist for cache in caches: try: jsonschema.validate(cache, ADD_SOURCE_SCHEMA) except jsonschema.ValidationError as e: message = 'Invalid cache source params: %s' % e logger.error(message) raise BadRequest(message) try: CachePackageSource.objects.add_cache_source( cache['name'], cache['type'], cache_packages, cache.get('desc', ''), **cache['details']) except exceptions.GcloudExternalPluginsError as e: message = 'Create cache source raise error: %s' % e logger.error(message) raise BadRequest(message) # create origins after for origin in origins: source_type = origin['type'] details = origin['details'] # divide details into two parts,base_kwargs mains fields in base model(e.g. fields of # pipeline.contrib.external_plugins.models.GitRepoSource) # original_kwargs mains field in origin model but not in base model(e.g. repo_address、desc) source_model = source_cls_factory[source_type] original_kwargs, base_kwargs = source_model.objects.divide_details_parts( source_type, details) original_kwargs['desc'] = origin.get('desc', '') source_model.objects.add_original_source( origin['name'], source_type, origin['packages'], original_kwargs, **base_kwargs) def patch_list(self, request, **kwargs): request = convert_post_to_patch(request) deserialized = self.deserialize(request, request.body, format=request.META.get( 'CONTENT_TYPE', 'application/json')) bundle = self.build_bundle(data=deserialized, request=request) return self.obj_update(bundle) def obj_update(self, bundle, skip_errors=False, **kwargs): try: origins = bundle.data.pop('origins') caches = bundle.data.pop('caches') except KeyError: raise BadRequest('Invalid params, please check origins and caches') with transaction.atomic(): # collect packages of all origin to cache if caches: cache_packages = {} for origin_type, origin_model in source_cls_factory.items(): origins_from_db = origin_model.objects.all().values( 'packages') for origin in origins_from_db: cache_packages.update(origin['packages']) for origin in origins: try: jsonschema.validate(origin, UPDATE_SOURCE_SCHEMA) except jsonschema.ValidationError as e: message = 'Invalid origin source params: %s' % e logger.error(message) raise BadRequest(message) cache_packages.update(origin['packages']) # create or update cache first caches_to_update = [ cache['id'] for cache in caches if 'id' in cache ] # delete caches whom id not in param caches CachePackageSource.objects.exclude( id__in=caches_to_update).delete() for cache in caches: try: jsonschema.validate(cache, UPDATE_SOURCE_SCHEMA) except jsonschema.ValidationError as e: message = 'Invalid cache source params: %s' % e logger.error(message) raise BadRequest(message) if 'id' in cache: try: CachePackageSource.objects.update_base_source( cache['id'], cache['type'], cache_packages, **cache['details']) except CachePackageSource.DoesNotExist: message = 'Invalid cache source id: %s, which cannot be found' % cache[ 'id'] logger.error(message) raise BadRequest(message) if cache.get('desc', ''): CachePackageSource.objects.filter( id=cache['id']).update(desc=cache['desc']) else: try: CachePackageSource.objects.add_cache_source( cache['name'], cache['type'], cache_packages, cache.get('desc', ''), **cache['details']) except exceptions.GcloudExternalPluginsError as e: message = 'Create cache source raise error: %s' % e.message logger.error(message) raise BadRequest(message) else: CachePackageSource.objects.all().delete() # delete origins whom id not in param origins for origin_type, origin_model in source_cls_factory.items(): origins_to_update = [ origin['id'] for origin in origins if 'id' in origin and origin['type'] == origin_type ] origin_model.objects.exclude(id__in=origins_to_update).delete() # create origins after for origin in origins: source_type = origin['type'] details = origin['details'] # divide details into two parts,base_kwargs mains fields in base model(e.g. fields of # pipeline.contrib.external_plugins.models.GitRepoSource) # original_kwargs mains field in origin model but not in base model(e.g. repo_address、desc) source_model = source_cls_factory[source_type] original_kwargs, base_kwargs = source_model.objects.divide_details_parts( source_type, details) if origin.get('desc', ''): original_kwargs['desc'] = origin['desc'] if 'id' in origin: source_model.objects.update_original_source( origin['id'], origin['packages'], original_kwargs, **base_kwargs) else: source_model.objects.add_original_source( origin['name'], source_type, origin['packages'], original_kwargs, **base_kwargs) def obj_get(self, bundle, **kwargs): raise NotFound("Invalid resource uri, please use obj_get_list") def obj_delete_list(self, bundle, **kwargs): with transaction.atomic(): caches = CachePackageSource.objects.all() # 需要单独调用自定义 delete 方法 for cache in caches: cache.delete() for origin_type, origin_model in source_cls_factory.items(): origins = origin_model.objects.all() # 需要单独调用自定义 delete 方法 for origin in origins: origin.delete() def obj_delete_list_for_update(self, bundle, **kwargs): pass def obj_delete(self, bundle, **kwargs): raise NotFound("Invalid resource uri, please use obj_delete_list") def rollback(self, bundles): pass
class AreaResource(ModelResource): parent = fields.ForeignKey(EnvironmentResource, 'environment') features = fields.ListField() owner = fields.DictField() admin = fields.ForeignKey(UserResource, 'admin', null = True, full = True) class Meta: queryset = Area.objects.all() resource_name = 'area' allowed_methods = ['get'] excludes = ['shape', 'layout'] filtering = { 'parent': ['exact'], } authentication = Authentication() def get_list(self, request, **kwargs): ## override the list retrieval part to verify additionally that an ``environment`` filter exists ## otherwise reject the call with a HttpMethodNotAllowed if 'parent' in request.GET or 'q' in request.GET: return super(AreaResource, self).get_list(request, **kwargs) else: raise ImmediateHttpResponse(response=http.HttpMethodNotAllowed()) def build_filters(self, filters = None): """ enable filtering by level (which does not have its own field) """ if filters is None: filters = {} orm_filters = super(AreaResource, self).build_filters(filters) if "level" in filters: orm_filters["layout__level"] = int(filters["level"]) return orm_filters def dehydrate_tags(self, bundle): return bundle.obj.tags.to_serializable() def dehydrate_parent(self, bundle): parent_data = bundle.data['parent'] parent_name = bundle.obj.environment.name return {'uri' : parent_data, 'name': parent_name} def dehydrate_owner(self, bundle): user_res = UserResource() user_bundle = user_res.build_bundle(bundle.obj.environment.owner, request=bundle.request) user_bundle = user_res.full_dehydrate(user_bundle) return user_bundle.data def dehydrate_features(self, bundle): ## retrieve the value of the virtual flag virtual = get_virtual_flag_from_url(bundle.request) ## return a list of dictionary values from the features of this area feature_list = [] for feature in bundle.obj.features.all().select_subclasses(): feat_dict = feature.to_serializable(virtual = virtual) if feat_dict: ## attach resource_uri and area_uri feat_dict['resource_uri'] = FeatureResource().get_resource_uri(feature) feat_dict['area'] = self.get_resource_uri(bundle) feature_list.append(feat_dict) ## then see if environment features which also apply to the area are available - e.g. program, order environment = bundle.obj.environment environment_features = environment.features.select_subclasses().filter(is_general = True) for env_feat in environment_features: feat_dict = env_feat.to_serializable(virtual = virtual) if feat_dict: ## attach resource_uri and area_uri feat_dict['resource_uri'] = FeatureResource().get_resource_uri(env_feat) feat_dict['environment'] = EnvironmentResource().get_resource_uri(environment) feature_list.append(feat_dict) return feature_list def dehydrate(self, bundle): """ delete admin field from bundle.data if the model field is null """ if bundle.obj.admin is None: del bundle.data['admin'] """ Delete the img_thumbnail_url if it is null """ if bundle.obj.img_thumbnail_url is None: del bundle.data['img_thumbnail_url'] """ append level data from the layout reference of the Area obj """ bundle.data['level'] = bundle.obj.layout.level """ make bundle consistent for location parsing on mobile client: add a location_type entry in the bundle.data put all the rest of the data under location_data """ location_data = bundle.data.copy() bundle.data.clear() bundle.data['location_type'] = self._meta.resource_name bundle.data['location_data'] = location_data return bundle
class CableResource(NodeHandleResource): def __init__(self, *args, **kwargs): super(CableResource, self).__init__(*args, **kwargs) try: self.fields['cable_type'].help_text = u'Choices {}'.format( Dropdown.get('cable_types').as_values()) except: # Fails during creatin also will not update when cabletypes are added. pass node_name = fields.CharField(attribute='node_name') cable_type = fields.CharField(attribute='cable_type', blank=True, null=True) end_points = fields.ListField( help_text='[{"device": "", "device_type": "", "port": ""},]', blank=True, null=True) class Meta: queryset = NodeHandle.objects.filter(node_type__slug__exact='cable') resource_name = 'cable' pk_field = 'node_name' pk_field_regex = r'[-\w]+' authentication = ApiKeyAuthentication() authorization = Authorization() include_absolute_url = True always_return_data = True allowed_methods = ['get', 'put', 'post', 'patch'] filtering = { "node_name": ALL, } def _initial_form_data(self, bundle): initial_data = { 'node_type': '/api/v1/node_type/cable/', 'node_meta_type': 'Physical', } return initial_data def obj_create(self, bundle, **kwargs): try: node_type = helpers.slug_to_node_type(self.Meta.resource_name, create=True) NodeHandle.objects.get(node_name=bundle.data['node_name'], node_type=node_type) raise_conflict_error('Cable ID (%s) is already in use.' % bundle.data['node_name']) except NodeHandle.DoesNotExist: bundle.data.update(self._initial_form_data(bundle)) bundle.data['name'] = bundle.data['node_name'] form = common_forms.NewCableForm(bundle.data) if form.is_valid(): bundle.data.update({ 'node_name': form.cleaned_data['name'], 'creator': '/api/%s/user/%d/' % (self._meta.api_name, bundle.request.user.pk), 'modifier': '/api/%s/user/%d/' % (self._meta.api_name, bundle.request.user.pk), }) node_data = bundle.data.get('node', {}) node_data.update( {'cable_type': form.cleaned_data['cable_type']}) bundle.data['node'] = node_data del bundle.data['name'] # Create the new cable bundle = super(NodeHandleResource, self).obj_create(bundle, **kwargs) # Depend the created service on provided end points end_point_nodes = self.get_end_point_nodes(bundle) node = bundle.obj.get_node() for end_point in end_point_nodes: helpers.set_connected_to(bundle.request.user, node, end_point.handle_id) return self.hydrate_node(bundle) else: raise_not_acceptable_error([ "%s is missing or incorrect." % key for key in form.errors.keys() ]) def obj_update(self, bundle, **kwargs): bundle = super(CableResource, self).obj_update(bundle, **kwargs) end_point_nodes = self.get_end_point_nodes(bundle) node = bundle.obj.get_node() if end_point_nodes: for result in node.relationships.get('Connected_to', []): helpers.delete_relationship(bundle.request.user, result['relationship_id']) for end_point in end_point_nodes: helpers.set_connected_to(bundle.request.user, node, end_point.handle_id) return bundle def dehydrate(self, bundle): bundle = super(CableResource, self).dehydrate(bundle) bundle.data['cable_type'] = bundle.data['node'].get('cable_type', None) bundle.data['object_path'] = bundle.data['absolute_url'] del bundle.data['absolute_url'] return bundle def get_end_point_nodes(self, bundle): end_point_nodes = [] for end_point in (bundle.data.get('end_points') or []): try: port_node = self.get_port(bundle, end_point['device'], end_point['device_type'], end_point['port']) end_point_nodes.append(port_node) except ObjectDoesNotExist: raise_not_acceptable_error('End point %s not found.' % end_point) return end_point_nodes def get_port(self, bundle, device_name, device_type, port_name): node_type = helpers.slug_to_node_type(slugify(device_type), create=True) parent_node = nc.get_unique_node_by_name(nc.graphdb.manager, device_name, node_type.get_label()) if not parent_node: raise_not_acceptable_error("End point {0} {1} not found.".format( device_type, device_name)) result = parent_node.get_port(port_name).get('Has', []) if len(result) > 1: raise_not_acceptable_error( 'Multiple port objects returned for a unique port name.') if result: port_node = result[0]['node'] else: port_node = helpers.create_port(parent_node, port_name, bundle.request.user) return port_node
class ServiceL2VPNResource(ServiceResource): node_name = fields.CharField(attribute='node_name') operational_state = fields.CharField( help_text='Choices: In service, Reserved, Decommissioned, Testing') vrf_target = fields.CharField() route_distinguisher = fields.CharField() vpn_type = fields.CharField(help_text='Choices: l2vpn, interface-switch') end_points = fields.ListField(help_text='[{"device": "", "port": ""},]') class Meta(ServiceResource.Meta): resource_name = 'l2vpn' def _initial_form_data(self, bundle): initial_data = { 'node_type': '/api/v1/node_type/service/', 'node_meta_type': 'Logical', } try: vpn_type = bundle.data['vpn_type'].lower() if vpn_type == 'l2vpn': initial_data['service_type'] = 'L2VPN' elif vpn_type == 'interface-switch': initial_data['service_type'] = 'Interface Switch' else: raise_not_acceptable_error( 'KeyError: vpn_type %s not recognized.' % vpn_type) except KeyError as e: raise_not_acceptable_error('%s is missing or incorrect.' % e) return initial_data def obj_create(self, bundle, **kwargs): bundle.data.update(self._initial_form_data(bundle)) try: if unique_ids.is_free_unique_id(NordunetUniqueId, bundle.data['node_name']): bundle.data['name'] = bundle.data['node_name'] else: raise_conflict_error('Service ID (%s) is already in use.' % bundle.data['node_name']) except KeyError as e: raise_not_acceptable_error('%s is missing.' % e) form = forms.NewL2vpnServiceForm(bundle.data) if form.is_valid(): bundle.data.update({ 'node_name': form.cleaned_data['name'], 'creator': '/api/%s/user/%d/' % (self._meta.api_name, bundle.request.user.pk), 'modifier': '/api/%s/user/%d/' % (self._meta.api_name, bundle.request.user.pk) }) node_data = bundle.data.get('node', {}) node_data.update({ 'service_type': form.cleaned_data['service_type'], 'service_class': form.cleaned_data['service_class'], 'ncs_service_name': form.cleaned_data['ncs_service_name'], 'vpn_type': form.cleaned_data['vpn_type'], 'vlan': form.cleaned_data['vlan'], 'vrf_target': form.cleaned_data['vrf_target'], 'route_distinguisher': form.cleaned_data['route_distinguisher'], 'operational_state': form.cleaned_data['operational_state'], 'description': form.cleaned_data['description'], }) bundle.data['node'] = node_data del bundle.data['name'] # Ensure that we have all the data needed to create the L2VPN service end_point_nodes = self.get_end_point_nodes(bundle) # Create the new service bundle = super(ServiceL2VPNResource, self).obj_create(bundle, **kwargs) unique_ids.register_unique_id(NordunetUniqueId, bundle.data['node_name']) # Depend the created service on provided end points node = bundle.obj.get_node() for end_point in end_point_nodes: helpers.set_depends_on(bundle.request.user, node, end_point.handle_id) return self.hydrate_node(bundle) else: raise_not_acceptable_error([ "%s is missing or incorrect." % key for key in form.errors.keys() ]) def obj_update(self, bundle, **kwargs): bundle = super(ServiceL2VPNResource, self).obj_update(bundle, **kwargs) end_point_nodes = self.get_end_point_nodes(bundle) node = bundle.obj.get_node() if end_point_nodes: for item in node.get_dependencies().get('Depends_on', []): helpers.delete_relationship(bundle.request.user, item['relationship_id']) for end_point in end_point_nodes: helpers.set_depends_on(bundle.request.user, node, end_point.handle_id) return bundle def dehydrate(self, bundle): bundle = super(ServiceL2VPNResource, self).dehydrate(bundle) bundle.data['vrf_target'] = bundle.data['node'].get('vrf_target', '') bundle.data['route_distinguisher'] = bundle.data['node'].get( 'route_distinguisher', '') bundle.data['vpn_type'] = bundle.data['node'].get('vpn_type', '') del bundle.data['end_points'] return bundle def get_object_list(self, request, **kwargs): q = """ MATCH (node:Service) WHERE node.service_type = "L2VPN" OR node.service_type = "Interface Switch" RETURN collect(node.handle_id) as handle_ids """ hits = nc.query_to_dict(nc.graphdb.manager, q) return NodeHandle.objects.filter(pk__in=hits['handle_ids']) def obj_get_list(self, request=None, **kwargs): return self.get_object_list(request, **kwargs) def get_port(self, bundle, device_name, device_type, port_name): node_type = helpers.slug_to_node_type(slugify(device_type), create=True) parent_node = nc.get_unique_node_by_name(nc.graphdb.manager, device_name, node_type.get_label()) if not parent_node: raise_not_acceptable_error("End point {0} {1} not found.".format( device_type, device_name)) result = parent_node.get_port(port_name).get('Has', []) if len(result) > 1: raise_not_acceptable_error( 'Multiple port objects returned for a unique port name.') if result: port_node = result[0]['node'] else: port_node = helpers.create_port(parent_node, port_name, bundle.request.user) return port_node def get_unit(self, bundle, port_node, unit_name): result = port_node.get_unit(unit_name).get('Part_of', []) if len(result) > 1: raise_not_acceptable_error( 'Multiple unit objects returned for a unique unit name.') if result: unit_node = result[0]['node'] else: unit_node = helpers.create_unit(port_node, unit_name, bundle.request.user) return unit_node def get_vlan(self, bundle): vlan = bundle.data.get('vlan', None) if vlan: if '<->' in str( vlan ): # VLAN rewrite, VLAN needs to be specified on each end point. return None vlan = str(bundle.data.get('vlan')).split('-')[ 0] # Use lowest vlan if a range, "5-10" -> "5" return vlan def get_end_point_nodes(self, bundle): end_point_nodes = [] for end_point in bundle.data.get('end_points', []): try: port_node = self.get_port(bundle, end_point['device'], 'Router', end_point['port']) if end_point.get('unit', None): unit_node = self.get_unit(bundle, port_node, end_point.get('unit')) elif end_point.get('vlan', None) or self.get_vlan(bundle): vlan = end_point.get('vlan', None) if not vlan: vlan = self.get_vlan(bundle) unit_node = self.get_unit(bundle, port_node, vlan) unit_properties = {'vlan': vlan} helpers.dict_update_node(bundle.request.user, unit_node.handle_id, unit_properties, unit_properties.keys()) else: # Use Unit 0 if nothing else is specified unit_node = self.get_unit(bundle, port_node, '0') end_point_nodes.append(unit_node) except ObjectDoesNotExist: raise_not_acceptable_error('End point %s not found.' % end_point) return end_point_nodes
class FaceResource(PieforkModelResource): tags = fields.ToManyField( 'viewer.api.v3.TagResource', 'tags', full=True, blank=True, null=True, help_text="List of tags, input separated by comma", default='') comments = fields.ListField(attribute='comments', null=True, readonly=True, help_text="List of comments") artist = fields.CharField(attribute='artist', null=True, readonly=True, help_text="Name of artist of image if known") title = fields.CharField(attribute='title', null=True, readonly=True, help_text="Generated title for this face.") description = fields.CharField( attribute='description', null=True, readonly=True, help_text="Generated description for this image.") thumbnails = fields.DictField( attribute="thumbnails", readonly=True, null=True, help_text="List of thumbnails related to this face") resizes = fields.DictField(attribute="resizes", readonly=True, null=True, help_text="Resized versions of this face") class Meta: queryset = models.Face.objects.filter(removed=False) max_limit = 1000 list_allowed_methods = ['get', 'post'] detail_allowed_methods = ['get', 'put', 'delete'] always_return_data = True filtering = { "id": ["gt", "gte", "lt", "lte"], "accepted": ["exact"], "views": ["gt", "gte", "lt", "lte"], "hotness": ["gt", "gte", "lt", "lte"], "tags": ["all", "any"] } ordering = ["id", "random", "views", "hotness"] excludes = [ "gif", "png", "jpg", "webp", "small", "medium", "large", "huge", "removed" ] readonlys = [ "views", "md5", "accepted", "comment", "added", "height", "width", "hotness", "processed" ] authorization = auths.AnonMethodAllowed().set_allowed( ["GET", "POST", "PUT", "PATCH"]) validation = FaceValidation() description = """Resource that contains all the reaction images in \ the service. Allows uploading base64 formatted images and modification of \ old ones. \n\ Tags should be separated by comma eg, 'yes, rainbow dash' """ # def get_list(self, request, **kwargs): # trixie = request.GET.copy() # trixie["tags__all"] = trixie.get("tags__all", "") + ",trixie," # request.GET = trixie # return super(FaceResource, self).get_list(request, **kwargs) def build_filters(self, filters=None): #TODO Can these be made into real filters? for filter in ("tags__all", "tags__any"): if filter in filters: filters.pop(filter) return super(FaceResource, self).build_filters(filters) def get_object_list(self, request): if request.GET.get("tags__all"): tagsstring = re.sub("( ?, ?)+", ",", request.GET.get("tags__all")) tags = tagsstring.strip(", ").split(",") objects = models.Face.tagged.with_all(tags) elif request.GET.get("tags__any"): tagsstring = re.sub("( ?, ?)+", ",", request.GET.get("tags__any")) tags = tagsstring.strip(", ").split(",") objects = models.Face.tagged.with_any(tags) else: objects = super(FaceResource, self).get_object_list(request) return objects 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 build_bundle(self, obj=None, data=None, request=None): bundle = super(FaceResource, self).build_bundle(obj, data, request) if request and bundle.data.get("tags"): tags = re.sub("( ?, ?)+", ", ", bundle.data.get("tags", "") + ", ") bundle.data["tags"] = tags.strip(", ") return bundle def obj_update(self, bundle, request=None, skip_errors=False, **kwargs): lookup_kwargs = self.lookup_kwargs_with_identifiers(bundle, kwargs) bundle.obj = self.obj_get(bundle, **lookup_kwargs) self.is_valid(bundle) if bundle.errors and not skip_errors: self.error_response(bundle.errors, request) bundle.obj.public_update(bundle.data) # if bundle.data["source"]: # bundle.obj.source = bundle.data["source"] # if bundle.data["tags"]: # bundle.obj.tags = bundle.data["tags"] # bundle.obj.save() return bundle def obj_create(self, bundle, request=None, **kwargs): # behavour change from 0.9 to 0.11, this is the haxfix bundle.data["image"] = json.dumps(bundle.data["image"]) self.is_valid(bundle) if bundle.errors: self.error_response(request, bundle.errors) raise Exception() bundle.obj = models.Face.submit(**bundle.data) return bundle
class HostScanResource(Resource): handle_id = fields.IntegerField(attribute='handle_id', readonly=True, unique=True) ip_addresses = fields.ListField(attribute='ip_addresses') tcp_ports = fields.ListField(attribute='tcp_ports') udp_ports = fields.ListField(attribute='udp_ports') class Meta: resource_name = 'host-scan' authorization = Authorization() authentication = ApiKeyAuthentication() def detail_uri_kwargs(self, bundle_or_obj): kwargs = {} if isinstance(bundle_or_obj, Bundle): kwargs['pk'] = bundle_or_obj.obj.handle_id else: kwargs['pk'] = bundle_or_obj.handle_id return kwargs def last_seen(self, days=7): return (datetime.now() - timedelta(days)).isoformat() def get_object_list(self, request): q = """ MATCH (h:Host)<-[r:Depends_on]-(s:Host_Service) WHERE h.operational_state <> 'Decommissioned' AND r.state CONTAINS 'open' AND r.noclook_last_seen > {last_seen} RETURN h.handle_id as handle_id, h.ip_addresses as ip_addresses, collect(distinct r.protocol + r.port) as ports """ host_list = nc.query_to_list(nc.graphdb.manager, q, last_seen=self.last_seen()) return [HostScan(h) for h in host_list] def obj_get_list(self, bundle, **kwargs): return self.get_object_list(bundle.request) def obj_get(self, bundle, **kwargs): handle_id = int(kwargs.get('pk')) q = """ MATCH (h:Host {handle_id: {handle_id}})<-[r:Depends_on]-(s:Host_Service) WHERE h.operational_state <> 'Decommissioned' AND r.state CONTAINS 'open' AND r.noclook_last_seen > {last_seen} RETURN h.handle_id as handle_id, h.ip_addresses as ip_addresses, collect(distinct r.protocol + r.port) as ports """ host_list = nc.query_to_list(nc.graphdb.manager, q, handle_id=handle_id, last_seen=self.last_seen()) if len(host_list) == 0: raise NotFound( 'HostScan object not found with handle_id: {}'.format( handle_id)) if len(host_list) > 1: raise HttpMultipleChoices( 'Found {} HostScan objects with handle_id: {}'.format( len(host_list), handle_id)) return HostScan(host_list[0])
class BulkUserResource(HqBaseResource, DomainSpecificResourceMixin): """ A read-only user data resource based on elasticsearch. Supported Params: limit offset q fields """ type = "bulk-user" id = fields.CharField(attribute='id', readonly=True, unique=True) email = fields.CharField(attribute='email') username = fields.CharField(attribute='username', unique=True) first_name = fields.CharField(attribute='first_name', null=True) last_name = fields.CharField(attribute='last_name', null=True) phone_numbers = fields.ListField(attribute='phone_numbers', null=True) @staticmethod def to_obj(user): ''' Takes a flat dict and returns an object ''' if '_id' in user: user['id'] = user.pop('_id') return namedtuple('user', user.keys())(**user) class Meta(CustomResourceMeta): authentication = RequirePermissionAuthentication(Permissions.edit_commcare_users) list_allowed_methods = ['get'] detail_allowed_methods = ['get'] object_class = object resource_name = 'bulk-user' def dehydrate(self, bundle): fields = bundle.request.GET.getlist('fields') data = {} if not fields: return bundle for field in fields: data[field] = bundle.data[field] bundle.data = data return bundle def obj_get_list(self, bundle, **kwargs): request_fields = bundle.request.GET.getlist('fields') for field in request_fields: if field not in self.fields: raise BadRequest('{0} is not a valid field'.format(field)) params = bundle.request.GET param = lambda p: params.get(p, None) fields = self.fields.keys() fields.remove('id') fields.append('_id') fn = MOCK_BULK_USER_ES or user_es_call users = fn( domain=kwargs['domain'], q=param('q'), fields=fields, size=param('limit'), start_at=param('offset'), ) return map(self.to_obj, users) def detail_uri_kwargs(self, bundle_or_obj): return { 'pk': get_obj(bundle_or_obj).id }
class ConfigurableReportDataResource(HqBaseResource, DomainSpecificResourceMixin): """ A resource that replicates the behavior of the ajax part of the ConfigurableReport view. """ data = fields.ListField(attribute="data", readonly=True) columns = fields.ListField(attribute="columns", readonly=True) total_records = fields.IntegerField(attribute="total_records", readonly=True) next_page = fields.CharField(attribute="next_page", readonly=True) LIMIT_DEFAULT = 50 LIMIT_MAX = 50 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 _get_limit_param(self, bundle): try: limit = int(bundle.request.GET.get('limit', self.LIMIT_DEFAULT)) if limit < 0: raise ValueError except (ValueError, TypeError): raise BadRequest("limit must be a positive integer.") if limit > self.LIMIT_MAX: raise BadRequest("Limit may not exceed {}.".format(self.LIMIT_MAX)) return limit def _get_next_page(self, domain, id_, start, limit, total_records, get_query_dict): if total_records > start + limit: start += limit new_get_params = get_query_dict.copy() new_get_params["offset"] = start # limit has not changed, but it may not have been present in get params before. new_get_params["limit"] = limit return reverse('api_dispatch_detail', kwargs=dict( api_name=self._meta.api_name, resource_name=self._meta.resource_name, domain=domain, pk=id_, )) + "?" + new_get_params.urlencode() else: return "" def _get_report_data(self, report_config, domain, start, limit, get_params): report = ReportFactory.from_spec(report_config) filter_values = get_filter_values( report_config.ui_filters, query_dict_to_dict(get_params, domain) ) report.set_filter_values(filter_values) page = list(report.get_data(start=start, limit=limit)) columns = [] for column in report.columns: simple_column = { "header": column.header, "slug": column.slug, } if isinstance(column, UCRExpandDatabaseSubcolumn): simple_column['expand_column_value'] = column.expand_value columns.append(simple_column) total_records = report.get_total_records() return page, columns, total_records def obj_get(self, bundle, **kwargs): domain = kwargs['domain'] pk = kwargs['pk'] start = self._get_start_param(bundle) limit = self._get_limit_param(bundle) report_config = self._get_report_configuration(pk, domain) page, columns, total_records = self._get_report_data( report_config, domain, start, limit, bundle.request.GET) return ConfigurableReportData( data=page, columns=columns, total_records=total_records, id=report_config._id, domain=domain, get_params=bundle.request.GET, next_page=self._get_next_page( domain, report_config._id, start, limit, total_records, bundle.request.GET, ) ) def _get_report_configuration(self, id_, domain): """ Fetch the required ReportConfiguration object :param id_: The id of the ReportConfiguration :param domain: The domain of the ReportConfiguration :return: A ReportConfiguration """ if report_config_id_is_static(id_): report_config = StaticReportConfiguration.by_id(id_) if report_config.domain != domain: raise NotFound else: try: report_config = get_document_or_not_found(ReportConfiguration, domain, id_) except DocumentNotFound: raise NotFound return report_config def detail_uri_kwargs(self, bundle_or_obj): return { 'domain': get_obj(bundle_or_obj).domain, 'pk': get_obj(bundle_or_obj).id, } def get_resource_uri(self, bundle_or_obj=None, url_name='api_dispatch_list'): uri = super(ConfigurableReportDataResource, self).get_resource_uri(bundle_or_obj, url_name) if bundle_or_obj is not None and uri: get_params = get_obj(bundle_or_obj).get_params.copy() if "offset" not in get_params: get_params["offset"] = 0 if "limit" not in get_params: get_params["limit"] = self.LIMIT_DEFAULT uri += "?{}".format(get_params.urlencode()) return uri class Meta(CustomResourceMeta): list_allowed_methods = [] detail_allowed_methods = ["get"]
class JournalResource(ModelResource): missions = fields.CharField(readonly=True) other_titles = fields.CharField(readonly=True) abstract_keyword_languages = fields.CharField(readonly=True) languages = fields.CharField(readonly=True) pub_status_history = fields.ListField(readonly=True) contact = fields.DictField(readonly=True) study_areas = fields.ListField(readonly=True) pub_status = fields.CharField(readonly=True) pub_status_reason = fields.CharField(readonly=True) national_code = fields.CharField(attribute='ccn_code', readonly=True) # Relation fields creator = fields.ForeignKey(UserResource, 'creator') use_license = fields.ForeignKey(UseLicenseResource, 'use_license', full=True) sponsors = fields.ManyToManyField(SponsorResource, 'sponsor') collections = fields.ManyToManyField(CollectionResource, 'collections') issues = fields.OneToManyField(IssueResource, 'issue_set') sections = fields.OneToManyField(SectionResource, 'section_set') subject_categories = fields.ManyToManyField(SubjectCategoryResource, 'subject_categories', readonly=True) # Recursive field previous_title = fields.ForeignKey('self', 'previous_title', null=True) succeeding_title = fields.ForeignKey('self', 'succeeding_title', null=True) class Meta(ApiKeyAuthMeta): queryset = models.Journal.objects.all() resource_name = 'journals' allowed_methods = [ 'get', ] filtering = { 'is_trashed': ('exact', ), 'eletronic_issn': ('exact', ), 'print_issn': ('exact', ), } def build_filters(self, filters=None): """ Custom filter that retrieves data filter by collection and pubstatus. """ if filters is None: filters = {} query_filters = {} orm_filters = super(JournalResource, self).build_filters(filters) if 'collection' in filters: query_filters['collections__name_slug'] = filters['collection'] if 'pubstatus' in filters: query_filters['membership__status__in'] = filters.getlist( 'pubstatus') journals = models.Journal.objects.filter(**query_filters) orm_filters['pk__in'] = journals return orm_filters def dehydrate_missions(self, bundle): return { mission.language.iso_code: mission.description for mission in bundle.obj.missions.all() } def dehydrate_other_titles(self, bundle): return { title.category: title.title for title in bundle.obj.other_titles.all() } def dehydrate_languages(self, bundle): return [language.iso_code for language in bundle.obj.languages.all()] def dehydrate_pub_status_history(self, bundle): return [{ 'date': event.since, 'status': event.status } for event in bundle.obj.statuses.order_by('-since').all()] def dehydrate_study_areas(self, bundle): return [area.study_area for area in bundle.obj.study_areas.all()] def dehydrate_pub_status(self, bundle): return { col.name: bundle.obj.membership_info(col, 'status') for col in bundle.obj.collections.all() } def dehydrate_pub_status_reason(self, bundle): return { col.name: bundle.obj.membership_info(col, 'reason') for col in bundle.obj.collections.all() } def dehydrate_collections(self, bundle): return [col.name for col in bundle.obj.collections.all()] def dehydrate_subject_categories(self, bundle): return [ subject_category.term for subject_category in bundle.obj.subject_categories.all() ] def dehydrate(self, bundle): # garantia de compatibilidade bundle.data.pop('ccn_code', False) return bundle
class CorosyncConfigurationResource(StatefulModelResource, BulkResourceOperation): """ LNetConfiguration information. """ host = fields.ToOneField("chroma_api.host.HostResource", "host", full=False) network_interfaces = fields.ListField( null=True, help_text= "Network interfaces the form part of the corosync configuration.") class Meta: queryset = CorosyncConfiguration.objects.all() authorization = PatchedDjangoAuthorization() authentication = AnonymousAuthentication() resource_name = "corosync_configuration" list_allowed_methods = ["get", "put"] detail_allowed_methods = ["get", "put"] filtering = { "host": ALL_WITH_RELATIONS, "id": ["exact"], "host__fqdn": ["exact", "startswith"] } @validate def obj_update(self, bundle, **kwargs): request = bundle.request super(CorosyncConfigurationResource, self).obj_update(bundle, **kwargs) def _update_corosync_configuration(self, corosync_configuration, request, **kwargs): network_interface_ids = [ resolve(interwork_interface)[2]["pk"] for interwork_interface in corosync_configuration["network_interfaces"] ] return self.BulkActionResult( dehydrate_command( JobSchedulerClient.update_corosync_configuration( corosync_configuration_id=corosync_configuration["id"], mcast_port=corosync_configuration["mcast_port"], network_interface_ids=network_interface_ids, )), None, None, ) self._bulk_operation(_update_corosync_configuration, "command", bundle, request, **kwargs) def dehydrate_network_interfaces(self, bundle): from chroma_api.urls import api return [ api.get_resource_uri(network_interface) for network_interface in bundle.obj.network_interfaces ]
class CBHChemicalSearchResource(Resource): """ Provides a REST interface to POST a molfile for use with chemical search """ id = fields.CharField( help_text= "uuid generated on POST of data - comes from the task ID when molecule is searched for" ) query_type = fields.CharField( help_text= "Chemical query type - currently supports 'with_substructure' or 'flexmatch'" ) molfile = fields.CharField( help_text="MDL molfile text for the molecule being searched for") smiles = fields.CharField( help_text="Generated SMILES string for the molecule being searched for" ) pids = fields.ListField( help_text="Project IDs over which this chemical search should be run") filter_is_applied = fields.BooleanField( default=False, help_text="front end helper boolean") inprogress = fields.BooleanField(default=False, help_text="front end helper boolean") class Meta: """ authorization is not used in the standard way as we just need to check the submitted project id list """ resource_name = 'cbh_chemical_search' authorization = ProjectAuthorization() def convert_mol_string(self, strn): """ Take the mdl molfile string and convert it into a SMILES string """ try: mol = Chem.MolFromMolBlock(strn) smiles = Chem.MolToSmiles(mol) except: smiles = "" return smiles def get_detail(self, request, **kwargs): """ Used in the saved search method on the front end to return the molecule that should be structure searched This caching needs an upgrade to use the database instead as saved search could be retrieved in a different session """ bundle = self.build_bundle(request=request) bundle.data = caches[settings.SESSION_CACHE_ALIAS].get( "structure_search__%s" % kwargs.get("pk", None)) bundle = self.alter_detail_data_to_serialize(request, bundle) return self.create_response(request, bundle) def alter_deserialized_detail_data(self, request, deserialized): """ Standard tastypie hook to alter the input data from a post request after deserialization This function adds SMILES patterns and images to the input molfile """ deserialized["smiles"] = self.convert_mol_string( deserialized["molfile"]) if not deserialized["smiles"]: deserialized["error"] = True deserialized["image"] = None else: deserialized["error"] = False deserialized["image"] = _ctab2image(deserialized["molfile"], 50, False, recalc=None) deserialized["inprogress"] = False deserialized["filter_is_applied"] = False return deserialized def post_list(self, request, **kwargs): """ Takes an input molfile from a POST request and processes the structure search then saves it to the session cache """ deserialized = self.deserialize(request, request.body, format=request.META.get( 'CONTENT_TYPE', 'application/json')) deserialized = self.alter_deserialized_detail_data( request, deserialized) bundle = self.build_bundle(data=deserialized, request=request) updated_bundle = self.obj_create( bundle, **self.remove_api_resource_names(kwargs)) updated_bundle = self.alter_detail_data_to_serialize( request, updated_bundle) return self.create_response(request, updated_bundle, response_class=http.HttpCreated, location=None) def obj_create(self, bundle, **kwargs): """ Generate a task id and send the relevant tasks to django q """ pids = bundle.data.get("pids", None) project_ids = [] if pids: project_ids = [int(pid) for pid in pids.split(",")] allowed_pids = set(self._meta.authorization.project_ids( bundle.request)) for requested_pid in project_ids: if requested_pid not in allowed_pids: raise Unauthorized("No permissions for requested project") if len(project_ids) == 0: project_ids = allowed_pids allowed_pids = list(allowed_pids) one_eighth = int(len(allowed_pids) / 1) + 1 #Split the projects into 8 equal parts pid_chunks = list(chunks(allowed_pids, one_eighth)) args = [(pid_list, bundle.data["query_type"], bundle.data["smiles"]) for pid_list in pid_chunks] bundle.data = self.add_task_id(bundle.data, args) return bundle def add_task_id(self, data, args): """ Calls async_iter to generate a django_q task id and set the qcluster process to work processing the structure search. The user will then be able to search for it but this gives an extra second or so while the user considers pressing the apply key""" data["id"] = async_iter( 'cbh_chem_api.tasks.get_structure_search_for_projects', args) caches[settings.SESSION_CACHE_ALIAS].set( "structure_search__%s" % data["id"], data) return data
class StorageResourceClassResource(ChromaModelResource): """ Defines a type of ``storage_resource`` that can be created. Storage resource classes belong to a particular plugin (``plugin_name`` attribute) . The name of the storage resource class (``class_name`` attribute) is unique within the plugin. """ plugin_name = fields.CharField(attribute="storage_plugin__module_name") plugin_internal = fields.BooleanField(attribute="storage_plugin__internal") label = fields.CharField( help_text= "A unique human-readable name for the resource class, including" 'the plugin name. e.g. "TestPlugin-ResourceOne"') columns = fields.ListField( help_text= "List of resource attributes to be used when presenting resource in tabular form" ) fields = fields.DictField( help_text= "List of resource attributes which should be presented in an input form" ) def dehydrate_columns(self, bundle): properties = bundle.obj.get_class().get_all_attribute_properties() return [{ "name": name, "label": props.get_label(name) } for (name, props) in properties if not isinstance(props, attributes.Password)] def dehydrate_fields(self, bundle): resource_klass = bundle.obj.get_class() fields = [] for name, attr in resource_klass.get_all_attribute_properties(): fields.append({ "label": attr.get_label(name), "name": name, "optional": attr.optional, "user_read_only": attr.user_read_only, "class": attr.__class__.__name__, }) return fields def dehydrate_label(self, bundle): return "%s-%s" % (bundle.obj.storage_plugin.module_name, bundle.obj.class_name) class Meta: queryset = StorageResourceClass.objects.filter( id__in=filter_class_ids()) resource_name = "storage_resource_class" filtering = { "plugin_name": ["exact"], "class_name": ["exact"], "user_creatable": ["exact"], "plugin_internal": ["exact"], } authorization = DjangoAuthorization() authentication = AnonymousAuthentication() list_allowed_methods = ["get"] detail_allowed_methods = ["get"] ordering = ["class_name"] def prepend_urls(self): from django.conf.urls import url return [ url( r"^(?P<resource_name>%s)/(?P<storage_plugin__module_name>\w+)/(?P<class_name>\w+)/$" % self._meta.resource_name, self.wrap_view("dispatch_detail"), name="dispatch_detail", ) ]
class HostResource(StatefulModelResource, BulkResourceOperation): """ Represents a Lustre server that is being monitored and managed from the manager server. PUTs to this resource must have the ``state`` attribute set. POSTs to this resource must have the ``address`` attribute set. """ nids = fields.ListField(null=True) root_pw = fields.CharField(help_text="ssh root password to new server.") private_key = fields.CharField(help_text="ssh private key matching a " "public key on the new server.") private_key_passphrase = fields.CharField(help_text="passphrase to " "decrypt private key") server_profile = fields.ToOneField(ServerProfileResource, "server_profile", full=True) lnet_configuration = fields.ToOneField( "chroma_api.lnet_configuration.LNetConfigurationResource", "lnet_configuration", full=False ) corosync_configuration = fields.ToOneField( "chroma_api.corosync.CorosyncConfigurationResource", "corosync_configuration", null=True, full=False ) pacemaker_configuration = fields.ToOneField( "chroma_api.pacemaker.PacemakerConfigurationResource", "pacemaker_configuration", null=True, full=False ) def dehydrate_nids(self, bundle): return [n.nid_string for n in Nid.objects.filter(lnet_configuration=bundle.obj.lnet_configuration)] class Meta: queryset = ManagedHost.objects.select_related("lnet_configuration").prefetch_related( "lnet_configuration__nid_set" ) resource_name = "host" excludes = ["not_deleted"] authentication = AnonymousAuthentication() authorization = PatchedDjangoAuthorization() ordering = ["fqdn"] list_allowed_methods = ["get", "post", "put"] detail_allowed_methods = ["get", "put", "delete"] readonly = [ "nodename", "fqdn", "nids", "needs_update", "boot_time", ] # HYD-2256: remove these fields when other auth schemes work readonly += ["root_pw", "private_key_passphrase", "private_key"] validation = HostValidation() always_return_data = True filtering = {"id": ["exact"], "fqdn": ["exact", "startswith"]} def put_list(self, request, **kwargs): """ based on tastypie/resources.py but modified to do what we actually want! Up a collection of resources with another collection. Calls ``delete_list`` to clear out the collection then ``obj_create`` with the provided the data to create the new collection. Return ``HttpNoContent`` (204 No Content) if ``Meta.always_return_data = False`` (default). Return ``HttpAccepted`` (202 Accepted) if ``Meta.always_return_data = True``. """ deserialized = self.deserialize( request, request.body, format=request.META.get("CONTENT_TYPE", "application/json") ) deserialized = self.alter_deserialized_list_data(request, deserialized) if not "objects" in deserialized: raise http.HttpBadRequest("Invalid data sent.") bundle = self.build_bundle(data=dict_strip_unicode_keys(deserialized), request=request) self.obj_update(bundle, **kwargs) @validate def obj_update(self, bundle, **kwargs): def _update_action(self, data, request, **kwargs): # For simplicity lets fake the kwargs if we can, this is for when we are working from objects if "address" in data: host = ManagedHost.objects.get(address=data["address"]) elif "pk" in kwargs: host = self.cached_obj_get( self.build_bundle(data=data, request=request), **self.remove_api_resource_names(kwargs) ) else: return self.BulkActionResult(None, "Unable to decipher target host", None) # If the host that is being updated is in the undeployed state then this is a special case and the normal # state change doesn't work because we need to provide some parameters to the allow the ssh connection to # bootstrap the agent into existence. if host.state == "undeployed": return self._create_host(host.address, data, request) else: if "pk" in kwargs: try: super(HostResource, self).obj_update(self.build_bundle(data=data, request=request), **kwargs) return self.BulkActionResult(None, "State data not present for host %s" % host, None) except ImmediateHttpResponse as ihr: if int(ihr.response.status_code / 100) == 2: return self.BulkActionResult(json.loads(ihr.response.content), None, None) else: return self.BulkActionResult(None, json.loads(ihr.response.content), None) else: return self.BulkActionResult(None, "Bulk setting of state not yet supported", None) self._bulk_operation(_update_action, "command_and_host", bundle, bundle.request, **kwargs) @validate def obj_create(self, bundle, **kwargs): # FIXME HYD-1657: we get errors back just fine when something goes wrong # during registration, but the UI tries to format backtraces into # a 'validation errors' dialog which is pretty ugly. if bundle.data.get("failed_validations"): log.warning( "Attempting to create host %s after failed validations: %s" % (bundle.data.get("address"), bundle.data.get("failed_validations")) ) def _update_action(self, data, request, **kwargs): return self._create_host(None, data, request) self._bulk_operation(_update_action, "command_and_host", bundle, bundle.request, **kwargs) def _create_host(self, address, data, request): # Resolve a server profile URI to a record profile = ServerProfileResource().get_via_uri(data["server_profile"], request) host, command = JobSchedulerClient.create_host_ssh(server_profile=profile.name, **_host_params(data, address)) # TODO: Could simplify this by adding a 'command' key to the # bundle, then optionally handling dehydrating that # in super.alter_detail_data_to_serialize. That way could # return from this method avoiding all this extra code, and # providing a central handling for all things that migth have # a command argument. NB: not tested, and not part of any ticket object = { "command": dehydrate_command(command), "host": self.alter_detail_data_to_serialize(None, self.full_dehydrate(self.build_bundle(obj=host))).data, } return self.BulkActionResult(object, None, None) def apply_filters(self, request, filters=None): objects = super(HostResource, self).apply_filters(request, filters) # convenience filter for the UI client if request.GET.get("worker", False): objects = objects.filter(server_profile__worker=True) return objects.distinct()
class EnvironmentResource(ModelResource): features = fields.ListField() parent = fields.ForeignKey('self', 'parent', null = True) owner = fields.ForeignKey(UserResource, 'owner', full = True) class Meta: queryset = Environment.objects.all() resource_name = 'environment' #api_name = 'v1/resources' #fields = ['name', 'data', 'tags', 'parentID', 'category', 'latitude', 'longitude', 'timestamp'] excludes = ['width', 'height'] detail_allowed_methods = ['get'] list_allowed_methods = ['get'] authentication = Authentication() default_format = "application/json" def dehydrate_tags(self, bundle): return bundle.obj.tags.to_serializable() def dehydrate_parent(self, bundle): if not bundle.data['parent'] is None: parent_data = bundle.data['parent'] parent_name = bundle.obj.parent.name return {'uri' : parent_data, 'name': parent_name} return None def dehydrate_features(self, bundle): ## retrieve the value of the virtual flag virtual = get_virtual_flag_from_url(bundle.request) ## return a list of dictionary values from the features of this environment feature_list = [] for feature in bundle.obj.features.select_subclasses(): feat_dict = feature.to_serializable(virtual = virtual) if feat_dict: ## attach resource_uri and environment_uri feat_dict['resource_uri'] = FeatureResource().get_resource_uri(feature) feat_dict['environment'] = self.get_resource_uri(bundle) feature_list.append(feat_dict) return feature_list def dehydrate(self, bundle): """ Delete the img_thumbnail_url if it is null """ if bundle.obj.img_thumbnail_url is None: del bundle.data['img_thumbnail_url'] """ append layout url if a level filter exists in the request """ if "level" in bundle.request.GET: level = int(bundle.request.GET["level"]) bundle.data["layout_url"] = bundle.obj.layouts.get(level=level).mapURL """ make bundle consistent for location parsing on mobile client: add a location_type entry in the bundle.data put all the rest of the data under location_data """ location_data = bundle.data.copy() bundle.data.clear() bundle.data['location_type'] = self._meta.resource_name bundle.data['location_data'] = location_data return bundle
class VoteResource(BaseResource): class Meta(BaseResource.Meta): queryset = Vote.objects.all() allowed_methods = ['get'] list_fields = [ 'time', 'title', 'vote_type', 'votes_count', 'for_votes_count', 'against_votes_count', 'meeting_number', 'vote_number', 'importance', 'controversy', 'against_party ', 'against_coalition', 'against_opposition', 'against_own_bill', ] filtering = dict(tag=('exact'), member=ALL, member_for=ALL, member_against=ALL, from_date=ALL, to_date=ALL) votes = fields.ToManyField( VoteActionResource, attribute=lambda bundle: VoteAction.objects.filter( vote=bundle.obj).select_related('member'), null=True, full=True) agendas = fields.ListField() tags = fields.ToManyField('auxiliary.api.TagResource', attribute=lambda t: t.obj.tags, null=True, full=False) def build_filters(self, filters={}): orm_filters = super(VoteResource, self).build_filters(filters) if 'tag' in filters: # hard-coded the __in filter. not great, but works. orm_filters["tagged_items__tag__in"] = \ filters["tag"].split(',') if 'from_date' in filters and filters.get('from_date'): orm_filters["time__gte"] = filters['from_date'] if 'to_date' in filters: # the to_date needs to be incremented by a day since when humans say to_date=2014-07-30 they # actually mean midnight between 30 to 31. python on the other hand interperts this as midnight between # 29 and 30 to_date = parser.parse(filters["to_date"]) + timedelta(days=1) orm_filters["time__lte"] = to_date.strftime("%Y-%m-%d") return orm_filters def dehydrate_agendas(self, bundle): agendavotes = bundle.obj.agendavotes.select_related('agenda') result = [] for avote in agendavotes: agenda = avote.agenda resource_uri = reverse('api_dispatch_detail', kwargs={ 'resource_name': 'agenda', 'api_name': 'v2', 'pk': agenda.pk }) agenda_bundle = { 'name': agenda.name, 'image': agenda.image.url if agenda.image else None, 'resource_uri': resource_uri, 'score': avote.score, 'importance': avote.importance, 'reasoning': avote.reasoning, } result.append(agenda_bundle) return result
class SwarmResource(ReversionModelResource): app = fields.ToOneField('vr.server.api.resources.AppResource', 'app') squad = fields.ToOneField('vr.server.api.resources.SquadResource', 'squad') # Leave 'release' blank when you want to set 'version' to # something new, and the model will intelligently create a new # release for you. release = fields.ToOneField('vr.server.api.resources.ReleaseResource', 'release', blank=True, null=True) shortname = fields.CharField('shortname') volumes = fields.ListField('volumes', null=True) config_ingredients = fields.ToManyField( 'vr.server.api.resources.IngredientResource', 'config_ingredients') compiled_config = fields.DictField('get_config') compiled_env = fields.DictField('get_env') version = fields.CharField('version') class Meta: queryset = models.Swarm.objects.select_related( 'app', 'squad', 'release').prefetch_related( 'config_ingredients', 'squad__hosts', 'release__build', 'release__build__app', ).all() resource_name = 'swarms' filtering = { 'ingredients': ALL_WITH_RELATIONS, 'squad': ALL_WITH_RELATIONS, 'app': ALL_WITH_RELATIONS, 'proc_name': ALL, 'config_name': ALL, 'pool': ALL, } authentication = auth.MultiAuthentication( auth.BasicAuthentication(), auth.SessionAuthentication(), ) authorization = Authorization() def dehydrate(self, bundle): # add in proc data # TODO: Make these proper attributes so they can be saved by a # PUT/POST to the swarm resource. bundle.data['procs_uri'] = bundle.data['resource_uri'] + 'procs/' bundle.data['procs'] = [ p.as_dict() for p in bundle.obj.get_procs(check_cache=True) ] bundle.data['squad_name'] = bundle.obj.squad.name # Also add in convenience data bundle.data.update(app_name=bundle.obj.app.name, config_name=bundle.obj.config_name) return bundle def dehydrate_env_yaml(self, bundle): # Explicit dehydrate to avoid this field is stringified with str() return yamlize(bundle.obj.env_yaml) def dehydrate_config_yaml(self, bundle): # Explicit dehydrate to avoid this field is stringified with str() return yamlize(bundle.obj.config_yaml) def hydrate(self, bundle): # delete the compiled_config and compiled_env keys in the # bundle, because they can cause hydration problems if # tastypie tries to set them. bundle.data.pop('compiled_config', None) bundle.data.pop('compiled_env', None) # If version is provided, that takes priority over release if 'version' in bundle.data: bundle.data.pop('release', None) return bundle def prepend_urls(self): return [ url(r"^(?P<resource_name>%s)/(?P<pk>\w[\w/-]*)/swarm%s$" % (self._meta.resource_name, trailing_slash()), auth_required(self.wrap_view('do_swarm')), name="api_do_swarm"), ] def do_swarm(self, request, **kwargs): if request.method == 'POST': try: swarm = models.Swarm.objects.get(id=int(kwargs['pk'])) except models.Swarm.DoesNotExist: return HttpResponseNotFound() swarm_id = do_swarm(swarm, request.user) # Status 202 means "The request has been accepted for # processing, but the processing has not been completed." return HttpResponse(json.dumps({'swarm_id': swarm_id}), status=202, content_type='application/json') return HttpResponseNotAllowed(["POST"]) def apply_filters(self, request, applicable_filters): base_object_list = super(SwarmResource, self).apply_filters(request, applicable_filters) # Allow filtering Swarms on pool name, like so: # /api/v1/swarms/?pool=[pool_name] pool = request.GET.get('pool', None) if pool: base_object_list = base_object_list.filter(pool=pool) return base_object_list
class LookupTableResource(CouchResourceMixin, HqBaseResource): id = tp_f.CharField(attribute='get_id', readonly=True, unique=True) is_global = tp_f.BooleanField(attribute='is_global') tag = tp_f.CharField(attribute='tag') fields = tp_f.ListField(attribute='fields') item_attributes = tp_f.ListField(attribute='item_attributes') def dehydrate_fields(self, bundle): return [{ 'field_name': field.field_name, 'properties': field.properties, } for field in bundle.obj.fields] def obj_get(self, bundle, **kwargs): return get_object_or_not_exist(FixtureDataType, kwargs['pk'], kwargs['domain']) def obj_get_list(self, bundle, domain, **kwargs): return list(FixtureDataType.by_domain(domain)) def obj_delete(self, bundle, **kwargs): try: data_type = FixtureDataType.get(kwargs['pk']) except ResourceNotFound: raise NotFound('Lookup table not found') with CouchTransaction() as transaction: data_type.recursive_delete(transaction) return ImmediateHttpResponse(response=HttpAccepted()) def obj_create(self, bundle, request=None, **kwargs): if FixtureDataType.by_domain_tag(kwargs['domain'], bundle.data.get("tag")): raise BadRequest("A lookup table with name %s already exists" % bundle.data.get("tag")) bundle.obj = FixtureDataType(bundle.data) bundle.obj.domain = kwargs['domain'] bundle.obj.save() return bundle def obj_update(self, bundle, **kwargs): if 'tag' not in bundle.data: raise BadRequest("tag must be specified") try: bundle.obj = FixtureDataType.get(kwargs['pk']) except ResourceNotFound: raise NotFound('Lookup table not found') if bundle.obj.domain != kwargs['domain']: raise NotFound('Lookup table not found') if bundle.obj.tag != bundle.data['tag']: raise BadRequest("Lookup table tag cannot be changed") save = False if 'is_global' in bundle.data: save = True bundle.obj.is_global = bundle.data['is_global'] if 'fields' in bundle.data: save = True bundle.obj.fields = [ FixtureTypeField.wrap(field) for field in bundle.data['fields'] ] if 'item_attributes' in bundle.data: save = True bundle.obj.item_attributes = bundle.data['item_attributes'] if save: bundle.obj.save() return bundle class Meta(CustomResourceMeta): object_class = FixtureDataType detail_allowed_methods = ['get', 'put', 'delete'] list_allowed_methods = ['get', 'post'] resource_name = 'lookup_table'
class LoopUserResource(BaseResource): user = fields.ForeignKey(UserResource, 'user') village = fields.ForeignKey(VillageResource, 'village') assigned_villages = fields.ListField() assigned_mandis = fields.ListField() class Meta: queryset = LoopUser.objects.prefetch_related('assigned_villages', 'assigned_mandis', 'user').all() resource_name = 'loopuser' authorization = Authorization() hydrate_user = partial(dict_to_foreign_uri, field_name='user') hydrate_village = partial(dict_to_foreign_uri, field_name='village') hydrate_assigned_villages = partial(dict_to_foreign_uri_m2m, field_name='assigned_villages', resource_name='village') hydrate_assigned_mandis = partial(dict_to_foreign_uri_m2m, field_name='assigned_mandis', resource_name='mandi') dehydrate_user = partial(foreign_key_to_id, field_name='user', sub_field_names=['id', 'username']) dehydrate_village = partial(foreign_key_to_id, field_name='village', sub_field_names=['id', 'village_name']) def obj_create(self, bundle, **kwargs): bundle = super(LoopUserResource, self).obj_create(bundle, **kwargs) assigned_mandi_list = bundle.data.get('assigned_mandis') assigned_village_list = bundle.data.get('assigned_villages') if assigned_mandi_list or assigned_village_list: user_id = None if bundle.request.user: user_id = bundle.request.user.id loop_user_id = getattr(bundle.obj, 'id') for mandi in assigned_mandi_list: try: assigned_mandi_obj = LoopUserAssignedMandi( loop_user_id=loop_user_id, mandi_id=mandi['mandi_id'], user_created_id=user_id) assigned_mandi_obj.save() except Exception, e: raise AssignedMandiNotSaved( 'For Loop User with id: ' + str(loop_user_id) + ' mandi is not getting saved. Mandi details: ' + str(e)) for village in assigned_village_list: try: assigned_village_obj = LoopUserAssignedVillage( loop_user_id=loop_user_id, village_id=village['village_id'], user_created_id=user_id) assigned_village_obj.save() except Exception, e: raise AssignedVillageNotSaved( 'For Loop User with id: ' + str(loop_user_id) + ' village is not getting saved. Village details: ' + str(e)) return bundle
class MemberAgendasResource(BaseResource): ''' The Parliament Member Agenda-compliance API ''' agendas = fields.ListField() class Meta(BaseResource.Meta): queryset = Member.objects.select_related('current_party').order_by() allowed_methods = ['get'] fields = ['agendas' ] # We're not really interested in any member details here resource_name = "member-agendas" def dehydrate_agendas(self, bundle): mk = bundle.obj _cache_key = 'api_v2_member_agendas_' + str(mk.pk) agendas = cache.get(_cache_key) if not agendas: agendas_values = mk.get_agendas_values() if mk.current_party: friends = (mk.current_party.current_members().values_list( 'id', flat=True)) else: friends = [] agendas = [] for a in Agenda.objects.filter(pk__in=agendas_values.keys(), is_public=True): amin = 200.0 amax = -200.0 pmin = 200.0 pmax = -200.0 av = agendas_values[a.id] for mk_id, values in a.get_mks_values_old(): score = values['score'] if score < amin: amin = score if score > amax: amax = score if mk_id in friends: if score < pmin: pmin = score if score > pmax: pmax = score agendas.append( dict( name=a.name, id=a.id, owner=a.public_owner_name, score=av['score'], rank=av['rank'], min=amin, max=amax, party_min=pmin, party_max=pmax, absolute_url=a.get_absolute_url(), )) cache.set(_cache_key, agendas, 24 * 3600) return agendas
class AnswerResource(MongoUserResource): course_id = fields.IntegerField(null=False) unit_id = fields.IntegerField(null=False) kq_id = fields.IntegerField(null=False) question_id = fields.IntegerField(null=False) date = fields.DateTimeField(readonly=True, default=datetime.now) replyList = fields.ListField(null=False) class Meta: resource_name = 'answer' collection = 'answers' datakey = 'question_id' object_class = MongoObj authentication = DjangoAuthentication() authorization = DjangoAuthorization() allowed_methods = ['get', 'post', 'put'] filtering = { "question_id": ('exact'), "course_id": ('exact'), "unit_id": ('exact'), "kq_id": ('exact'), } validation = AnswerValidation() input_schema = { "course_id": 1, "unit_id": 1, "kq_id": 1, "question_id": 1, "replyList": 1, "user_id": 0, "date": 0, } def obj_create(self, bundle, request=None, **kwargs): bundle.data["date"] = datetime.utcnow() bundle = super(AnswerResource, self).obj_create(bundle, request) bundle.uuid = bundle.obj.question_id return bundle def obj_update(self, bundle, request=None, **kwargs): answer_validate_date(bundle, request) question_id = int(kwargs.get("pk")) if (len(bundle.data.get("replyList", [])) > 0): newobj = self._collection.find_and_modify( { 'user_id': request.user.id, 'question_id': question_id, }, update={ "$set": { 'replyList': bundle.data.get("replyList"), "date": datetime.utcnow(), } }, safe=True, new=True) bundle.obj = newobj self.send_updated_signal(request.user.id, bundle.obj) return bundle
class MemberResource(BaseResource): ''' The Parliament Member API ''' class Meta(BaseResource.Meta): queryset = Member.objects.exclude( current_party__isnull=True).select_related('current_party') allowed_methods = ['get'] ordering = [ 'name', 'is_current', 'bills_stats_proposed', 'bills_stats_pre', 'bills_stats_first', 'bills_stats_approved', ] filtering = dict( name=ALL, is_current=ALL, ) excludes = ['website', 'backlinks_enabled', 'area_of_residence'] list_fields = [ 'name', 'id', 'img_url', 'is_current', 'average_weekly_presence_hours', 'mmms_count', 'bills_stats_first', 'bills_stats_proposed', ] include_absolute_url = True party_name = fields.CharField() party_url = fields.CharField() mmms_count = fields.IntegerField(null=True) votes_count = fields.IntegerField(null=True) video_about = fields.ToManyField( VideoResource, attribute=lambda b: get_videos_queryset(b.obj, group='about'), null=True, full=True) videos_related = fields.ToManyField( VideoResource, attribute=lambda b: get_videos_queryset(b.obj, group='related'), null=True) links = fields.ToManyField( LinkResource, attribute=lambda b: Link.objects.for_model(b.obj), full=True, null=True) bills_uri = fields.CharField() agendas_uri = fields.CharField() committees = fields.ListField() detailed_roles = fields.ToManyField( RoleResource, attribute=lambda b: Person.objects.get(mk=b.obj).roles.all(), full=True, null=True) fields.ToOneField(PartyResource, 'current_party', full=True) average_weekly_presence_rank = fields.IntegerField() def obj_get_list(self, bundle, **kwargs): simple = super(MemberResource, self).obj_get_list(bundle, **kwargs) if hasattr(bundle.request, 'GET'): # Grab a mutable copy. filters = bundle.request.GET.copy() # Update with the provided kwargs. filters.update(kwargs) name = filters.get('name') if name and not simple: try: return Member.objects.filter(person__aliases__name=name) except PersonAlias.DoesNotExist: return simple return simple def dehydrate_committees(self, bundle): temp_list = bundle.obj.committee_meetings.exclude( committee__type='plenum') temp_list = temp_list.values("committee", "committee__name").annotate( Count("id")).order_by('-id__count')[:5] return (map( lambda item: (item['committee__name'], reverse('committee-detail', args=[item['committee']])), temp_list)) def dehydrate_bills_uri(self, bundle): return '%s?%s' % (reverse( 'api_dispatch_list', kwargs={ 'resource_name': 'bill', 'api_name': 'v2', }), urllib.urlencode(dict(proposer=bundle.obj.id))) def dehydrate_gender(self, bundle): return bundle.obj.get_gender_display() def dehydrate_agendas_uri(self, bundle): return reverse('api_dispatch_detail', kwargs={ 'resource_name': 'member-agendas', 'api_name': 'v2', 'pk': bundle.obj.id }) def dehydrate_party_name(self, bundle): party = bundle.obj.current_party return party.name if party else None def dehydrate_party_url(self, bundle): party = bundle.obj.current_party return party.get_absolute_url() if party else None def dehydrate_mmms_count(self, bundle): _cache_key = 'api_v2_member_mmms_' + str(bundle.obj.pk) count = cache.get(_cache_key) if count is None: count = bundle.obj.mmm_documents.count() cache.set(_cache_key, count, 24 * 3600) return count def dehydrate_votes_count(self, bundle): _cache_key = 'api_v2_member_votes_' + str(bundle.obj.pk) count = cache.get(_cache_key) if count is None: count = bundle.obj.votes.count() cache.set(_cache_key, count, 24 * 3600) return count def dehydrate_average_weekly_presence_rank(self, bundle): ''' Calculate the distribution of presence and place the user on a 5 level scale ''' SCALE = 5 member = bundle.obj rel_location = cache.get('average_presence_location_%d' % member.id) if not rel_location: presence_list = sorted( map(lambda member: member.average_weekly_presence_hours, Member.objects.all())) presence_groups = int(math.ceil(len(presence_list) / float(SCALE))) # Generate cache for all members for mk in Member.objects.all(): avg = mk.average_weekly_presence_hours if avg: mk_location = 1 + (presence_list.index(avg) / presence_groups) else: mk_location = 0 cache.set('average_presence_location_%d' % mk.id, mk_location, 60 * 60 * 24) if mk.id == member.id: rel_location = mk_location return rel_location def build_filters(self, filters=None): if filters is None: filters = {} try: knesset = int(filters.get('knesset', 0)) except KeyError: knesset = 0 orm_filters = super(MemberResource, self).build_filters(filters) if knesset: knesset = Knesset.objects.get(number=knesset) orm_filters['parties__knesset'] = knesset return orm_filters
class JobDuration(StatisticsResource): """ Histograms of total job duration (from submission to completion) for completed jobs and for error jobs """ status = fields.CharField(attribute="status") platform = fields.CharField(attribute="platform") values = fields.ListField(attribute="values") bins = fields.ListField(attribute="bins") max = fields.FloatField(attribute="max") class Meta: resource_name = "statistics/job-duration" list_allowed_methods = ['get'] detail_allowed_methods = [] def get_object_list(self, request): n_bins = int(request.GET.get("bins", 50)) scale = request.GET.get("scale", "linear") requested_max = request.GET.get("max", None) all_jobs = Job.objects.annotate( duration=ExpressionWrapper(F('timestamp_completion') - F('timestamp_submission'), output_field=DurationField())) job_durations = [] for status in ("finished", "error"): for platform in STANDARD_QUEUES: durations = [ x['duration'].total_seconds() for x in all_jobs.filter( status=status, hardware_platform=platform).values( 'duration') if x['duration'] is not None ] durations = np.array(durations) negative_durations = (durations < 0) if negative_durations.any(): n_neg = negative_durations.sum() logger.warning( "There were {} negative durations ({}%) for status={} and platform={}" .format(n_neg, 100 * n_neg / durations.size, status, platform)) durations = durations[~negative_durations] if durations.size > 0: if requested_max is None: max = (durations.max() // n_bins + 1) * n_bins else: max = float(requested_max) if scale == "log": log_bins = np.linspace(0, np.ceil(np.log10(max)), n_bins) values = np.histogram(np.log10(durations), bins=log_bins)[0] #bins = np.power(10, log_bins) bins = log_bins else: # linear, whatever the value of `scale` values, bins = np.histogram(durations, bins=n_bins, range=(0, max)) job_durations.append( Histogram(platform=platform, status=status, values=values.tolist(), bins=bins, scale=scale, max=max)) return job_durations
class ApplicationResource(BaseApplicationResource): id = fields.CharField(attribute='_id') name = fields.CharField(attribute='name') version = fields.IntegerField(attribute='version') is_released = fields.BooleanField(attribute='is_released', null=True) built_on = fields.DateTimeField(attribute='built_on', null=True) build_comment = fields.CharField(attribute='build_comment', null=True) built_from_app_id = fields.CharField(attribute='copy_of', null=True) modules = fields.ListField() versions = fields.ListField() @staticmethod def dehydrate_versions(bundle): app = bundle.obj if app.copy_of: return [] results = get_all_built_app_results(app.domain, app.get_id) return [{ 'id': result['value']['_id'], 'built_on': result['value']['built_on'], 'build_comment': result['value']['build_comment'], 'is_released': result['value']['is_released'], 'version': result['value']['version'], } for result in results] @staticmethod def dehydrate_module(app, module, langs): """ Convert a Module object to a JValue representation with just the good parts. NOTE: This is not a tastypie "magic"-name method to dehydrate the "module" field; there is no such field. """ try: dehydrated = {} dehydrated['case_type'] = module.case_type dehydrated['case_properties'] = get_case_properties( app, [module.case_type], defaults=['name'])[module.case_type] dehydrated['unique_id'] = module.unique_id dehydrated['forms'] = [] for form in module.forms: form_unique_id = form.unique_id form_jvalue = { 'xmlns': form.xmlns, 'name': form.name, 'questions': form.get_questions(langs, include_triggers=True, include_groups=True, include_translations=True), 'unique_id': form_unique_id, } dehydrated['forms'].append(form_jvalue) return dehydrated except Exception as e: return {'error': str(e)} def dehydrate_modules(self, bundle): app = bundle.obj if app.doc_type == Application._doc_type: return [ self.dehydrate_module(app, module, app.langs) for module in bundle.obj.modules ] elif app.doc_type == RemoteApp._doc_type: return [] def dehydrate(self, bundle): if not _safe_bool(bundle, "extras"): return super(ApplicationResource, self).dehydrate(bundle) else: app_data = {} app_data.update(bundle.obj._doc) app_data.update(bundle.data) return app_data
class ScreeningResource(BaseResource): village = fields.ForeignKey(VillageResource, 'village') animator = fields.ForeignKey(MediatorResource, 'animator') partner = fields.ForeignKey(PartnerResource, 'partner') parentcategory = fields.ForeignKey(ParentCategoryResource, 'parentcategory', null=True) frontlineworkerpresent = fields.ToManyField( 'coco.api.FrontLineWorkerPresentResource', 'frontlineworkerpresent', related_name='screening') videoes_screened = fields.ToManyField('coco.api.VideoResource', 'videoes_screened', related_name='screening') farmer_groups_targeted = fields.ToManyField('coco.api.PersonGroupResource', 'farmer_groups_targeted', related_name='screening') farmers_attendance = fields.ListField() category = fields.ListField() dehydrate_village = partial(foreign_key_to_id, field_name='village', sub_field_names=['id', 'village_name']) dehydrate_parentcategory = partial( foreign_key_to_id, field_name='parentcategory', sub_field_names=['id', 'parent_category_name']) dehydrate_animator = partial(foreign_key_to_id, field_name='animator', sub_field_names=['id', 'name']) hydrate_village = partial(dict_to_foreign_uri, field_name='village') hydrate_animator = partial(dict_to_foreign_uri, field_name='animator', resource_name='mediator') hydrate_farmer_groups_targeted = partial( dict_to_foreign_uri_m2m, field_name='farmer_groups_targeted', resource_name='group') hydrate_videoes_screened = partial(dict_to_foreign_uri_m2m, field_name='videoes_screened', resource_name='video') hydrate_frontlineworkerpresent = partial( dict_to_foreign_uri_m2m, field_name='frontlineworkerpresent', resource_name='frontlineworkerpresent') hydrate_partner = partial(assign_partner) hydrate_parentcategory = partial(dict_to_foreign_uri, field_name='parentcategory') # For Network and Client Side Optimization Sending Screenings after 1 Jan 2013 class Meta: max_limit = None queryset = Screening.objects.prefetch_related( 'village', 'animator', 'videoes_screened', 'farmer_groups_targeted', 'personmeetingattendance_set__person', 'partner').filter(date__gte=datetime.now().date() - timedelta(days=365)) resource_name = 'screening' authentication = SessionAuthentication() authorization = VillagePartnerAuthorization('village__in') validation = ModelFormValidation(form_class=ScreeningForm) always_return_data = True excludes = [ 'location', 'time_created', 'time_modified', 'observation_status', 'screening_grade', 'observer' ] def obj_create(self, bundle, **kwargs): pma_list = bundle.data.get('farmers_attendance') if pma_list: bundle = super(ScreeningResource, self).obj_create(bundle, **kwargs) user_id = None if bundle.request.user: user_id = bundle.request.user.id screening_id = getattr(bundle.obj, 'id') for pma in pma_list: try: person_obj = Person.objects.get(id=pma['person_id']) person_obj.age = int( pma.get('age')) if pma.get('age') else None person_obj.gender = pma.get('gender') if pma.get( 'gender') else None person_obj.save() if pma.get('category'): category = json.dumps(pma.get('category')) else: category = None attendance = PersonMeetingAttendance( screening_id=screening_id, person_id=pma['person_id'], user_created_id=user_id, category=category) attendance.save() except Exception, e: raise PMANotSaved( 'For Screening with id: ' + str(screening_id) + ' pma is not getting saved. pma details: ' + str(e)) return bundle else:
class VosaeUserResource(WakeUpMixinResource, ZombieMixinResource, TenantResource): full_name = base_fields.CharField( attribute='get_full_name', readonly=True, help_text=HELP_TEXT['vosae_user']['full_name']) email = base_fields.CharField(attribute='email', help_text=HELP_TEXT['vosae_user']['email']) status = base_fields.CharField(attribute='status', blank=True, help_text=HELP_TEXT['vosae_user']['status']) photo_uri = base_fields.CharField( attribute='photo_uri', readonly=True, null=True, blank=True, help_text=HELP_TEXT['vosae_user']['photo_uri']) specific_permissions = base_fields.DictField( attribute='specific_permissions', blank=True, help_text=HELP_TEXT['vosae_user']['specific_permissions']) permissions = base_fields.ListField( readonly=True, help_text=HELP_TEXT['vosae_user']['permissions']) groups = fields.ReferencedListField( of='core.api.resources.VosaeGroupResource', attribute='groups', null=True, blank=True, help_text=HELP_TEXT['vosae_user']['groups']) settings = fields.EmbeddedDocumentField( embedded='core.api.resources.VosaeUserSettingsResource', attribute='settings', help_text=HELP_TEXT['vosae_user']['settings']) class Meta(TenantResource.Meta): resource_name = 'user' queryset = VosaeUser.objects.all() list_allowed_methods = ('get', 'post') excludes = ('tenant', ) filtering = {"email": ('exact', )} @classmethod def post_create(self, sender, resource, bundle, **kwargs): """ Post create hook. Fills initial data (based on request's language) after VosaeUser creation """ # Fill user initial data (Tenant and VosaeUser are required) fill_user_initial_data.delay(bundle.obj, bundle.request.LANGUAGE_CODE) def hydrate_email(self, bundle): """ Email can only be used on POST (creation) in order to link the :class:`~core.models.VosaeUser` to the Django user. """ if bundle.request.method.lower() != 'post': bundle.data.update(email=bundle.obj.email) return bundle def dehydrate_permissions(self, bundle): """Returns the list of acquired permissions""" return list(bundle.obj.permissions.acquired)