class AdminLevelSerializer(RemoveNullFieldsMixin, DynamicFieldsMixin, serializers.ModelSerializer): """ Admin Level Model Serializer """ geo_shape_file_details = SimpleFileSerializer(source='geo_shape_file', read_only=True) geojson_file = URLCachedFileField(required=False, read_only=True) bounds_file = URLCachedFileField(required=False, read_only=True) class Meta: model = AdminLevel exclude = ('geo_area_titles', ) # Validations def validate_region(self, region): if not region.can_modify(self.context['request'].user): raise serializers.ValidationError('Invalid region') return region def create(self, validated_data): admin_level = super().create(validated_data) admin_level.stale_geo_areas = True admin_level.save() region = admin_level.region region.modified_by = self.context['request'].user region.save() if not settings.TESTING: transaction.on_commit(lambda: load_geo_areas.delay(region.id)) return admin_level def update(self, instance, validated_data): admin_level = super().update( instance, validated_data, ) admin_level.stale_geo_areas = True admin_level.save() region = admin_level.region region.modified_by = self.context['request'].user region.save() if not settings.TESTING: transaction.on_commit(lambda: load_geo_areas.delay(region.id)) return admin_level
class SimpleOrganizationSerializer(serializers.ModelSerializer): logo = URLCachedFileField(source='logo.file', read_only=True) merged_as = MergedAsOrganizationSerializer(source='parent', read_only=True) class Meta: model = Organization fields = ('id', 'title', 'short_name', 'merged_as', 'logo')
class SimpleFileSerializer(RemoveNullFieldsMixin, serializers.ModelSerializer): title = serializers.CharField(required=False, read_only=True) file = URLCachedFileField(required=False, read_only=True) mime_type = serializers.CharField(required=False, read_only=True) class Meta: model = File fields = ('id', 'title', 'file', 'mime_type') read_only_fields = FILE_READONLY_FIELDS
class ArySourceOrganizationSerializer(DynamicFieldsMixin, UserResourceSerializer): logo = URLCachedFileField(source='logo.file', allow_null=True) key = serializers.IntegerField(source='pk') merged_as = MergedAsOrganizationSerializer(source='parent', read_only=True) class Meta: model = Organization fields = ('key', 'title', 'long_name', 'short_name', 'logo', 'organization_type', 'merged_as')
class LeadPreviewImageSerializer(RemoveNullFieldsMixin, DynamicFieldsMixin, serializers.ModelSerializer): """ Serializer for lead preview image """ file = URLCachedFileField(read_only=True) class Meta: model = LeadPreviewImage fields = ('id', 'file',)
def batch_load_fn(self, keys): display_picture_qs = User.objects.filter(pk__in=keys).values_list( 'id', 'profile__display_picture__file') # Membership map display_picture_map = {} for user_id, display_picture in display_picture_qs: if display_picture: display_picture_map[ user_id] = self.context.request.build_absolute_uri( URLCachedFileField.name_to_representation( display_picture)) return Promise.resolve([display_picture_map.get(key) for key in keys])
def _get_viz_data(request, project, can_view_confidential, token=None): """ Util function to trigger and serve Project entry/ary viz data """ if ( project.analysis_framework is None or project.analysis_framework.properties is None or project.analysis_framework.properties.get('stats_config') is None ): return { 'error': f'No configuration provided for current Project: {project.title}, Contact Admin', }, status.HTTP_404_NOT_FOUND stats, created = ProjectStats.objects.get_or_create(project=project) if token and ( not stats.public_share or token != str(stats.token) ): return { 'error': 'Token is invalid or sharing is disabled. Please contact project\'s admin.' }, status.HTTP_403_FORBIDDEN stat_file = stats.confidential_file if can_view_confidential else stats.file file_url = ( request.build_absolute_uri(URLCachedFileField().to_representation(stat_file)) if stat_file else None ) stats_meta = { 'data': file_url, 'modified_at': stats.modified_at, 'status': stats.status, 'public_share': stats.public_share, 'public_url': stats.get_public_url(request), } if stats.is_ready(): return stats_meta, status.HTTP_200_OK elif stats.status == ProjectStats.Status.FAILURE: return { 'error': 'Failed to generate stats, Contact Admin', **stats_meta, }, status.HTTP_200_OK transaction.on_commit(lambda: generate_viz_stats.delay(project.pk)) # NOTE: Not changing modified_at if already pending if stats.status != ProjectStats.Status.PENDING: stats.status = ProjectStats.Status.PENDING stats.save() return { 'message': 'Processing the request, try again later', **stats_meta, }, status.HTTP_202_ACCEPTED
class UserPreferencesSerializer(RemoveNullFieldsMixin, serializers.ModelSerializer): display_picture = serializers.PrimaryKeyRelatedField( source='profile.display_picture', queryset=File.objects.all(), allow_null=True, required=False, ) display_picture_url = URLCachedFileField( source='profile.display_picture.file', read_only=True, ) display_name = serializers.CharField( source='profile.get_display_name', read_only=True, ) last_active_project = serializers.PrimaryKeyRelatedField( source='profile.last_active_project', queryset=Project.objects.all(), allow_null=True, required=False, ) language = serializers.CharField(source='profile.language', read_only=True) fallback_language = serializers.CharField( source='profile.get_fallback_language', read_only=True, ) accessible_features = FeatureSerializer( source='profile.get_accessible_features', many=True, read_only=True, ) class Meta: model = User fields = ( 'display_name', 'username', 'email', 'last_active_project', 'display_picture', 'display_picture_url', 'is_superuser', 'language', 'accessible_features', 'fallback_language', )
class EntryCommentUserSerializer(serializers.ModelSerializer): name = serializers.CharField(source='profile.get_display_name', read_only=True) display_picture_url = URLCachedFileField( source='profile.display_picture.file', read_only=True, ) organization = serializers.CharField(source='profile.organization', read_only=True) class Meta: model = User fields = ( 'id', 'name', 'email', 'organization', 'display_picture_url', )
class SimpleUserSerializer(RemoveNullFieldsMixin, serializers.ModelSerializer): display_name = serializers.CharField( source='profile.get_display_name', read_only=True, ) display_picture = serializers.PrimaryKeyRelatedField( source='profile.display_picture', read_only=True, ) display_picture_url = URLCachedFileField( source='profile.display_picture.file', read_only=True, ) organization_title = serializers.CharField(source='profile.organization', read_only=True) class Meta: model = User fields = ('id', 'display_name', 'email', 'display_picture', 'display_picture_url', 'organization_title')
class OrganizationSerializer( DynamicFieldsMixin, RemoveNullFieldsMixin, UserResourceSerializer, ): organization_type_display = OrganizationTypeSerializer( source='organization_type', read_only=True, ) regions_display = SimpleRegionSerializer( source='regions', read_only=True, many=True, ) logo_url = URLCachedFileField(source='logo.file', allow_null=True, required=False) merged_as = MergedAsOrganizationSerializer(source='parent', read_only=True) client_id = None class Meta: model = Organization exclude = ('parent',) read_only_fields = ('verified', 'logo_url',) def create(self, validated_data): organization = super().create(validated_data) organization.created_by = organization.modified_by = self.context['request'].user return organization
class FileSerializer(RemoveNullFieldsMixin, DynamicFieldsMixin, UserResourceSerializer): file = URLCachedFileField(required=True, read_only=False) class Meta: model = File fields = ('__all__') read_only_fields = FILE_READONLY_FIELDS # Validations def validate_file(self, file): extension = os.path.splitext(file.name)[1][1:] if file.content_type not in deep_doc_types.DEEP_SUPPORTED_MIME_TYPES\ and extension not in deep_doc_types.DEEP_SUPPORTED_EXTENSIONS: raise serializers.ValidationError( 'Unsupported file type {}'.format(file.content_type)) return file def _get_metadata(self, file): metadata = {'md5_hash': calculate_md5(file.file)} mime_type = file.content_type if mime_type in deep_doc_types.PDF_MIME_TYPES: metadata.update({ 'pages': get_pages_in_pdf(file.file), }) elif mime_type in deep_doc_types.DOCX_MIME_TYPES: metadata.update({ 'pages': get_pages_in_docx(file.file), }) return metadata def create(self, validated_data): validated_data['mime_type'] = validated_data.get('file').content_type try: validated_data['metadata'] = self._get_metadata( validated_data.get('file')) except Exception: logger.error('File create Failed!!', exc_info=True) return super().create(validated_data)
class MergedAsOrganizationSerializer(serializers.ModelSerializer): logo = URLCachedFileField(source='logo.file', read_only=True) class Meta: model = Organization fields = ('id', 'title', 'logo')
class LeadSerializer( RemoveNullFieldsMixin, DynamicFieldsMixin, WriteOnlyOnCreateSerializerMixin, UserResourceSerializer, ): """ Lead Model Serializer """ # annotated in lead.get_for entries_count = serializers.IntegerField(read_only=True) controlled_entries_count = serializers.IntegerField(read_only=True) filtered_entries_count = serializers.IntegerField(read_only=True) controlled_filtered_entries_count = serializers.IntegerField(read_only=True) assessment_id = serializers.IntegerField(read_only=True) priority_display = serializers.CharField(source='get_priority_display', read_only=True) attachment = SimpleFileSerializer(required=False) thumbnail = URLCachedFileField( source='leadpreview.thumbnail', read_only=True, ) thumbnail_height = serializers.IntegerField( source='leadpreview.thumbnail_height', read_only=True, ) thumbnail_width = serializers.IntegerField( source='leadpreview.thumbnail_width', read_only=True, ) word_count = serializers.IntegerField( source='leadpreview.word_count', read_only=True, ) page_count = serializers.IntegerField( source='leadpreview.page_count', read_only=True, ) classified_doc_id = serializers.IntegerField( source='leadpreview.classified_doc_id', read_only=True, ) # TODO: Remove (Legacy) author_detail = SimpleOrganizationSerializer(source='author', read_only=True) authors_detail = SimpleOrganizationSerializer(source='authors', many=True, read_only=True) source_detail = SimpleOrganizationSerializer(source='source', read_only=True) assignee_details = SimpleUserSerializer( source='get_assignee', # many=True, read_only=True, ) assignee = SingleValueThayMayBeListField( source='get_assignee.id', required=False, ) tabular_book = serializers.SerializerMethodField() emm_triggers = LeadEMMTriggerSerializer(many=True, required=False) emm_entities = EMMEntitySerializer(many=True, required=False) # extra fields added from entryleadserializer confidentiality_display = serializers.CharField(source='get_confidentiality_display', read_only=True) class Meta: model = Lead fields = ('__all__') # Legacy Fields read_only_fields = ('author_raw', 'source_raw') write_only_on_create_fields = ['emm_triggers', 'emm_entities'] def get_tabular_book(self, obj): file = obj.attachment if file and hasattr(file, 'book'): return file.book.id return None @staticmethod def add_update__validate(data, instance, attachment=None): project = data.get('project', instance and instance.project) source_type = data.get('source_type', instance and instance.source_type) text = data.get('text', instance and instance.text) url = data.get('url', instance and instance.url) return raise_or_return_existing_lead( project, instance, source_type, url, text, attachment, ) def validate_is_assessment_lead(self, value): # Allow setting True # For False make sure there are no assessment attached. if value is False and hasattr(self.instance, 'assessment'): raise serializers.ValidationError('Lead already has an assessment.') return value def validate(self, data): attachment_id = self.get_initial().get('attachment', {}).get('id') LeadSerializer.add_update__validate( data, self.instance, File.objects.filter(pk=attachment_id).first() ) return data # TODO: Probably also validate assignee to valid list of users def create(self, validated_data): assignee_field = validated_data.pop('get_assignee', None) assignee_id = assignee_field and assignee_field.get('id', None) assignee = assignee_id and get_object_or_404(User, id=assignee_id) emm_triggers = validated_data.pop('emm_triggers', []) emm_entities_names = [ entity['name'] for entity in validated_data.pop('emm_entities', []) if isinstance(entity, dict) and 'name' in entity ] lead = super().create(validated_data) for entity in EMMEntity.objects.filter(name__in=emm_entities_names): lead.emm_entities.add(entity) lead.save() with transaction.atomic(): for trigger in emm_triggers: LeadEMMTrigger.objects.create(**trigger, lead=lead) if assignee: lead.assignee.add(assignee) return lead def update(self, instance, validated_data): assignee_field = validated_data.pop('get_assignee', None) assignee_id = assignee_field and assignee_field.get('id', None) assignee = assignee_id and get_object_or_404(User, id=assignee_id) # We do not update triggers and entities validated_data.pop('emm_entities', None) validated_data.pop('emm_triggers', None) lead = super().update(instance, validated_data) if assignee_field: lead.assignee.clear() if assignee: lead.assignee.add(assignee) return lead
def resolve_url(root, info, **kwargs) -> Union[str, None]: return info.context.request.build_absolute_uri( URLCachedFileField.name_to_representation(root))
def resolve_data_url(root, info, **_): url = root.file if PP.check_permission(info, PP.Permission.VIEW_ALL_LEAD): url = root.confidential_file return url and info.context.request.build_absolute_uri( URLCachedFileField.name_to_representation(url))
class UserSerializer(RemoveNullFieldsMixin, WriteOnlyOnCreateSerializerMixin, DynamicFieldsMixin, serializers.ModelSerializer): organization = serializers.CharField(source='profile.organization', allow_blank=True) language = serializers.CharField( source='profile.language', allow_null=True, required=False, ) display_picture = serializers.PrimaryKeyRelatedField( source='profile.display_picture', queryset=File.objects.all(), allow_null=True, required=False, ) display_picture_url = URLCachedFileField( source='profile.display_picture.file', read_only=True, ) display_name = serializers.CharField( source='profile.get_display_name', read_only=True, ) last_active_project = serializers.PrimaryKeyRelatedField( source='profile.last_active_project', queryset=Project.objects.all(), allow_null=True, required=False, ) email_opt_outs = serializers.ListField( source='profile.email_opt_outs', required=False, ) login_attempts = serializers.IntegerField( source='profile.login_attempts', read_only=True, ) hcaptcha_response = serializers.CharField(write_only=True) class Meta: model = User fields = ('id', 'username', 'first_name', 'last_name', 'display_name', 'last_active_project', 'login_attempts', 'hcaptcha_response', 'email', 'organization', 'display_picture', 'display_picture_url', 'language', 'email_opt_outs') write_only_on_create_fields = ('email', 'username') @classmethod def update_or_create_profile(cls, user, profile_data): profile, created = Profile.objects.update_or_create( user=user, defaults=profile_data) return profile def validate_hcaptcha_response(self, captcha): validate_hcaptcha(captcha) def validate_last_active_project(self, project): if project and not project.is_member(self.context['request'].user): raise serializers.ValidationError('Invalid project') return project def create(self, validated_data): profile_data = validated_data.pop('profile', None) validated_data.pop('hcaptcha_response', None) validated_data['email'] = validated_data['username'] = ( validated_data['email'] or validated_data['email']).lower() user = super().create(validated_data) user.save() user.profile = self.update_or_create_profile(user, profile_data) send_password_reset(user=user, welcome=True) return user def update(self, instance, validated_data): profile_data = validated_data.pop('profile', None) user = super().update(instance, validated_data) if 'password' in validated_data: user.set_password(validated_data['password']) user.save() user.profile = self.update_or_create_profile(user, profile_data) return user