예제 #1
0
    def test_delete(self, usernames, side_effects, mock_logger, mock_remove_profile_images):
        """
        Test that remove_profile_images is called with the expected list
        of profile image filenames for all users.
        Also test that exceptions are ignored and logged.
        """
        if side_effects:
            mock_remove_profile_images.side_effect = side_effects

        delete_profile_images.delay(usernames)

        expected_names = []
        for username in usernames:
            expected_names += get_profile_image_names(username).values()

        # flatten the list of called arguments
        deleted_names = []
        called_args = [v[0][0].values() for v in mock_remove_profile_images.call_args_list]
        for args in called_args:
            deleted_names.extend(args)

        self.assertSetEqual(set(expected_names), set(deleted_names))

        if side_effects and [exc for exc in side_effects.values() if isinstance(exc, Exception)]:
            mock_logger.exception.assert_called()
예제 #2
0
 def create_profile_image(self, user, storage):
     """
     Creates profile image for user and checks that created image exists in storage
     """
     with make_image_file() as image_file:
         create_profile_images(image_file, get_profile_image_names(user.username))
         self.check_images(user, storage)
         set_has_profile_image(user.username, True, self.TEST_PROFILE_IMAGE_UPLOADED_AT)
예제 #3
0
 def setUp(self):
     super(ProfileImageViewDeleteTestCase, self).setUp()
     with make_image_file() as image_file:
         create_profile_images(image_file, get_profile_image_names(self.user.username))
         self.check_images()
         set_has_profile_image(self.user.username, True, TEST_UPLOAD_DT)
         # Ignore previous event
         self.reset_tracker()
예제 #4
0
 def test_remove_self(self, mock_log):
     """
     Test that an authenticated user can DELETE to remove their own profile
     images.
     """
     response = self.client.delete(self.url)
     self.check_response(response, 204)
     self.check_images(False)
     self.check_has_profile_image(False)
     mock_log.info.assert_called_once_with(
         LOG_MESSAGE_DELETE,
         {'image_names': get_profile_image_names(self.user.username).values(), 'user_id': self.user.id}
     )
     self.check_remove_event_emitted()
예제 #5
0
    def check_images(self, user, storage, exist=True):
        """
        If exist is True, make sure the images physically exist in storage
        with correct sizes and formats.

        If exist is False, make sure none of the images exist.
        """
        for size, name in get_profile_image_names(user.username).items():
            if exist:
                self.assertTrue(storage.exists(name))
                with closing(Image.open(storage.path(name))) as img:
                    self.assertEqual(img.size, (size, size))
                    self.assertEqual(img.format, 'JPEG')  # pylint: disable=no-member
            else:
                self.assertFalse(storage.exists(name))
예제 #6
0
    def post(self, request, username):
        """
        POST /api/user/v1/accounts/{username}/image
        """

        # validate request:
        # verify that the user's
        # ensure any file was sent
        if 'file' not in request.FILES:
            return Response(
                {
                    "developer_message": u"No file provided for profile image",
                    "user_message": _(u"No file provided for profile image"),

                },
                status=status.HTTP_400_BAD_REQUEST
            )

        # process the upload.
        uploaded_file = request.FILES['file']

        # no matter what happens, delete the temporary file when we're done
        with closing(uploaded_file):

            # image file validation.
            try:
                validate_uploaded_image(uploaded_file)
            except ImageValidationError as error:
                return Response(
                    {"developer_message": text_type(error), "user_message": error.user_message},
                    status=status.HTTP_400_BAD_REQUEST,
                )

            # generate profile pic and thumbnails and store them
            profile_image_names = get_profile_image_names(username)
            create_profile_images(uploaded_file, profile_image_names)

            # update the user account to reflect that a profile image is available.
            set_has_profile_image(username, True, _make_upload_dt())

            log.info(
                LOG_MESSAGE_CREATE,
                {'image_names': profile_image_names.values(), 'user_id': request.user.id}
            )

        # send client response.
        return Response(status=status.HTTP_204_NO_CONTENT)
예제 #7
0
 def test_remove_staff(self, mock_log):
     """
     Test that an authenticated staff user can DELETE to remove another user's
     profile images.
     """
     staff_user = UserFactory(is_staff=True, password=TEST_PASSWORD)
     staff_client = APIClient()
     staff_client.login(username=staff_user.username, password=TEST_PASSWORD)
     response = self.client.delete(self.url)
     self.check_response(response, 204)
     self.check_images(False)
     self.check_has_profile_image(False)
     mock_log.info.assert_called_once_with(
         LOG_MESSAGE_DELETE,
         {'image_names': get_profile_image_names(self.user.username).values(), 'user_id': self.user.id}
     )
     self.check_remove_event_emitted()
예제 #8
0
 def test_upload_by_mimetype(self, content_type, extension, _mock_make_image_version, mock_log):
     """
     Test that a user can upload raw content with the appropriate mimetype
     """
     with make_image_file(extension=extension) as image_file:
         data = image_file.read()
         response = self.client.post(
             self.url,
             data,
             content_type=content_type,
             HTTP_CONTENT_DISPOSITION='attachment;filename=filename{}'.format(extension),
         )
         self.check_response(response, 204)
         self.check_images()
         self.check_has_profile_image()
     mock_log.info.assert_called_once_with(
         LOG_MESSAGE_CREATE,
         {'image_names': get_profile_image_names(self.user.username).values(), 'user_id': self.user.id}
     )
     self.check_upload_event_emitted()
