예제 #1
0
class MeSerializer(serializers.HyperlinkedModelSerializer):
    groups = serializers.SlugRelatedField(slug_field='name',
                                          many=True,
                                          queryset=Group.objects.all(),
                                          required=False)

    _links = HALLinksField(
        nested_endpoints=['regen_secret', 'change_password'],
        view_name='users:munchuser-detail')

    class Meta:
        model = MunchUser
        fields = [
            'identifier', 'first_name', 'last_name', 'secret', 'groups',
            'organization', '_links'
        ]
        extra_kwargs = {
            'organization': {
                'view_name': 'users:organization-detail'
            }
        }

    def validate(self, attrs):
        super().validate()
        for field in ('first_name', 'last_name'):
            if field in attrs and attrs[field] == '':
                raise ValidationError(_('{} cannot be empty'.format(field)))
예제 #2
0
class SendingDomainSerializer(serializers.HyperlinkedModelSerializer):
    dkim_status = serializers.ReadOnlyField(allow_null=True)
    app_domain_status = serializers.ReadOnlyField(allow_null=True)
    _links = HALLinksField(nested_endpoints=['revalidate'],
                           view_name='domains:sendingdomain-detail')
    alt_organizations = AltOrganizationsField(
        many=True, view_name='users:organization-detail', required=False)
    organization = serializers.HiddenField(
        default=serializers.CreateOnlyDefault(CurrentOrganizationDefault()))

    class Meta:
        model = SendingDomain
        fields = [
            'url', 'name', 'dkim_status', 'app_domain_status', 'organization',
            'alt_organizations', 'app_domain', 'app_domain_status_date',
            'dkim_status_date', '_links'
        ]
        read_only_fields = [
            'organization', 'dkim_status_date', 'app_domain_status_date'
        ]
        extra_kwargs = {'url': {'view_name': 'domains:sendingdomain-detail'}}

    def validate(self, attrs):
        for organization in attrs.get('alt_organizations', []):
            if organization.parent_id != attrs.get('organization').id:
                raise ValidationError('Invalid organization')
        return attrs
예제 #3
0
class OrganizationSerializer(serializers.HyperlinkedModelSerializer):
    can_attach_files = serializers.ReadOnlyField()
    can_external_optout = serializers.ReadOnlyField()
    name = serializers.CharField(required=True)
    contact_email = serializers.EmailField(required=True)
    settings = OrganizationSettingsSerializer(required=False)
    parent = ScopedHyperLinkedRelatedField(
        required=False,
        allow_null=True,
        view_name='users:organization-detail',
        queryset=Organization.objects.all())
    _links = HALLinksField(
        nested_endpoints=['opt_outs', 'children', 'invite_user'],
        view_name='users:organization-detail')

    class Meta:
        model = Organization
        fields = [
            'url', 'name', 'contact_email', 'settings', 'parent',
            'can_attach_files', 'can_external_optout', '_links'
        ]
        read_only_fields = ['can_attach_files', 'can_external_optout']
        extra_kwargs = {
            'url': {
                'view_name': 'users:organization-detail'
            },
            'parent': {
                'view_name': 'users:organization-detail'
            }
        }

    def validate(self, data):
        if not self.instance and not data.get('parent'):
            raise ValidationError({'parent': 'This field may not be blank.'})
        if self.context.get('request').user.organization != data.get('parent'):
            raise ValidationError(
                {'parent': 'Parent organization must be your organization.'})
        return super().validate(data)

    def create(self, validated_data):
        settings_data = validated_data.pop('settings', {})
        organization = Organization(**validated_data)
        organization.clean()
        organization.save()

        if settings_data:
            for field, value in settings_data.items():
                setattr(organization.settings, field, value)
            organization.settings.save()
        return organization

    def update(self, instance, validated_data):
        settings_data = validated_data.pop('settings', {})
        if settings_data:
            for field, value in settings_data.items():
                setattr(instance.settings, field, value)
            instance.settings.save()
        return super().update(instance, validated_data)
예제 #4
0
class MailBatchSerializer(serializers.HyperlinkedModelSerializer):
    _links = HALLinksField(
        nested_endpoints=['mails', 'stats', 'bounces', 'opt_outs'],
        view_name='transactional:batch-detail')

    class Meta:
        model = MailBatch
        fields = ['url', 'creation_date', 'name', 'category', '_links']
        extra_kwargs = {
            'url': {
                'view_name': 'transactional:batch-detail'
            },
            'category': {
                'view_name': 'core:category-detail'
            }
        }
