Beispiel #1
0
    def _are_nodes_valid_for_publishing(story_nodes):
        """Validates the story nodes before publishing.

        Args:
            story_nodes: list(dict(str, *)). The list of story nodes dicts.

        Raises:
            Exception: The story node doesn't contain any exploration id or the
                exploration id is invalid or isn't published yet.
        """
        exploration_id_list = []
        for node in story_nodes:
            if not node.exploration_id:
                raise Exception('Story node with id %s does not contain an '
                                'exploration id.' % node.id)
            exploration_id_list.append(node.exploration_id)
        explorations = exp_fetchers.get_multiple_explorations_by_id(
            exploration_id_list, strict=False)
        for node in story_nodes:
            if not node.exploration_id in explorations:
                raise Exception('Exploration id %s doesn\'t exist.' %
                                node.exploration_id)
        multiple_exploration_rights = (
            rights_manager.get_multiple_exploration_rights_by_ids(
                exploration_id_list))
        for exploration_rights in multiple_exploration_rights:
            if exploration_rights.is_private():
                raise Exception('Exploration with id %s isn\'t published.' %
                                exploration_rights.id)
Beispiel #2
0
def get_displayable_exp_summary_dicts_matching_ids(exploration_ids, user=None):
    """Gets a summary of explorations in human readable form from
    exploration ids.

    Given a list of exploration ids, optionally filters the list for
    explorations that are currently non-private and not deleted, and returns a
    list of dicts of the corresponding exploration summaries. This function can
    also filter based on a user ID who has edit access to the corresponding
    exploration, where the editor ID is for private explorations. Please use
    this function when needing summary information to display on exploration
    summary tiles in the frontend.

    Args:
        exploration_ids: list(str). List of exploration ids.
        user: UserActionsInfo or None. Object having user_id, role and actions
            for given user.

    Return:
        list(dict). A list of exploration summary dicts in human readable form.
        Example:

        [ {
            'category': u'A category',
            'community_owned': False,
            'id': 'eid2',
            'language_code': 'en',
            'num_views': 0,
            'objective': u'An objective',
            'status': 'public',
            'tags': [],
            'thumbnail_bg_color': '#a33f40',
            'thumbnail_icon_url': self.get_static_asset_url(
                '/images/subjects/Lightbulb.svg'),
            'title': u'Exploration 2 Albert title',
        }, ]
    """
    exploration_summaries = (
        exp_services.get_exploration_summaries_matching_ids(exploration_ids))
    exploration_rights_objects = (
        rights_manager.get_multiple_exploration_rights_by_ids(exploration_ids))

    filtered_exploration_summaries = []
    for (exploration_summary, exploration_rights) in (
            zip(exploration_summaries, exploration_rights_objects)):
        if exploration_summary is None:
            continue

        if exploration_rights is None:
            continue
        if exploration_summary.status == (
                rights_manager.ACTIVITY_STATUS_PRIVATE):
            if user is None:
                continue
            if not rights_manager.check_can_edit_activity(
                    user, exploration_rights):
                continue

        filtered_exploration_summaries.append(exploration_summary)

    return get_displayable_exp_summary_dicts(filtered_exploration_summaries)
Beispiel #3
0
    def test_get_multiple_exploration_rights(self):
        exp_ids = ['exp1', 'exp2', 'exp3', 'exp4']

        # saving only first 3 explorations to check that None is returned for
        # non-existing exploration.
        for exp_id in exp_ids[:3]:
            self.save_new_valid_exploration(exp_id, self.user_id_admin)
        exp_rights = rights_manager.get_multiple_exploration_rights_by_ids(
            exp_ids)

        self.assertEqual(len(exp_rights), 4)
        for rights_object in exp_rights[:3]:
            self.assertIsNotNone(rights_object)
        self.assertIsNone(exp_rights[3])
