def get_scopes(self, obj): user = self.context.get('request').user superuser = user.is_superuser is True at_least_admin = (False if user.is_anonymous else user.is_at_least_admin) staff = False if user.is_anonymous else user.is_at_least_staff if staff or at_least_admin or superuser: divider = getattr(obj, DIVIDER_MODEL.lower(), None) if divider: return {"entity_uid": divider.uid} return None
def test_filter_objects_by_divider(self): url_projects = '/api/v1.1/project/' # User get only projects from cloisonX url_filter = '/api/v1.1/project/?{}={}'.format( DIVIDER_MODEL.lower(), str(self.cloisonX.uid) ) resp = self.client.get( url_filter, HTTP_AUTHORIZATION='Token {}'.format(self.token_a) ) self.assertEqual( resp.status_code, status.HTTP_200_OK, msg=resp.content ) results = resp.json()['results'] self.assertEqual(len(results), 1) self.assertEqual(results[0]['name'], "projet A") # User get only projects from cloisonY url_filter = '/api/v1.1/project/?{}={}'.format( DIVIDER_MODEL.lower(), str(self.cloisonY.uid) ) resp = self.client.get( url_filter, HTTP_AUTHORIZATION='Token {}'.format(self.token_a) ) self.assertEqual( resp.status_code, status.HTTP_200_OK, msg=resp.content ) results = resp.json()['results'] self.assertEqual(len(results), 1) self.assertEqual(results[0]['name'], "projet B") # User get two projects without filter resp = self.client.get( url_projects, HTTP_AUTHORIZATION='Token {}'.format(self.token_a) ) self.assertEqual(len(resp.json()['results']), 2)
class Meta: model = get_user_model() fields = ( "uid", 'email', "url", "token", 'first_name', "password", "last_name", "level", 'is_verified', 'groups', 'external_auth', "{}s".format(DIVIDER_MODEL.lower()), )
def make_account_me_serialier(api_namespace=DEFAULT_API_NAMESPACE): meta = get_meta_definition_by_model_name('User') meta_serializer_class = make_serializer_class(meta_model=meta, api_namespace=api_namespace, nested=False, safe=True) Meta = meta_serializer_class.Meta Meta.fields = [ field for field in Meta.fields if field not in ['admin', 'is_staff', 'is_superuser', 'is_active'] ] + ['level'] Meta.read_only_fields = Meta.read_only_fields + [ 'uid', 'public', 'creation_date', 'modification_date', '{}s'.format(DIVIDER_MODEL.lower()), ] serializer_attrs = { 'Meta': Meta, 'level': serializers.SerializerMethodField(), 'get_level': lambda self, obj: obj.get_level(), } if settings.USE_CONCRETE_ROLES: Meta.fields = Meta.fields + ['roles', 'roles_uid'] Meta.read_only_fields = Meta.read_only_fields + ['roles', 'roles_uid'] serializer_attrs.update({ 'roles': serializers.SerializerMethodField(), 'get_roles': lambda self, obj: obj.get_roles(), 'roles_uid': serializers.SerializerMethodField(), 'get_roles_uid': lambda self, obj: obj.get_roles_uid(), }) return type(str('AccountMeSerializer'), (meta_serializer_class, ), serializer_attrs)
def get_scopes(self, obj): divider = getattr(obj, DIVIDER_MODEL.lower(), None) if divider: return {"entity_uid": divider.uid} return None
def make_serializer_class( meta_model, api_namespace=DEFAULT_API_NAMESPACE, limit_fields=None, nested=True, safe=False, ): enum_fields = list(meta_model.get_fields()) dict_fields = OrderedDict(enum_fields) _all_fields = (list(dict_fields.keys()) + list(get_common_fields().keys()) + ['url', 'verbose_name']) custom_fields_names, custom_fields_attrs = make_custom_serializer_fields( meta_model, api_namespace=api_namespace) _all_fields += custom_fields_names if meta_model.get_model_name() not in ('User', ): _all_fields += get_user_tracked_fields().keys() if meta_model.get_model_name() not in ('User', DIVIDER_MODEL): _all_fields += ['scopes'] api_display_fields = meta_model.get_property('m_api_list_display') or [] if api_display_fields == []: if limit_fields is None: _fields = _all_fields else: _fields = [f for f in _all_fields if f in limit_fields] else: _fields = api_display_fields if meta_model.get_model_name() == 'User' and api_display_fields == []: _fields += [ 'last_name', 'first_name', "{}s".format(DIVIDER_MODEL.lower()), "admin", "is_staff", "level", "unsubscribe_notification_url", "unsubscribe_all", "unsubscribe_to", "external_auth", ] if safe: _fields += ['email'] # TODO: rajouter les <name>_uid dans _fields fk_read_only_fields = [] for name, field in enum_fields: if field.type.startswith("rel_"): _fields += ['{}_uid'.format(name)] fk_read_only_fields += [name] class Meta: model = concrete.models[meta_model.get_model_name().lower()] fields = _fields read_only_fields = ( ['created_by', 'admin', 'is_staff'] + fk_read_only_fields + [f for f in _all_fields if f.startswith('resource_')]) extra_kwargs = { name: { 'required': is_field_required(field) } for name, field in enum_fields } # TODO: DEACTIVATED by LCO on 06/11/18 # vars_model = vars(model) # for key, value in vars_model.items(): # # TODO: Exclude model User # if isinstance(value, ReverseManyToOneDescriptor): # if not (key.startswith('divider') or (key.startswith('can'))): # fields.append(key) # read_only_fields.append(key) attrs = {'Meta': Meta} # TODO : if field is relational, expose pk and url serialized for name, field in enum_fields: if field.f_type == 'FileField': attrs.update({ name: serializers.FileField( required=False, allow_null=True, validators=[validate_file], ) }) if field.f_type == 'PointField': attrs.update({ name: PointField( required=not field.f_args.get("blank", False), allow_null=True, ) }) if field.f_type == 'JSONField': attrs.update( {name: serializers.JSONField(binary=False, required=False)}) if field.type.startswith("rel_") and nested is True: force_nested = getattr(field, 'force_nested', False) attrs.update({ name: make_related_serializer_class( target_model_name=field.f_args['to'], many=(field.type == 'rel_iterable'), nested=force_nested, api_namespace=api_namespace, ) }) attrs.update(custom_fields_attrs) class _ModelSerializer(serializers.ModelSerializer): url = serializers.SerializerMethodField() verbose_name = serializers.SerializerMethodField() scopes = serializers.SerializerMethodField() def get_scopes(self, obj): divider = getattr(obj, DIVIDER_MODEL.lower(), None) if divider: return {"entity_uid": divider.uid} return None def get_url(self, obj): uri = reverse( "{}:{}-detail".format(api_namespace, meta_model.get_dashed_case_class_name()), args=(obj.pk, ), ) if hasattr(self, '_context'): if 'request' in self._context: request = self._context['request'] return request.build_absolute_uri(uri) return build_absolute_uri(uri) # skip-test-coverage def get_verbose_name(self, obj): try: return str(obj) except Exception: return '' for name, field in enum_fields: attrs.update({f'validate_{name}': get_field_validator(field=field)}) if field.type.startswith("rel_i"): x = field.f_args["to"].split('.') field_model = apps.get_model(app_label=x[0], model_name=x[1]) required = not field.f_args.get("blank", False) attrs.update({ '{}_uid'.format(name): serializers.PrimaryKeyRelatedField( source=name, many=True, allow_null=True, required=required, queryset=field_model.objects.all(), ) }) if field.type.startswith("rel_s"): # Ex: concrete.Category, split to get # Django model with apps.get_model() x = field.f_args["to"].split('.') field_model = apps.get_model(app_label=x[0], model_name=x[1]) required = not field.f_args.get("blank", False) null = field.f_args.get("null", False) attrs.update({ '{}_uid'.format(name): serializers.PrimaryKeyRelatedField( many=False, source=name, allow_null=null, required=required, queryset=field_model.objects.all(), ) }) if meta_model.get_model_name() == 'User': attrs.update({'level': serializers.CharField()}) def validate_level(self, value): value = value.lower() if value not in LIST_USER_LEVEL: raise serializers.ValidationError("Wrong value") else: user_level = self.context.get('request').user.level forbidden_for_admin = user_level == "admin" and value in [ "admin", "superuser", ] forbidden_for_manager = user_level == "manager" and value in [ "admin", "superuser", "manager", "blocked", ] forbidden_for_simple = user_level == "simpleuser" if (forbidden_for_manager or forbidden_for_admin or forbidden_for_simple): raise serializers.ValidationError( "You don't have permission to set this level") return value _ModelSerializer.validate_level = validate_level attrs.update({ 'unsubscribe_notification_url': serializers.SerializerMethodField('get_unsubscribe_url') }) def get_unsubscribe_url(self, obj): return '{scheme}://{domain}:{port}{uri}'.format( scheme=settings.SCHEME, domain=settings.HOSTNAME, port=settings.PORT, uri=reverse( 'concrete:unsubscribe_notifications', kwargs={'token': obj.subscription_notification_token}, ), ) _ModelSerializer.get_unsubscribe_url = get_unsubscribe_url api_model_serializer = type( str('{}ModelSerializer'.format(meta_model.get_model_name())), (_ModelSerializer, ), attrs, ) return api_model_serializer
from django.db.models import Q from django.conf import settings from django.contrib.auth import get_user_model from rest_framework.exceptions import APIException from rest_framework import permissions, status from concrete_datastore.concrete.models import ( ConcretePermission, DIVIDER_MODEL, UNDIVIDED_MODEL, ) DIVIDER_MODELs = "{}s".format(DIVIDER_MODEL) DIVIDER_MODELs_LOWER = DIVIDER_MODELs.lower() DIVIDER_MODEL_LOWER = DIVIDER_MODEL.lower() class PreconditionFailed(APIException): status_code = status.HTTP_412_PRECONDITION_FAILED default_detail = 'Precondition Fail to perform this action' default_code = 'precondition_failed' CONCRETE_SETTINGS = getattr(settings, 'CONCRETE', {}) API_PERMISSIONS_CLASSES = CONCRETE_SETTINGS.get('API_PERMISSIONS_CLASSES', {}) def get_permissions_classes_by_meta_model(meta_model): permissions_classes_path = API_PERMISSIONS_CLASSES.get( meta_model._specifier.name,