class CatalogSerializer(serializers.HyperlinkedModelSerializer): scope = core_serializers.GenericRelatedField() class Meta: model = models.Catalog fields = ( 'uuid', 'url', 'created', 'modified', 'name', 'description', 'catalog_url', 'branch', 'commit', 'runtime_state', 'scope', 'scope_type', ) read_only_fields = ('runtime_state', 'commit') extra_kwargs = { 'url': { 'lookup_field': 'uuid', 'view_name': 'rancher-catalog-detail' }, }
def get_resource_by_url(self, request, resource_url): related_models = structure_models.VirtualMachine.get_all_models() field = core_serializers.GenericRelatedField( related_models=related_models) # Trick to set field context without serializer field._context = {'request': request} return field.to_internal_value(resource_url)
class NestedNodeSerializer(serializers.HyperlinkedModelSerializer): instance = core_serializers.GenericRelatedField( related_models=VirtualMachine.get_all_models(), read_only=True) subnet = serializers.HyperlinkedRelatedField( view_name='openstacktenant-subnet-detail', queryset=openstack_tenant_models.SubNet.objects.all(), lookup_field='uuid', allow_null=True, write_only=True, ) storage = serializers.IntegerField(write_only=True) memory = serializers.IntegerField(write_only=True) cpu = serializers.IntegerField(write_only=True) roles = serializers.MultipleChoiceField( choices=['controlplane', 'etcd', 'worker'], write_only=True) class Meta(object): model = models.Node extra_kwargs = { 'url': { 'lookup_field': 'uuid', 'view_name': 'rancher-node-detail' }, 'cluster': { 'lookup_field': 'uuid', 'view_name': 'rancher-cluster-detail' } } exclude = ('cluster', 'object_id', 'content_type')
def filter_queryset(self, request, queryset, view): event_types = request.query_params.getlist('event_type') if event_types: queryset = queryset.filter(event_type__in=event_types) features = request.query_params.getlist('feature') if features: queryset = queryset.filter( event_type__in=expand_event_groups(features)) if 'scope' in request.query_params: field = core_serializers.GenericRelatedField( related_models=utils.get_loggable_models()) field._context = {'request': request} scope = field.to_internal_value(request.query_params['scope']) # Check permissions visible = scope._meta.model.get_permitted_objects(request.user) if not visible.filter(pk=scope.pk).exists(): return queryset.none() content_type = ContentType.objects.get_for_model(scope._meta.model) events = models.Feed.objects.filter( content_type=content_type, object_id=scope.id, ).values_list('event_id', flat=True) queryset = queryset.filter(id__in=events) elif not request.user.is_staff and not request.user.is_support: # If user is not staff nor support, he is allowed to see # events related to particular scope only. queryset = queryset.none() return queryset
class NodeSerializer(serializers.HyperlinkedModelSerializer): instance = core_serializers.GenericRelatedField( related_models=VirtualMachine.get_all_models(), required=True, ) class Meta: model = models.Node fields = ('uuid', 'url', 'created', 'modified', 'cluster', 'instance', 'controlplane_role', 'etcd_role', 'worker_role', 'get_node_command') extra_kwargs = { 'url': { 'lookup_field': 'uuid', 'view_name': 'rancher-node-detail' }, 'cluster': { 'lookup_field': 'uuid', 'view_name': 'rancher-cluster-detail' } } def validate(self, attrs): instance = attrs.get('instance') if models.Node.objects.filter( object_id=instance.id, content_type=ContentType.objects.get_for_model( instance)).exists(): raise serializers.ValidationError( {'instance': 'The selected instance is already in use.'}) return super(NodeSerializer, self).validate(attrs)
class ResourceSerializer(BaseItemSerializer): class Meta(BaseItemSerializer.Meta): model = models.Resource fields = BaseItemSerializer.Meta.fields + ( 'scope', 'state', 'resource_uuid', 'resource_type', 'project', 'project_uuid', 'project_name', 'customer_uuid', 'customer_name', 'offering_uuid', 'offering_name', 'backend_metadata', 'is_usage_based', ) read_only_fields = ('backend_metadata', 'scope',) state = serializers.ReadOnlyField(source='get_state_display') scope = core_serializers.GenericRelatedField() resource_uuid = serializers.ReadOnlyField(source='backend_uuid') resource_type = serializers.ReadOnlyField(source='backend_type') project = serializers.HyperlinkedRelatedField( lookup_field='uuid', view_name='project-detail', read_only=True, ) project_uuid = serializers.ReadOnlyField(source='project.uuid') project_name = serializers.ReadOnlyField(source='project.name') customer_uuid = serializers.ReadOnlyField(source='project.customer.uuid') customer_name = serializers.ReadOnlyField(source='project.customer.name') offering_uuid = serializers.ReadOnlyField(source='offering.uuid') offering_name = serializers.ReadOnlyField(source='offering.name') # If resource is usage-based, frontend would render button to show and report usage is_usage_based = serializers.ReadOnlyField(source='offering.is_usage_based')
def filter_queryset(self, request, queryset, view): value = self.get_field_value(request) if value: field = core_serializers.GenericRelatedField(related_models=self.get_related_models()) # Trick to set field context without serializer field._context = {'request': request} obj = field.to_internal_value(value) ct = ContentType.objects.get_for_model(obj) return queryset.filter(**{self.object_id_field: obj.id, self.content_type_field: ct}) return queryset
class NestedNodeSerializer(BaseNodeSerializer): instance = core_serializers.GenericRelatedField( related_models=VirtualMachine.get_all_models(), read_only=True) class Meta(BaseNodeSerializer.Meta): extra_kwargs = { 'url': { 'lookup_field': 'uuid', 'view_name': 'rancher-node-detail' }, 'cluster': { 'lookup_field': 'uuid', 'view_name': 'rancher-cluster-detail' }, } exclude = ('cluster', 'object_id', 'content_type', 'name')
class PriceEstimateSerializer(serializers.HyperlinkedModelSerializer): scope = core_serializers.GenericRelatedField( related_models=models.PriceEstimate.get_estimated_models(), required=False) scope_name = serializers.ReadOnlyField(source='scope.name') scope_uuid = serializers.ReadOnlyField(source='scope.uuid') class Meta(object): model = models.PriceEstimate fields = ('url', 'uuid', 'scope', 'scope_name', 'scope_uuid', 'limit', 'total', 'threshold') read_only_fields = ('total', 'scope') extra_kwargs = { 'url': { 'lookup_field': 'uuid' }, } def validate(self, attrs): if 'limit' in attrs: if isinstance(self.instance.scope, structure_models.Project): self._validate_project_limit(self.instance.scope, attrs['limit']) if isinstance(self.instance.scope, structure_models.Customer): self._validate_customer_limit(self.instance.scope, attrs['limit']) return attrs def _validate_project_limit(self, project, limit): customer = project.customer customer_limit = self._get_customer_limit(customer) if customer_limit == -1: return total_limit = self._get_total_limit( customer.projects.exclude(uuid=project.uuid)) + limit if total_limit > customer_limit: message = _( 'Total price limits of projects exceeds organization price limit. ' 'Total limit: %(total_limit)s, organization limit: %(customer_limit)s' ) context = dict(total_limit=total_limit, customer_limit=customer_limit) raise serializers.ValidationError({'limit': message % context}) def _validate_customer_limit(self, customer, limit): if limit == -1: return total_limit = self._get_total_limit(customer.projects.all()) if limit < total_limit: message = _( 'Organization limit cannot be less than a sum of its projects limits: %d' ) raise serializers.ValidationError({'limit': message % total_limit}) def _get_customer_limit(self, customer): try: estimate = models.PriceEstimate.objects.get(scope=customer) return estimate.limit except models.PriceEstimate.DoesNotExist: return -1 def _get_total_limit(self, projects): if not projects.exists(): return 0 estimates = models.PriceEstimate.objects.filter( scope__in=projects).exclude(limit=-1) return estimates.aggregate(Sum('limit'))['limit__sum'] or 0
class IssueSerializer(core_serializers.AugmentedSerializerMixin, serializers.HyperlinkedModelSerializer): resource = core_serializers.GenericRelatedField( related_models=structure_models.ResourceMixin.get_all_models(), required=False) caller = serializers.HyperlinkedRelatedField( view_name='user-detail', lookup_field='uuid', queryset=User.objects.all(), required=False, allow_null=True, ) reporter = serializers.HyperlinkedRelatedField( view_name='support-user-detail', lookup_field='uuid', read_only=True ) assignee = serializers.HyperlinkedRelatedField( view_name='support-user-detail', lookup_field='uuid', queryset=models.SupportUser.objects.all(), required=False, allow_null=True, ) template = serializers.HyperlinkedRelatedField( view_name='support-template-detail', lookup_field='uuid', queryset=models.Template.objects.all(), required=False, allow_null=True, ) resource_type = serializers.SerializerMethodField() resource_name = serializers.ReadOnlyField(source='resource.name') type = serializers.ChoiceField( choices=[(t, t) for t in settings.WALDUR_SUPPORT['ISSUE']['types']], initial=settings.WALDUR_SUPPORT['ISSUE']['types'][0], default=settings.WALDUR_SUPPORT['ISSUE']['types'][0]) is_reported_manually = serializers.BooleanField( initial=False, default=False, write_only=True, help_text=_('Set true if issue is created by regular user via portal.')) class Meta: model = models.Issue fields = ( 'url', 'uuid', 'type', 'key', 'backend_id', 'link', 'summary', 'description', 'status', 'resolution', 'priority', 'caller', 'caller_uuid', 'caller_full_name', 'reporter', 'reporter_uuid', 'reporter_name', 'assignee', 'assignee_uuid', 'assignee_name', 'customer', 'customer_uuid', 'customer_name', 'project', 'project_uuid', 'project_name', 'resource', 'resource_type', 'resource_name', 'created', 'modified', 'is_reported_manually', 'first_response_sla', 'template' ) read_only_fields = ('key', 'status', 'resolution', 'backend_id', 'link', 'first_response_sla') protected_fields = ('customer', 'project', 'resource', 'type', 'caller', 'template', 'priority') extra_kwargs = dict( url={'lookup_field': 'uuid'}, customer={'lookup_field': 'uuid', 'view_name': 'customer-detail'}, project={'lookup_field': 'uuid', 'view_name': 'project-detail'}, ) related_paths = dict( caller=('uuid', 'full_name',), reporter=('uuid', 'name',), assignee=('uuid', 'name',), customer=('uuid', 'name',), project=('uuid', 'name',), ) def get_fields(self): fields = super(IssueSerializer, self).get_fields() if 'view' not in self.context: # On docs generation context does not contain "view". return fields user = self.context['view'].request.user if not user.is_staff and not user.is_support: del fields['link'] return fields def get_resource_type(self, obj): if isinstance(obj.resource, structure_models.ResourceMixin): return SupportedServices.get_name_for_model(obj.resource_content_type.model_class()) def validate(self, attrs): if self.instance is not None: return attrs if attrs.pop('is_reported_manually'): attrs['caller'] = self.context['request'].user if attrs.get('assignee'): raise serializers.ValidationError( {'assignee': _('Assignee cannot be defined if issue is reported manually.')}) else: if not attrs.get('caller'): raise serializers.ValidationError({'caller': _('This field is required.')}) reporter = models.SupportUser.objects.filter( user=self.context['request'].user, is_active=True).first() if not reporter: raise serializers.ValidationError( _('You cannot report issues because your help desk account is not connected to profile.')) attrs['reporter'] = reporter return attrs def validate_customer(self, customer): """ User has to be customer owner, staff or global support """ if not customer: return customer user = self.context['request'].user if (not customer or user.is_staff or user.is_support or customer.has_user(user, structure_models.CustomerRole.OWNER)): return customer raise serializers.ValidationError(_('Only customer owner, staff or support can report customer issues.')) def validate_project(self, project): if not project: return project user = self.context['request'].user if (not project or user.is_staff or user.is_support or project.customer.has_user(user, structure_models.CustomerRole.OWNER) or project.has_user(user, structure_models.ProjectRole.MANAGER) or project.has_user(user, structure_models.ProjectRole.ADMINISTRATOR)): return project raise serializers.ValidationError( _('Only customer owner, project manager, project admin, staff or support can report such issue.')) def validate_resource(self, resource): if resource: self.validate_project(resource.service_project_link.project) return resource def validate_priority(self, priority): user = self.context['request'].user if not user.is_staff and not user.is_support: raise serializers.ValidationError(_('Only staff or support can specify issue priority.')) try: models.Priority.objects.get(name=priority) except (models.Priority.DoesNotExist, models.Priority.MultipleObjectsReturned): raise serializers.ValidationError(_('Priority with requested name does not exist.')) return priority @transaction.atomic() def create(self, validated_data): resource = validated_data.get('resource') if resource: validated_data['project'] = resource.service_project_link.project project = validated_data.get('project') if project: validated_data['customer'] = project.customer validated_data['description'] = render_issue_template('description', validated_data) validated_data['summary'] = render_issue_template('summary', validated_data) return super(IssueSerializer, self).create(validated_data) def _render_template(self, config_name, issue): raw = self.issue_settings[config_name] template = Template(raw) return template.render(Context({'issue': issue}))
class NodeSerializer(serializers.HyperlinkedModelSerializer): instance = core_serializers.GenericRelatedField( related_models=VirtualMachine.get_all_models(), required=True, ) resource_type = serializers.SerializerMethodField() state = serializers.ReadOnlyField(source='get_state_display') service_name = serializers.ReadOnlyField( source='service_project_link.service.settings.name') service_uuid = serializers.ReadOnlyField( source='service_project_link.service.uuid') project_uuid = serializers.ReadOnlyField( source='service_project_link.project.uuid') cluster_name = serializers.ReadOnlyField(source='cluster.name') cluster_uuid = serializers.ReadOnlyField(source='cluster.uuid') instance_name = serializers.ReadOnlyField(source='instance.name') instance_uuid = serializers.ReadOnlyField(source='instance.uuid') class Meta: model = models.Node fields = ( 'uuid', 'url', 'created', 'modified', 'name', 'backend_id', 'project_uuid', 'service_name', 'service_uuid', 'resource_type', 'state', 'cluster', 'cluster_name', 'cluster_uuid', 'instance', 'instance_name', 'instance_uuid', 'controlplane_role', 'etcd_role', 'worker_role', 'get_node_command', 'k8s_version', 'docker_version', 'cpu_allocated', 'cpu_total', 'ram_allocated', 'ram_total', 'pods_allocated', 'pods_total', 'labels', 'annotations', 'runtime_state', ) read_only_fields = ( 'backend_id', 'k8s_version', 'docker_version', 'cpu_allocated', 'cpu_total', 'ram_allocated', 'ram_total', 'pods_allocated', 'pods_total', 'labels', 'annotations', 'runtime_state', ) extra_kwargs = { 'url': { 'lookup_field': 'uuid', 'view_name': 'rancher-node-detail' }, 'cluster': { 'lookup_field': 'uuid', 'view_name': 'rancher-cluster-detail' }, } def validate(self, attrs): instance = attrs.get('instance') if models.Node.objects.filter( object_id=instance.id, content_type=ContentType.objects.get_for_model(instance), ).exists(): raise serializers.ValidationError( {'instance': 'The selected instance is already in use.'}) attrs['name'] = instance.name return super(NodeSerializer, self).validate(attrs) def get_resource_type(self, obj): return 'Rancher.Node'
class PythonManagementSerializer( common_serializers.BaseApplicationSerializer, structure_serializers.PermissionFieldFilteringMixin): REQUEST_IN_PROGRESS_STATES = (core_models.StateMixin.States.CREATION_SCHEDULED, core_models.StateMixin.States.CREATING) state = serializers.SerializerMethodField() virtual_environments = VirtualEnvironmentSerializer(many=True) virtual_envs_dir_path = serializers.CharField(max_length=255, validators=[ RegexValidator( regex=directory_and_library_allowed_pattern, message=_('Virtual environments root directory has invalid format!'), ), ]) name = serializers.SerializerMethodField() type = serializers.SerializerMethodField() instance = core_serializers.GenericRelatedField( related_models=structure_models.ResourceMixin.get_all_models(), required=False) instance_name = serializers.ReadOnlyField(source='instance.name') class Meta(object): model = models.PythonManagement fields = ('url', 'uuid', 'virtual_envs_dir_path', 'system_user', 'state', 'created', 'modified', 'virtual_environments', 'python_version', 'name', 'type', 'instance', 'instance_name',) read_only_fields = ('request_states', 'created', 'modified', 'python_version', 'type', 'name', 'url',) extra_kwargs = { 'url': {'lookup_field': 'uuid'}, } def get_name(self, python_management): instance_name = python_management.instance.name if python_management.instance else 'removed instance' return 'Python Management - %s - %s' % (instance_name, python_management.virtual_envs_dir_path) def get_type(self, python_management): return 'python_management' def get_filtered_field_names(self): return 'project' def get_state(self, python_management): states = [] initialize_request = utils.execute_safely( lambda: models.PythonManagementInitializeRequest.objects.filter(python_management=python_management).latest('id')) if initialize_request and self.is_in_progress_or_errored(initialize_request): return [self.build_state(initialize_request)] states.extend(self.get_request_state( utils.execute_safely(lambda: models.PythonManagementDeleteRequest.objects.filter(python_management=python_management).latest('id')))) states.extend( self.get_request_state( utils.execute_safely( lambda: models.PythonManagementDeleteVirtualEnvRequest.objects.filter(python_management=python_management).latest('id')))) states.extend(self.build_search_requests_states(python_management)) states.extend(self.build_states_from_last_group_of_the_request(python_management, models.PythonManagementSynchronizeRequest)) if not states: return core_models.StateMixin(state=core_models.StateMixin.States.OK).human_readable_state else: creation_scheduled_state = core_models.StateMixin(state=core_models.StateMixin.States.CREATION_SCHEDULED).human_readable_state creating_state = core_models.StateMixin(state=core_models.StateMixin.States.CREATING).human_readable_state erred_state = core_models.StateMixin(state=core_models.StateMixin.States.ERRED).human_readable_state if creating_state in states: return creating_state elif creation_scheduled_state in states: return creation_scheduled_state elif erred_state in states: return erred_state def build_search_requests_states(self, python_management): states = [] states.extend( self.get_request_state( utils.execute_safely( lambda: models.PythonManagementFindVirtualEnvsRequest.objects .filter(python_management=python_management).latest('id')))) states.extend(self.build_states_from_last_group_of_the_request(python_management, models.PythonManagementFindInstalledLibrariesRequest)) return states def get_request_state(self, request): if request and self.is_in_progress_or_errored(request): return [self.build_state(request)] else: return [] def build_states_from_last_group_of_the_request(self, python_management, request_class): states = [] requests = request_class.objects.filter(python_management=python_management).order_by('-id') last_request_group = self.get_last_requests_group(requests) for request in last_request_group: if self.is_in_progress_or_errored(request): states.append(self.build_state(request)) return states def get_last_requests_group(self, requests): last_request_group = [] last_request_time = None for request in requests: if not last_request_time: last_request_time = request.created - datetime.timedelta(minutes=1) if request.created < last_request_time: break last_request_group.append(request) return last_request_group def is_in_progress_or_errored(self, request): return request.state in PythonManagementSerializer.REQUEST_IN_PROGRESS_STATES \ or request.state == core_models.StateMixin.States.ERRED def build_state(self, request, state=None): request_state = state if state else request return request_state.human_readable_state @transaction.atomic def create(self, validated_data): python_management = models.PythonManagement( user=validated_data.get('user'), virtual_envs_dir_path=validated_data.get('virtual_envs_dir_path'), instance=validated_data.get('instance'), project=validated_data.get('instance').service_project_link.project, python_version='3', system_user=validated_data.get('system_user')) python_management.save() return python_management def validate(self, attrs): super(PythonManagementSerializer, self).validate(attrs) if not self.instance: attrs['user'] = self.context['request'].user self.check_resource_type(attrs) self.check_project_permissions(attrs) return attrs def check_resource_type(self, attrs): if not issubclass(type(attrs['instance']), structure_models.VirtualMachine): raise exceptions.ValidationError(_('Please specify a virtual machine, not just any resource.')) def check_project_permissions(self, attrs): if self.instance: project = self.instance.project else: project = attrs['instance'].service_project_link.project if not structure_permissions._has_admin_access(self.context['request'].user, project): raise exceptions.PermissionDenied()
class IssueSerializer(JiraPropertySerializer): priority = serializers.HyperlinkedRelatedField( view_name='jira-priorities-detail', queryset=models.Priority.objects.all(), lookup_field='uuid', ) access_url = serializers.ReadOnlyField(source='get_access_url') comments = CommentSerializer(many=True, read_only=True) scope = core_serializers.GenericRelatedField( source='resource', related_models=structure_models.BaseResource.get_all_models(), required=False, ) scope_type = serializers.SerializerMethodField() scope_name = serializers.ReadOnlyField(source='resource.name') parent = serializers.HyperlinkedRelatedField( view_name='jira-issues-detail', queryset=models.Issue.objects.all(), lookup_field='uuid', required=False, allow_null=True, ) # For consistency with resource serializer render # Waldur project as project and JIRA project as jira_project project = serializers.HyperlinkedRelatedField( source='project.project', view_name='project-detail', read_only=True, lookup_field='uuid', ) project_name = serializers.ReadOnlyField(source='project.project.name') project_uuid = serializers.ReadOnlyField(source='project.project.uuid') jira_project = serializers.HyperlinkedRelatedField( queryset=models.Project.objects.all(), source='project', view_name='jira-projects-detail', lookup_field='uuid', ) jira_project_name = serializers.ReadOnlyField(source='project.name') jira_project_uuid = serializers.ReadOnlyField(source='project.uuid') resource_type = serializers.SerializerMethodField() service_settings_state = serializers.SerializerMethodField() def get_resource_type(self, obj): return 'JIRA.Issue' def get_service_settings_state(self, obj): return 'OK' def get_scope_type(self, obj): if obj.resource: return get_resource_type(obj.resource_content_type.model_class()) class Meta(JiraPropertySerializer.Meta): model = models.Issue fields = JiraPropertySerializer.Meta.fields + ( 'project', 'project_uuid', 'project_name', 'jira_project', 'jira_project_uuid', 'jira_project_name', 'key', 'summary', 'description', 'resolution', 'status', 'priority', 'priority_name', 'priority_icon_url', 'priority_description', 'created', 'updated', 'creator_username', 'creator_name', 'creator_email', 'assignee_username', 'assignee_name', 'assignee_email', 'reporter_username', 'reporter_name', 'reporter_email', 'resolution_date', 'access_url', 'comments', 'resource_type', 'service_settings_state', 'type', 'type_name', 'type_description', 'type_icon_url', 'scope', 'scope_type', 'scope_name', 'parent', 'parent_uuid', 'parent_summary', 'resolution_sla', ) read_only_fields = ( 'status', 'resolution', 'updated_username', 'error_message', 'resolution_sla', 'backend_id', ) protected_fields = ( 'jira_project', 'key', 'type', 'scope', ) extra_kwargs = dict(url={ 'lookup_field': 'uuid', 'view_name': 'jira-issues-detail' }, type={ 'lookup_field': 'uuid', 'view_name': 'jira-issue-types-detail' }, parent={ 'lookup_field': 'uuid', 'view_name': 'jira-issues-detail' }, **JiraPropertySerializer.Meta.extra_kwargs) related_paths = dict(type=('icon_url', 'name', 'description'), parent=('uuid', 'summary'), priority=('icon_url', 'name', 'description'), **JiraPropertySerializer.Meta.related_paths) def create(self, validated_data): project = validated_data['project'] issue_type = validated_data['type'] if issue_type not in project.issue_types.all(): valid_choices = ', '.join( project.issue_types.values_list('name', flat=True)) raise serializers.ValidationError({ 'type': _('Invalid issue type. Please select one of following: %s') % valid_choices }) priority = validated_data['priority'] if priority.settings != project.service_settings: raise serializers.ValidationError({ 'parent': _('Priority should belong to the same JIRA provider.') }) parent_issue = validated_data.get('parent') if parent_issue: if not issue_type.subtask: raise serializers.ValidationError({ 'parent': _('Issue type is not subtask, parent issue is not allowed.' ) }) if parent_issue.project != project: raise serializers.ValidationError({ 'parent': _('Parent issue should belong to the same JIRA project.') }) return super(IssueSerializer, self).create(validated_data)
class ServiceSettingsSerializer( PermissionFieldFilteringMixin, core_serializers.RestrictedSerializerMixin, core_serializers.AugmentedSerializerMixin, serializers.HyperlinkedModelSerializer, ): customer_native_name = serializers.ReadOnlyField(source='customer.native_name') state = MappedChoiceField( choices=[(v, k) for k, v in core_models.StateMixin.States.CHOICES], choice_mappings={v: k for k, v in core_models.StateMixin.States.CHOICES}, read_only=True, ) scope = core_serializers.GenericRelatedField( related_models=models.BaseResource.get_all_models(), required=False, allow_null=True, ) options = serializers.DictField() class Meta: model = models.ServiceSettings fields = ( 'url', 'uuid', 'name', 'type', 'state', 'error_message', 'shared', 'customer', 'customer_name', 'customer_native_name', 'terms_of_services', 'scope', 'options', ) protected_fields = ('type', 'customer') read_only_fields = ('shared', 'state', 'error_message') related_paths = ('customer',) extra_kwargs = { 'url': {'lookup_field': 'uuid'}, 'customer': {'lookup_field': 'uuid'}, } def get_filtered_field_names(self): return ('customer',) @staticmethod def eager_load(queryset, request=None): return queryset.select_related('customer') def get_fields(self): fields = super(ServiceSettingsSerializer, self).get_fields() method = self.context['view'].request.method if method == 'GET' and 'options' in fields: fields['options'] = serializers.SerializerMethodField('get_options') return fields def get_options(self, service): options = { 'backend_url': service.backend_url, 'username': service.username, 'password': service.password, 'domain': service.domain, 'token': service.token, **service.options, } request = self.context['request'] if request.user.is_staff: return options if service.customer and service.customer.has_user( request.user, models.CustomerRole.OWNER ): return options options_serializer_class = get_options_serializer_class(service.type) secret_fields = options_serializer_class.Meta.secret_fields return {k: v for (k, v) in options.items() if k not in secret_fields} def validate(self, attrs): if 'options' not in attrs: return attrs service_type = self.instance and self.instance.type or attrs['type'] options_serializer_class = get_options_serializer_class(service_type) options_serializer = options_serializer_class( instance=self.instance, data=attrs['options'], context=self.context ) options_serializer.is_valid(raise_exception=True) service_options = options_serializer.validated_data attrs.update(service_options) self._validate_settings(models.ServiceSettings(**attrs)) return attrs def _validate_settings(self, service_settings): try: backend = service_settings.get_backend() backend.validate_settings() except ServiceBackendError as e: raise serializers.ValidationError(_('Wrong settings: %s.') % e) except ServiceBackendNotImplemented: pass
def filter_queryset(self, request, queryset, view): search_text = request.query_params.get( settings.api_settings.SEARCH_PARAM, '') must_terms = {} must_not_terms = {} should_terms = {} excluded_event_types = set() if 'event_type' in request.query_params: must_terms['event_type'] = request.query_params.getlist( 'event_type') if 'feature' in request.query_params: features = request.query_params.getlist('feature') must_terms['event_type'] = expand_event_groups(features) # Group events by features in order to prevent large HTTP GET request if 'exclude_features' in request.query_params: features = request.query_params.getlist('exclude_features') excluded_event_types.update(expand_event_groups(features)) if 'exclude_extra' in request.query_params: excluded_event_types.update(expand_event_groups(['update'])) if not django_settings.DEBUG: excluded_event_types.update(expand_event_groups(['debug_only'])) if excluded_event_types: must_not_terms['event_type'] = list(excluded_event_types) if 'user_username' in request.query_params: must_terms['user_username'] = [ request.query_params.get('user_username') ] if 'scope' in request.query_params: field = core_serializers.GenericRelatedField( related_models=utils.get_loggable_models()) field._context = {'request': request} obj = field.to_internal_value(request.query_params['scope']) # XXX: Ilja - disabling this hack and re-opening a ticket. Additional analysis is required for # a proper resolution # # XXX: hack to prevent leaking customer events # permitted_uuids = [uuid.hex for uuids in # obj.get_permitted_objects_uuids(request.user).values() for uuid in uuids] # if obj.uuid.hex not in permitted_uuids: # raise ValidationError('You do not have permission to view events for scope %s' # % request.query_params['scope']) for key, val in obj.filter_by_logged_object().items(): must_terms[format_raw_field(key)] = [val] elif 'scope_type' in request.query_params: choices = utils.get_scope_types_mapping() try: scope_type = choices[request.query_params['scope_type']] except KeyError: raise ValidationError( _('Scope type "%(value)s" is not valid. Has to be one from list: %(items)s.' ) % dict(value=request.query_params['scope_type'], items=', '.join(choices.keys()))) else: permitted_items = scope_type.get_permitted_objects_uuids( request.user).items() if not permitted_items: return EmptyQueryset() for field, uuids in permitted_items: must_terms[field] = [uuid.hex for uuid in uuids] elif 'resource_type' in request.query_params and 'resource_uuid' in request.query_params: # Filter events by resource type and uuid. # Please note, that permission checks are skipped, # because we can't check permission for deleted resources. # Also note, that resource type validation is skipped as well, # because resource type name formatting is defined in structure application, # but we don't want to create circular dependency between logging and structure apps. # This issue could be fixed by switching resource type name formatting to str(model._meta) # as it is done for scope_type parameter validation. must_terms[format_raw_field('resource_type')] = [ request.query_params['resource_type'] ] must_terms[format_raw_field('resource_uuid')] = [ request.query_params['resource_uuid'] ] else: should_terms.update( event_logger.get_permitted_objects_uuids(request.user)) mapped = { 'start': request.query_params.get('from'), 'end': request.query_params.get('to'), } timestamp_interval_serializer = core_serializers.TimestampIntervalSerializer( data={k: v for k, v in mapped.items() if v}) timestamp_interval_serializer.is_valid(raise_exception=True) filter_data = timestamp_interval_serializer.get_filter_data() queryset = queryset.filter(search_text=search_text, should_terms=should_terms, must_terms=must_terms, must_not_terms=must_not_terms, start=filter_data.get('start'), end=filter_data.get('end')) order_by = request.query_params.get('o', '-@timestamp') if order_by: queryset = queryset.order_by(order_by) return queryset