Beispiel #4
0
def get_exploration_metadata_dicts(exploration_ids, user):
    """Given a list of exploration ids, optionally filters the list for
    explorations that are currently non-private and not deleted, and returns a
    list of dicts of the corresponding exploration summaries for collection
    node search.

    Args:
        exploration_ids: list(str). A list of exploration ids for which
            exploration metadata dicts are to be returned.
        user: UserActionsInfo. Object having user_id, role and actions for
            given user.

    Returns:
        list(dict). A list of metadata dicts corresponding to the given
        exploration ids. Each dict has three keys:
            'id': the exploration id;
            'title': the exploration title;
            'objective': the exploration objective.
    """
    exploration_summaries = (
        exp_services.get_exploration_summaries_matching_ids(exploration_ids))
    exploration_rights_objects = (
        rights_manager.get_multiple_exploration_rights_by_ids(exploration_ids))

    filtered_exploration_summaries = []
    for (exploration_summary,
         exploration_rights) in (zip(exploration_summaries,
                                     exploration_rights_objects)):
        if exploration_summary is None:
            continue

        if exploration_rights is None:
            continue

        if exploration_summary.status == (
                rights_manager.ACTIVITY_STATUS_PRIVATE):
            if user.user_id is None:
                continue

            if not rights_manager.check_can_edit_activity(
                    user, exploration_rights):
                continue

        filtered_exploration_summaries.append(exploration_summary)

    return [
        summary.to_metadata_dict()
        for summary in filtered_exploration_summaries
    ]
Beispiel #5
0
 def _are_nodes_valid_for_publishing(story_nodes):
     exploration_id_list = []
     for node in story_nodes:
         if not node.exploration_id:
             raise Exception('Story node with id %s does not contain an '
                             'exploration id.' % node.id)
         exploration_id_list.append(node.exploration_id)
     for exploration in exp_services.get_multiple_explorations_by_id(
             exploration_id_list):
         if exploration is None:
             raise Exception('Exploration id %s doesn\'t exist.' %
                             exploration.id)
     multiple_exploration_rights = (
         rights_manager.get_multiple_exploration_rights_by_ids(
             exploration_id_list))
     for exploration_rights in multiple_exploration_rights:
         if exploration_rights.is_private():
             raise Exception('Exploration with id %s isn\'t published.' %
                             exploration_rights.id)
Beispiel #6
0
def validate_explorations_for_story(exp_ids, strict):
    """Validates the explorations in the given story and checks whether they
    are compatible with the mobile app and ready for publishing.

    Args:
        exp_ids: list(str). The exp IDs to validate.
        strict: bool. Whether to raise an Exception when a validation error
            is encountered. If not, a list of the error messages are
            returned. strict should be True when this is called before
            saving the story and False when this function is called from the
            frontend.

    Returns:
        list(str). The various validation error messages (if strict is
        False).

    Raises:
        ValidationError. Expected story to only reference valid explorations.
        ValidationError. Exploration with ID is not public. Please publish
            explorations before adding them to a story.
        ValidationError. All explorations in a story should be of the same
            category.
    """
    validation_error_messages = []

    # Strict = False, since the existence of explorations is checked below.
    exps_dict = (
        exp_fetchers.get_multiple_explorations_by_id(exp_ids, strict=False))

    exp_rights = (
        rights_manager.get_multiple_exploration_rights_by_ids(exp_ids))

    exp_rights_dict = {}

    for rights in exp_rights:
        if rights is not None:
            exp_rights_dict[rights.id] = rights.status

    for exp_id in exp_ids:
        if exp_id not in exps_dict:
            error_string = (
                'Expected story to only reference valid explorations, but found'
                ' a reference to an invalid exploration with ID: %s'
                % exp_id)
            if strict:
                raise utils.ValidationError(error_string)
            validation_error_messages.append(error_string)
        else:
            if exp_rights_dict[exp_id] != constants.ACTIVITY_STATUS_PUBLIC:
                error_string = (
                    'Exploration with ID %s is not public. Please publish '
                    'explorations before adding them to a story.'
                    % exp_id)
                if strict:
                    raise utils.ValidationError(error_string)
                validation_error_messages.append(error_string)

    if exps_dict:
        for exp_id in exp_ids:
            if exp_id in exps_dict:
                sample_exp_id = exp_id
                break
        common_exp_category = exps_dict[sample_exp_id].category
        for exp_id in exps_dict:
            exp = exps_dict[exp_id]
            if exp.category != common_exp_category:
                error_string = (
                    'All explorations in a story should be of the '
                    'same category. The explorations with ID %s and %s have'
                    ' different categories.' % (sample_exp_id, exp_id))
                if strict:
                    raise utils.ValidationError(error_string)
                validation_error_messages.append(error_string)
            try:
                validation_error_messages.extend(
                    exp_services.validate_exploration_for_story(exp, strict))
            except Exception as e:
                logging.exception(
                    'Exploration validation failed for exploration with ID: '
                    '%s. Error: %s' % (exp_id, e))
                raise Exception(e)

    return validation_error_messages