예제 #5
0
class MunchUserSerializer(serializers.HyperlinkedModelSerializer):
    api_key = serializers.ReadOnlyField(source='secret')
    groups = serializers.SlugRelatedField(slug_field='name',
                                          many=True,
                                          queryset=Group.objects.all(),
                                          required=False)

    _links = HALLinksField(
        nested_endpoints=['regen_secret', 'change_password'],
        view_name='users:munchuser-detail')

    class Meta:
        model = MunchUser
        fields = [
            'url', 'identifier', 'first_name', 'last_name', 'groups',
            'api_key', '_links'
        ]
        extra_kwargs = {'url': {'view_name': 'users:munchuser-detail'}}
예제 #6
0
class MailSerializer(serializers.HyperlinkedModelSerializer):
    last_status = NestedMailStatusSerializer(read_only=True)
    tracking = NestedTrackingSummarySerializer(read_only=True,
                                               source='tracking_info')
    message = CachedScopedHyperLinkedRelatedField(
        view_name='campaigns:message-detail', queryset=Message.objects.all())
    # TODO: Apiv2 rename
    to = serializers.EmailField(source='recipient')
    _links = HALLinksField(nested_endpoints=['optout', 'status_log'],
                           view_name='campaigns:recipient-detail')
    # TODO: Apiv2 rename
    date = serializers.DateTimeField(source='creation_date', read_only=True)
    delivery_status = serializers.CharField(source='curstatus', read_only=True)

    class Meta:
        model = Mail
        fields = [
            'url', 'to', 'date', 'last_status', 'message', 'tracking',
            'delivery_status', 'source_type', 'source_ref', 'properties',
            '_links'
        ]
        read_only_fields = ['date', 'delivery_status']
        list_serializer_class = MailListSerializer
        extra_kwargs = {'url': {'view_name': 'campaigns:recipient-detail'}}

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        extra_fields = ['last_status', 'tracking']

        request = kwargs['context'].get('request')
        if request and request.method == 'GET':
            for field in request.GET.get('extra_fields', '').split(','):
                if field in extra_fields:
                    extra_fields.remove(field)
            for field in extra_fields:
                self.fields.pop(field)

    def validate_message(self, value):
        if value.status in [Message.SENDING, Message.SENT]:
            raise ValidationError(
                _("Cannot add this recipient to a "
                  "sending or already sent message."))
        return value
예제 #7
0
class MailSerializer(serializers.HyperlinkedModelSerializer):
    last_status = MailStatusSerializer(read_only=True)
    tracking = NestedTrackingSummarySerializer(read_only=True,
                                               source='tracking_info')
    _links = HALLinksField(nested_endpoints=['statuses'],
                           view_name='transactional:mail-detail')

    class Meta:
        model = Mail
        fields = [
            'url', 'identifier', 'sender', 'creation_date', 'last_status',
            'tracking', 'batch', 'track_open', 'track_clicks', '_links'
        ]
        extra_kwargs = {
            'url': {
                'view_name': 'transactional:mail-detail'
            },
            'batch': {
                'view_name': 'transactional:batch-detail'
            }
        }
예제 #8
0
class SmtpApplicationSerializer(serializers.HyperlinkedModelSerializer):
    _links = HALLinksField(nested_endpoints=['regen_credentials'],
                           view_name='users:applications-smtp-detail')

    class Meta:
        model = SmtpApplication
        fields = ['url', 'username', 'secret', 'identifier', '_links']
        read_only_fields = ['username', 'secret']
        extra_kwargs = {'url': {'view_name': 'users:applications-smtp-detail'}}

    def validate(self, attrs):
        identifier = attrs.get('identifier')
        try:
            application = SmtpApplication.objects.get(
                author=self.context.get('request').user, identifier=identifier)
        except SmtpApplication.DoesNotExist:
            return attrs
        if self.instance and application.id == self.instance.id:
            return attrs
        else:
            raise ValidationError(
                _('You already own an smtp application with this identifier'))
