Esempio n. 1
0
    def test_upload_to(self):
        """
        Ensure that the field cannot be initialized with a callable `upload_to`
        as this will break the filename-generation template logic.
        """
        def dummy_upload_to(instance, filename):  # pylint: disable=missing-docstring, unused-argument
            return 'foo'

        with self.assertRaises(Exception) as exc_context:
            self.field = ResizingImageField('testing/{attr}/path',
                                            TEST_SIZES,
                                            upload_to=dummy_upload_to)

        self.assertEquals(
            exc_context.exception.message,
            'ResizingImageField does not support passing a custom callable for the `upload_to` keyword arg.',
        )
Esempio n. 2
0
class ProgramDefault(SingletonModel):
    """
    Model used to store default program configuration.
    This includes a default, resizable banner image which is
    used if a given program has not specified its own banner image.
    This model is a singleton - only one instance exists.
    """
    banner_image = ResizingImageField(
        path_template='program/banner/default',
        sizes=RESIZABLE_IMAGE_SIZES,
        null=True,
        blank=True,
        max_length=1000,
    )
Esempio n. 3
0
    def test_upload_to(self):
        """
        Ensure that the field cannot be initialized with a callable `upload_to`
        as this will break the filename-generation template logic.
        """
        def dummy_upload_to(instance, filename):  # pylint: disable=missing-docstring, unused-argument
            return 'foo'

        with self.assertRaises(Exception) as exc_context:
            self.field = ResizingImageField('testing/{attr}/path', TEST_SIZES, upload_to=dummy_upload_to)

        self.assertEquals(
            exc_context.exception.message,
            'ResizingImageField does not support passing a custom callable for the `upload_to` keyword arg.',
        )
Esempio n. 4
0
class Program(TimeStampedModel):
    """
    Representation of a Program.
    """

    uuid = models.UUIDField(
        blank=True,
        default=uuid4,
        editable=False,
        unique=True,
    )

    name = models.CharField(
        help_text=_('The user-facing display name for this Program.'),
        max_length=255,
        unique=True,
    )

    subtitle = models.CharField(
        help_text=_('A brief, descriptive subtitle for the Program.'),
        max_length=255,
        blank=True,
    )

    category = models.CharField(
        help_text=_('The category / type of Program.'),
        max_length=32,
        choices=_choices(constants.ProgramCategory.XSERIES),
    )

    status = models.CharField(
        help_text=_('The lifecycle status of this Program.'),
        max_length=24,
        choices=_choices(
            constants.ProgramStatus.UNPUBLISHED,
            constants.ProgramStatus.ACTIVE,
            constants.ProgramStatus.RETIRED,
            constants.ProgramStatus.DELETED,
        ),
        default=constants.ProgramStatus.UNPUBLISHED,
        # though this field is not nullable, setting blank=True ensures validators
        # will reject the empty string, instead of implicitly replacing it with the
        # default value.  This is consistent with how None/null is handled.
        blank=True,
    )

    marketing_slug = models.CharField(
        help_text=_('Slug used to generate links to the marketing site'),
        blank=True,
        max_length=255)

    banner_image = ResizingImageField(
        path_template='program/banner/{uuid}',
        sizes=RESIZABLE_IMAGE_SIZES,
        null=True,
        blank=True,
        max_length=1000,
    )

    def save(self, *a, **kw):
        """
        Verify that the marketing slug is not empty if the user has attempted
        to activate an XSeries.
        """
        if self.category == constants.ProgramCategory.XSERIES and self.status == constants.ProgramStatus.ACTIVE:
            if not self.marketing_slug:
                raise ValidationError(
                    _("Active XSeries Programs must have a valid marketing slug."
                      ))

        return super(Program, self).save(*a, **kw)

    class Meta(object):  # pylint: disable=missing-docstring
        index_together = ('status', 'category')

    def __unicode__(self):
        return unicode(self.name)
Esempio n. 5
0
 def setUp(self):
     super(ResizingImageFieldTestCase, self).setUp()
     self.model_instance = mock.Mock(attr='test-attr')
     self.field = ResizingImageField('testing/{attr}/path', TEST_SIZES)
