Exemple #1
0
def test_file_descriptor_tuples_after_sharing_with_old_team(
        mock_get_download_url, mock_remove_file, shared_file_upload_fixture, mock_block
):
    # Include a deleted file entry, and later assert that we have an empty FileDescriptor
    # record returned by ``file_descriptor_tuples()``
    block = mock_block(
        descriptions=['The first file', 'The deleted file', 'The second file'],
        names=['File A', 'File that is deleted', 'File B'],
        sizes=[22, 666, 44],
    )
    block.team.team_id = DEFAULT_TEAM_ID
    block.is_team_assignment.return_value = True

    student_item_dict = {
        'student_id': DEFAULT_OWNER_ID,
        'course_id': DEFAULT_COURSE_ID,
        'item_id': DEFAULT_ITEM_ID,
    }
    key_a = api.get_student_file_key(student_item_dict, index=0)
    key_deleted = api.get_student_file_key(student_item_dict, index=1)
    key_b = api.get_student_file_key(student_item_dict, index=2)

    # create a shared upload that was shared with an old team
    _ = shared_file_upload_fixture(team_id='an-old-team', file_key=key_a)

    # create one for the file we're going to delete
    _ = shared_file_upload_fixture(team_id=block.team.team_id, file_key=key_deleted)

    # create a shared upload that's shared with the learner's current team
    _ = shared_file_upload_fixture(team_id=block.team.team_id, file_key=key_b)

    file_manager = api.FileUploadManager(block)

    # go and delete the file we want to delete
    file_manager.delete_upload(1)

    # team_file_descriptor_tuples() should only give back a record for the upload shared with the current team
    actual_descriptors = file_manager.file_descriptor_tuples(include_deleted=True)
    expected_descriptors = [
        api.FileDescriptor(
            download_url=None,
            name=None,
            description=None,
            show_delete_button=False,
        ),
        api.FileDescriptor(
            download_url=mock_get_download_url.return_value,
            name='File B',
            description='The second file',
            show_delete_button=True,
        ),
    ]

    assert expected_descriptors == actual_descriptors
    mock_get_download_url.assert_called_once_with(key_b)
    mock_remove_file.assert_called_once_with(key_deleted)
Exemple #2
0
    def get_download_urls_from_submission(self, submission):
        """
        Returns a download URLs for retrieving content within a submission.

        Args:
            submission (dict): Dictionary containing an answer and a file_keys.
                The file_keys is used to try and retrieve a download urls
                with related content

        Returns:
            List with URLs to related content. If there is no content related to this
            key, or if there is no key for the submission, returns an empty
            list.

        """
        urls = []
        if 'file_keys' in submission['answer']:
            file_keys = submission['answer'].get('file_keys', [])
            descriptions = submission['answer'].get('files_descriptions', [])
            file_names = submission['answer'].get('files_name', submission['answer'].get('files_names', []))
            for idx, key in enumerate(file_keys):
                file_download_url = self._get_url_by_file_key(key)
                if file_download_url:
                    file_description = descriptions[idx].strip() if idx < len(descriptions) else ''
                    try:
                        file_name = file_names[idx].strip() if idx < len(file_names) else ''
                    except AttributeError:
                        file_name = ''
                        logger.error('descriptions[idx] is None in {}'.format(submission))
                    urls.append(
                        file_upload_api.FileDescriptor(
                            download_url=file_download_url,
                            description=file_description,
                            name=file_name,
                            show_delete_button=False
                        )._asdict()
                    )
        elif 'file_key' in submission['answer']:
            key = submission['answer'].get('file_key', '')
            file_download_url = self._get_url_by_file_key(key)
            if file_download_url:
                urls.append(
                    file_upload_api.FileDescriptor(
                        download_url=file_download_url,
                        description='',
                        name='',
                        show_delete_button=False
                    )._asdict()
                )
        return urls