예제 #9
0
class MessageAttachmentSerializer(serializers.HyperlinkedModelSerializer):
    file = serializers.FileField(validators=[validate_no_virus],
                                 write_only=True)

    _links = HALLinksField(nested_endpoints=['download', 'content'],
                           view_name='campaigns:messageattachment-detail')

    def validate(self, attrs):
        # this is defined as a pre_save because cant be checked in clean() as
        # there is not yet instance.message at this step.
        same_named = attrs['message'].attachments.filter(
            file__endswith='/{}'.format(attrs['file'].name))
        if same_named.exists():
            raise ValidationError(
                ('A file with the same name already exists '
                 'for this message : {}').format(same_named.first()))

        # Now check whether we would fit within the total allowed
        # attachment size for the message
        total_size = 0
        for attachment in attrs['message'].attachments.all():
            total_size += attachment.size
        total_size += attrs['file'].size
        if total_size > settings.CAMPAIGNS['ATTACHMENT_TOTAL_MAX_SIZE']:
            raise ValidationError(
                _('Can not accept this file. Total attachment size for this '
                  'message ({} bytes) would exceed the maximum allowed size of '
                  '{} bytes'.format(
                      total_size,
                      settings.CAMPAIGNS['ATTACHMENT_TOTAL_MAX_SIZE'])))
        return attrs

    def validate_file(self, value):
        # Check this attachment's size to make sure it's not too big
        if value.size > settings.CAMPAIGNS['ATTACHMENT_MAX_SIZE']:
            raise ValidationError(
                _('This file is too big. Maximum allowed size is '
                  '{} bytes'.format(
                      settings.CAMPAIGNS['ATTACHMENT_MAX_SIZE'])))
        if len(value.name) > 100:
            raise ValidationError(
                _('This file name is too long. It must be under 100 characters'
                  ))
        return value

    def create(self, validated_data):
        validated_data.update({'original_name': validated_data['file'].name})
        return super().create(validated_data)

    class Meta:
        model = MessageAttachment
        fields = ('url', 'message', 'file', 'filename', 'size', 'size_in_mail',
                  '_links')
        readonly_fields = ('filename', 'size', 'size_in_mail')
        extra_kwargs = {
            'url': {
                'view_name': 'campaigns:messageattachment-detail'
            },
            'message': {
                'view_name': 'campaigns:message-detail'
            }
        }
예제 #10
0
class MessageSerializer(ForwardValidationErrorsMixin,
                        serializers.HyperlinkedModelSerializer):
    completion_date = serializers.ReadOnlyField()
    creation_date = serializers.ReadOnlyField()
    msg_issue = serializers.ReadOnlyField()
    is_spam = serializers.ReadOnlyField()
    spam_score = serializers.ReadOnlyField()
    recipient_count = serializers.ReadOnlyField(source='mails.count')
    category = ScopedHyperLinkedRelatedField(view_name='core:category-detail',
                                             queryset=Category.objects.all(),
                                             required=False,
                                             allow_null=True)

    _links = HALLinksField(nested_endpoints=[
        'preview_send', 'preview', 'preview.html', 'preview.txt', 'recipients',
        'bounces', 'opt_outs', 'stats', 'attachments'
    ],
                           endpoints={
                               'archive_url': {
                                   'view_name': 'message_web_view',
                                   'lookup_field': 'identifier',
                                   'lookup_key': 'identifier'
                               }
                           },
                           view_name='campaigns:message-detail')

    def validate(self, attrs):
        """
        http://www.django-rest-framework.org/topics/3.0-announcement/#differences-between-modelserializer-validation-and-modelform
        """
        request = self.context.get('request', None)
        # Re-use model validation logic
        instance = Message(author=request.user, **attrs)
        try:
            instance.clean()
            if 'html' in attrs:
                instance.validate_html()
        except DjangoValidationError as err:
            message = {}
            for field, errors in err.message_dict.items():
                if not isinstance(errors, list):
                    errors = [errors]
                message[field] = errors
            raise ValidationError(message)
        return attrs

    class Meta:
        model = Message
        read_only_fields = ['send_date']
        fields = (
            'url',
            'id',
            'name',
            'sender_email',
            'sender_name',
            'subject',
            'html',
            'status',
            'category',
            'recipient_count',
            'properties',
            'creation_date',
            'send_date',
            'completion_date',
            'track_open',
            'track_clicks',
            'external_optout',
            'detach_images',
            'spam_score',
            'spam_details',
            'is_spam',
            'msg_issue',
            '_links',
        )
        extra_kwargs = {'url': {'view_name': 'campaigns:message-detail'}}