예제 #9
0
파일: views.py 프로젝트: JudyFox/edXMOOC
    def post(self, request, username):  # pylint: disable=unused-argument
        """
        POST /api/profile_images/v1/{username}/remove
        """
        try:
            # update the user account to reflect that the images were removed.
            set_has_profile_image(username, False)

            # remove physical files from storage.
            profile_image_names = get_profile_image_names(username)
            remove_profile_images(profile_image_names)

            log.info(
                LOG_MESSAGE_DELETE,
                {'image_names': profile_image_names.values(), 'user_id': request.user.id}
            )
        except UserNotFound:
            return Response(status=status.HTTP_404_NOT_FOUND)

        # send client response.
        return Response(status=status.HTTP_204_NO_CONTENT)
예제 #10
0
    def test_upload_self(self, extension, _mock_make_image_version, mock_log):
        """
        Test that an authenticated user can POST to their own upload endpoint.
        """
        with make_image_file(extension=extension) as image_file:
            response = self.client.post(self.url, {'file': image_file}, format='multipart')
            self.check_response(response, 204)
            self.check_images()
            self.check_has_profile_image()
        mock_log.info.assert_called_once_with(
            LOG_MESSAGE_CREATE,
            {'image_names': get_profile_image_names(self.user.username).values(), 'user_id': self.user.id}
        )
        self.check_upload_event_emitted()

        # Try another upload and make sure that a second event is emitted.
        with make_image_file() as image_file:
            response = self.client.post(self.url, {'file': image_file}, format='multipart')
            self.check_response(response, 204)

        self.check_upload_event_emitted(old=TEST_UPLOAD_DT, new=TEST_UPLOAD_DT2)
예제 #11
0
    def delete(self, request, username):
        """
        DELETE /api/user/v1/accounts/{username}/image
        """

        try:
            # update the user account to reflect that the images were removed.
            set_has_profile_image(username, False)

            # remove physical files from storage.
            profile_image_names = get_profile_image_names(username)
            remove_profile_images(profile_image_names)

            log.info(
                LOG_MESSAGE_DELETE,
                {'image_names': list(profile_image_names.values()), 'user_id': request.user.id}
            )
        except UserNotFound:
            return Response(status=status.HTTP_404_NOT_FOUND)

        # send client response.
        return Response(status=status.HTTP_204_NO_CONTENT)
예제 #12
0
파일: views.py 프로젝트: mreyk/edx-platform
 def delete_users_profile_images(user):
     set_has_profile_image(user.username, False)
     names_of_profile_images = get_profile_image_names(user.username)
     remove_profile_images(names_of_profile_images)
예제 #13
0
 def tearDown(self):
     super(ProfileImageEndpointMixin, self).tearDown()
     for name in get_profile_image_names(self.user.username).values():
         self.storage.delete(name)
예제 #14
0
 def delete_users_profile_images(user):
     set_has_profile_image(user.username, False)
     names_of_profile_images = get_profile_image_names(user.username)
     remove_profile_images(names_of_profile_images)
    def handle(self, *args, **options):
        if not options.get('aws_access_key'):
            raise CommandError(
                "migrate_profile_images command requires AWS access key in --aws-access-key"
            )

        if not options.get('aws_access_secret'):
            raise CommandError(
                "migrate_profile_images command requires AWS access secret in --aws-access-secret"
            )

        if not options.get('bucket_name'):
            raise CommandError(
                "migrate_profile_images command requires name of source s3 bucket in --bucket-name"
            )

        aws_access_key = options.get('aws_access_key')
        aws_access_secret = options.get('aws_access_secret')
        bucket_name = options.get('bucket_name')

        try:
            log.info("Starting Migration of Profile Images from %s",
                     bucket_name)
            bucket = Command.get_bucket_connection(aws_access_key,
                                                   aws_access_secret,
                                                   bucket_name)
            for user in User.objects.exclude(
                    profile__avatar_url__isnull=True).exclude(
                        profile__avatar_url__exact=''):
                try:
                    image_key = (
                        user.profile.avatar_url.split('/')[-2]) + '/' + (
                            user.profile.avatar_url.split('/')[-1])
                    image_url = Command.get_file_url(bucket, image_key)
                except IndexError:
                    log.info('Unknown avatar url(%s) for %s',
                             user.profile.avatar_url, user.username)
                    continue

                log.info("Get image_url %s of %s", image_url, user.username)
                if image_url:
                    with closing(urllib.urlopen(image_url)) as fd:
                        image_file = io.BytesIO(fd.read())

                    # generate profile pic and thumbnails and store them
                    profile_image_names = get_profile_image_names(
                        user.username)
                    create_profile_images(image_file, profile_image_names)

                    # update the user account to reflect that a profile image is available.
                    uploaded_at = datetime.datetime.utcnow().replace(
                        tzinfo=utc)
                    UserProfile.objects.filter(user=user).update(
                        profile_image_uploaded_at=uploaded_at)
                    log.info(
                        "Profile image updated of %s with upload timestamp %s",
                        user.username, uploaded_at)
                else:
                    log.info(
                        "Profile image for username %s not found in source bucket",
                        bucket_name)

        except S3ResponseError as ex:
            log.info("Unable to connect to bucket %s. %s", bucket_name,
                     ex.message)
예제 #16
0
 def tearDown(self):
     super(ProfileImageEndpointMixin, self).tearDown()
     for name in get_profile_image_names(self.user.username).values():
         self.storage.delete(name)
 def tearDown(self):
     super().tearDown()
     for name in get_profile_image_names(self.user.username).values():
         self.storage.delete(name)