Exemple #3
0
    def get_download_urls_from_submission(cls, submission):
        """
        Returns a download URLs for retrieving content within a submission.

        Args:
            submission (dict): Dictionary containing an answer and a file_keys.
                The file_keys is used to try and retrieve a download urls
                with related content

        Returns:
            List with URLs to related content. If there is no content related to this
            key, or if there is no key for the submission, returns an empty
            list.

        """
        urls = []
        raw_answer = submission.get('answer')
        answer = OraSubmissionAnswerFactory.parse_submission_raw_answer(
            raw_answer)
        for file_upload in answer.get_file_uploads(missing_blank=True):
            file_download_url = cls._get_url_by_file_key(file_upload.key)
            if file_download_url:
                urls.append(
                    file_upload_api.FileDescriptor(
                        download_url=file_download_url,
                        description=file_upload.description,
                        name=file_upload.name,
                        show_delete_button=False)._asdict())
        return urls
Exemple #4
0
def test_file_descriptor_tuples_no_team(mock_block):
    block = mock_block(
        descriptions=['The first file', 'The second file'],
        names=['File A', 'File B'],
        sizes=[22, 44],
    )
    block.is_team_assignment.return_value = False

    file_manager = api.FileUploadManager(block)

    actual_descriptors = file_manager.file_descriptor_tuples()
    expected_descriptors = [
        api.FileDescriptor(download_url='', name='File A', description='The first file', show_delete_button=True),
        api.FileDescriptor(download_url='', name='File B', description='The second file', show_delete_button=True),
    ]

    assert expected_descriptors == actual_descriptors
    def render_leaderboard_complete(self, student_item_dict):
        """
        Render the leaderboard complete state.

        Args:
            student_item_dict (dict): The student item

        Returns:
            template_path (string), tuple of context (dict)
        """
        # Import is placed here to avoid model import at project startup.
        from submissions import api as sub_api

        # Retrieve top scores from the submissions API
        # Since this uses the read-replica and caches the results,
        # there will be some delay in the request latency.
        scores = sub_api.get_top_submissions(student_item_dict['course_id'],
                                             student_item_dict['item_id'],
                                             student_item_dict['item_type'],
                                             self.leaderboard_show)
        for score in scores:
            raw_score_content_answer = score['content']
            answer = OraSubmissionAnswerFactory.parse_submission_raw_answer(
                raw_score_content_answer)
            score['files'] = []
            for uploaded_file in answer.get_file_uploads(missing_blank=True):
                file_download_url = self._get_file_download_url(
                    uploaded_file.key)
                if file_download_url:
                    score['files'].append(
                        file_upload_api.FileDescriptor(
                            download_url=file_download_url,
                            description=uploaded_file.description,
                            name=uploaded_file.name,
                            size=uploaded_file.size,
                            show_delete_button=False)._asdict())
            if 'text' in score['content'] or 'parts' in score['content']:
                submission = {'answer': score.pop('content')}
                score['submission'] = create_submission_dict(
                    submission, self.prompts)
            elif isinstance(score['content'], str):
                pass
            # Currently, we do not handle non-text submissions.
            else:
                score['submission'] = ""

            score.pop('content', None)

        context = {
            'topscores': scores,
            'allow_multiple_files': self.allow_multiple_files,
            'allow_latex': self.allow_latex,
            'prompts_type': self.prompts_type,
            'file_upload_type': self.file_upload_type,
            'xblock_id': self.get_xblock_id()
        }

        return 'openassessmentblock/leaderboard/oa_leaderboard_show.html', context
    def get_files_info_from_user_state(self, username):
        """
        Returns the files information from the user state for a given username.

        If the files information is present in the user state, return a list of following tuple:
        (file_download_url, file_description, file_name)

        Arguments:
            username(str): user's name whose state is being check for files information.
        Returns:
            List of files information tuple, if present, else empty list.
        """

        files_info = []
        user_state = self.get_user_state(username)
        item_dict = self.get_student_item_dict_from_username_or_email(username)
        if 'saved_files_descriptions' in user_state:
            # pylint: disable=protected-access
            files_descriptions = file_upload_api._safe_load_json_list(
                user_state.get('saved_files_descriptions'),
                log_error=True
            )
            files_names = file_upload_api._safe_load_json_list(
                user_state.get('saved_files_names', '[]'),
                log_error=True
            )
            for index, description in enumerate(files_descriptions):
                file_key = file_upload_api.get_student_file_key(item_dict, index)
                download_url = self._get_url_by_file_key(file_key)
                if download_url:
                    file_name = files_names[index] if index < len(files_names) else ''
                    files_info.append(
                        file_upload_api.FileDescriptor(
                            download_url=download_url,
                            description=description,
                            name=file_name,
                            show_delete_button=False
                        )._asdict()
                    )
                else:
                    # If file has been removed, the URL doesn't exist
                    logger.info(
                        "URLWorkaround: no URL for description %s & key %s for user:%s",
                        description,
                        username,
                        file_key
                    )
                    continue
        return files_info
    def get_all_upload_urls_for_user(self, username_or_email):
        """
        For a particular ORA block, get the download URLs for all the files uploaded and still present.

        Used for an extreme edge case, where the stored files indices are out of sync with
        the uploaded files, this is a last resort to get the download URLs of all the files
        that have been uploaded by a learner in an ORA block(and haven't been deleted from the storage).
        Starting from 0 index to maximum file upload count possible, this checks if a file exists against
        every index. If present, add the info, else repeat it for the next indices.

        Arguments:
            username_or_email(str): username or email of the learner whose files' information is to be obtained.
        Returns:
            List of 3-valued tuples, with first value being file URL and other two values as empty string.
            The other 2 values have to be appended to work properly in the template.
        """
        file_uploads = []
        student_item_dict = self.get_student_item_dict_from_username_or_email(username_or_email)
        for index in range(self.MAX_FILES_COUNT):
            file_key = file_upload_api.get_student_file_key(student_item_dict, index)
            download_url = ''
            try:
                download_url = file_upload_api.get_download_url(file_key)
            except FileUploadError:
                pass

            if download_url:
                logger.info(
                    "Download URL exists for key %s in block %s for user %s",
                    file_key,
                    username_or_email,
                    str(self.location)
                )
                file_uploads.append(
                    file_upload_api.FileDescriptor(
                        download_url=download_url,
                        description='',
                        name='',
                        show_delete_button=False
                    )._asdict()
                )
            else:
                continue

        return file_uploads
    def render_leaderboard_complete(self, student_item_dict):
        """
        Render the leaderboard complete state.

        Args:
            student_item_dict (dict): The student item

        Returns:
            template_path (string), tuple of context (dict)
        """
        # Import is placed here to avoid model import at project startup.
        from submissions import api as sub_api

        # Retrieve top scores from the submissions API
        # Since this uses the read-replica and caches the results,
        # there will be some delay in the request latency.
        scores = sub_api.get_top_submissions(
            student_item_dict['course_id'],
            student_item_dict['item_id'],
            student_item_dict['item_type'],
            self.leaderboard_show
        )
        for score in scores:
            score['files'] = []
            if 'file_keys' in score['content']:
                file_keys = score['content'].get('file_keys', [])
                descriptions = score['content'].get('files_descriptions', [])
                file_names = score['content'].get('files_name', [])
                for idx, key in enumerate(file_keys):
                    file_download_url = self._get_file_download_url(key)
                    if file_download_url:
                        file_description = descriptions[idx] if idx < len(descriptions) else ''
                        file_name = file_names[idx] if idx < len(file_names) else ''
                        score['files'].append(
                            file_upload_api.FileDescriptor(
                                download_url=file_download_url,
                                description=file_description,
                                name=file_name,
                                show_delete_button=False
                            )._asdict()
                        )

            elif 'file_key' in score['content']:
                file_download_url = self._get_file_download_url(score['content']['file_key'])
                if file_download_url:
                    score['files'].append(
                        file_upload_api.FileDescriptor(
                            download_url=file_download_url,
                            description='',
                            name='',
                            show_delete_button=False
                        )._asdict()
                    )
            if 'text' in score['content'] or 'parts' in score['content']:
                submission = {'answer': score.pop('content')}
                score['submission'] = create_submission_dict(submission, self.prompts)
            elif isinstance(score['content'], str):
                pass
            # Currently, we do not handle non-text submissions.
            else:
                score['submission'] = ""

            score.pop('content', None)

        context = {'topscores': scores,
                   'allow_latex': self.allow_latex,
                   'prompts_type': self.prompts_type,
                   'file_upload_type': self.file_upload_type,
                   'xblock_id': self.get_xblock_id()}

        return 'openassessmentblock/leaderboard/oa_leaderboard_show.html', context