Esempio n. 6
0
class ResizingImageFieldTestCase(TestCase):
    """
    Test the behavior of the definition of our custom field in the context of a
    model instance.
    """
    def setUp(self):
        super(ResizingImageFieldTestCase, self).setUp()
        self.model_instance = mock.Mock(attr='test-attr')
        self.field = ResizingImageField('testing/{attr}/path', TEST_SIZES)

    def test_generate_filename(self):
        """
        Ensure that the path_template is used to generate filenames correctly.
        """
        self.assertEqual(
            self.field.generate_filename(self.model_instance, 'test-filename'),
            'testing/test-attr/path/test-filename'
        )

    @mock.patch(PATCH_MODULE + '.validate_image_type')
    @mock.patch(PATCH_MODULE + '.validate_image_size')
    @ddt.data(
        (None, False),
        ('test-filename', False),
        ('test-filename', True),
    )
    @ddt.unpack
    def test_pre_save(self, filename, is_existing_file, mock_validate_size, mock_validate_type):
        """
        Ensure that image validation and resizing take place only when a new
        file is being stored.
        """
        # pylint: disable=too-many-function-args

        field_value = ResizingImageFieldFile(self.model_instance, self.field, filename)
        self.model_instance.resized_image = field_value
        self.field.attname = 'resized_image'
        self.field.name = 'resized_image'

        with mock.patch(PATCH_MODULE + '.ResizingImageFieldFile.create_resized_copies') as mock_resize:
            # actual file data is needed for this test to work
            with make_uploaded_file('image/jpeg', (1000, 1000)) as image_file:
                if filename:
                    field_value.file = image_file
                    field_value._committed = is_existing_file  # pylint: disable=protected-access
                self.field.pre_save(self.model_instance, False)

        expected_called = bool(filename) and not is_existing_file
        for actual_called in (mock_validate_size.called, mock_validate_type.called, mock_resize.called):
            self.assertEqual(actual_called, expected_called)

    def test_upload_to(self):
        """
        Ensure that the field cannot be initialized with a callable `upload_to`
        as this will break the filename-generation template logic.
        """
        def dummy_upload_to(instance, filename):  # pylint: disable=missing-docstring, unused-argument
            return 'foo'

        with self.assertRaises(Exception) as exc_context:
            self.field = ResizingImageField('testing/{attr}/path', TEST_SIZES, upload_to=dummy_upload_to)

        self.assertEquals(
            exc_context.exception.message,
            'ResizingImageField does not support passing a custom callable for the `upload_to` keyword arg.',
        )
Esempio n. 7
0
 def setUp(self):
     super(ResizingImageFieldFileTestCase, self).setUp()
     self.model_instance = mock.Mock()
     self.field = ResizingImageField('test-path', TEST_SIZES)
Esempio n. 8
0
 def setUp(self):
     super(ResizingImageFieldTestCase, self).setUp()
     self.model_instance = mock.Mock(attr='test-attr')
     self.field = ResizingImageField('testing/{attr}/path', TEST_SIZES)
Esempio n. 9
0
class ResizingImageFieldTestCase(TestCase):
    """
    Test the behavior of the definition of our custom field in the context of a
    model instance.
    """
    def setUp(self):
        super(ResizingImageFieldTestCase, self).setUp()
        self.model_instance = mock.Mock(attr='test-attr')
        self.field = ResizingImageField('testing/{attr}/path', TEST_SIZES)

    def test_generate_filename(self):
        """
        Ensure that the path_template is used to generate filenames correctly.
        """
        self.assertEqual(
            self.field.generate_filename(self.model_instance, 'test-filename'),
            'testing/test-attr/path/test-filename')

    @mock.patch(PATCH_MODULE + '.validate_image_type')
    @mock.patch(PATCH_MODULE + '.validate_image_size')
    @ddt.data(
        (None, False),
        ('test-filename', False),
        ('test-filename', True),
    )
    @ddt.unpack
    def test_pre_save(self, filename, is_existing_file, mock_validate_size,
                      mock_validate_type):
        """
        Ensure that image validation and resizing take place only when a new
        file is being stored.
        """
        # pylint: disable=too-many-function-args

        field_value = ResizingImageFieldFile(self.model_instance, self.field,
                                             filename)
        self.model_instance.resized_image = field_value
        self.field.attname = 'resized_image'
        self.field.name = 'resized_image'

        with mock.patch(PATCH_MODULE +
                        '.ResizingImageFieldFile.create_resized_copies'
                        ) as mock_resize:
            # actual file data is needed for this test to work
            with make_uploaded_file('image/jpeg', (1000, 1000)) as image_file:
                if filename:
                    field_value.file = image_file
                    field_value._committed = is_existing_file  # pylint: disable=protected-access
                self.field.pre_save(self.model_instance, False)

        expected_called = bool(filename) and not is_existing_file
        for actual_called in (mock_validate_size.called,
                              mock_validate_type.called, mock_resize.called):
            self.assertEqual(actual_called, expected_called)

    def test_upload_to(self):
        """
        Ensure that the field cannot be initialized with a callable `upload_to`
        as this will break the filename-generation template logic.
        """
        def dummy_upload_to(instance, filename):  # pylint: disable=missing-docstring, unused-argument
            return 'foo'

        with self.assertRaises(Exception) as exc_context:
            self.field = ResizingImageField('testing/{attr}/path',
                                            TEST_SIZES,
                                            upload_to=dummy_upload_to)

        self.assertEquals(
            exc_context.exception.message,
            'ResizingImageField does not support passing a custom callable for the `upload_to` keyword arg.',
        )