Beispiel #7
0
def validate_explorations_for_story(exp_ids, raise_error):
    """Validates the explorations in the given story and checks whether they
    are compatible with the mobile app.

    Args:
        exp_ids: list(str). The exp IDs to validate.
        raise_error: bool. Whether to raise an Exception when a validation error
            is encountered. If not, a list of the error messages are
            returned. raise_error should be True when this is called before
            saving the story and False when this function is called from the
            frontend.

    Returns:
        list(str). The various validation error messages (if raise_error is
        False).

    Raises:
        ValidationError. Expected story to only reference valid explorations.
        ValidationError. Exploration with ID is not public. Please publish
            explorations before adding them to a story.
        ValidationError. All explorations in a story should be of the same
            category.
        ValidationError. Invalid language found for exploration.
        ValidationError. Expected no exploration to have parameter values in it.
        ValidationError. Invalid interaction in exploration.
        ValidationError. RTE content in state of exploration with ID is not
            supported on mobile.
    """
    validation_error_messages = []

    # Strict = False, since the existence of explorations is checked below.
    exps_dict = (
        exp_fetchers.get_multiple_explorations_by_id(exp_ids, strict=False))

    exp_rights = (
        rights_manager.get_multiple_exploration_rights_by_ids(exp_ids))

    exp_rights_dict = {}

    for rights in exp_rights:
        if rights is not None:
            exp_rights_dict[rights.id] = rights.status

    for exp_id in exp_ids:
        if exp_id not in exps_dict:
            error_string = (
                'Expected story to only reference valid explorations, but found'
                ' a reference to an invalid exploration with ID: %s'
                % exp_id)
            if raise_error:
                raise utils.ValidationError(error_string)
            validation_error_messages.append(error_string)
        else:
            if exp_rights_dict[exp_id] != constants.ACTIVITY_STATUS_PUBLIC:
                error_string = (
                    'Exploration with ID %s is not public. Please publish '
                    'explorations before adding them to a story.'
                    % exp_id)
                if raise_error:
                    raise utils.ValidationError(error_string)
                validation_error_messages.append(error_string)

    if exps_dict:
        for exp_id in exp_ids:
            if exp_id in exps_dict:
                sample_exp_id = exp_id
                break
        common_exp_category = exps_dict[sample_exp_id].category
        for exp_id in exps_dict:
            exp = exps_dict[exp_id]
            if exp.category != common_exp_category:
                error_string = (
                    'All explorations in a story should be of the '
                    'same category. The explorations with ID %s and %s have'
                    ' different categories.' % (sample_exp_id, exp_id))
                if raise_error:
                    raise utils.ValidationError(error_string)
                validation_error_messages.append(error_string)
            if (
                    exp.language_code not in
                    android_validation_constants.SUPPORTED_LANGUAGES):
                error_string = (
                    'Invalid language %s found for exploration '
                    'with ID %s.' % (exp.language_code, exp_id))
                if raise_error:
                    raise utils.ValidationError(error_string)
                validation_error_messages.append(error_string)

            if exp.param_specs or exp.param_changes:
                error_string = (
                    'Expected no exploration to have parameter '
                    'values in it. Invalid exploration: %s' % exp.id)
                if raise_error:
                    raise utils.ValidationError(error_string)
                validation_error_messages.append(error_string)

            for state_name in exp.states:
                state = exp.states[state_name]
                if not state.interaction.is_supported_on_android_app():
                    error_string = (
                        'Invalid interaction %s in exploration '
                        'with ID: %s.' % (state.interaction.id, exp.id))
                    if raise_error:
                        raise utils.ValidationError(error_string)
                    validation_error_messages.append(error_string)

                if not state.is_rte_content_supported_on_android():
                    error_string = (
                        'RTE content in state %s of exploration '
                        'with ID %s is not supported on mobile.'
                        % (state_name, exp.id))
                    if raise_error:
                        raise utils.ValidationError(error_string)
                    validation_error_messages.append(error_string)

                if state.interaction.id == 'EndExploration':
                    recommended_exploration_ids = (
                        state.interaction.customization_args[
                            'recommendedExplorationIds'].value)
                    if len(recommended_exploration_ids) != 0:
                        error_string = (
                            'Exploration with ID: %s contains exploration '
                            'recommendations in its EndExploration interaction.'
                            % (exp.id))
                        if raise_error:
                            raise utils.ValidationError(error_string)
                        validation_error_messages.append(error_string)

    return validation_error_messages