Example #1
0
def get_challenges_metadata(
    session: Session,
    event_bus: ChallengeEventBus,
    challenges: List[UserChallenge],
) -> List[Dict]:
    # Break it up into map per challenge type
    challenge_map: Dict[str, List[str]] = defaultdict(lambda: [])
    specifier_metadata_map: Dict[str, Dict] = {}
    for challenge in challenges:
        challenge_map[challenge.challenge_id].append(challenge.specifier)

    for challenge_type, specifiers in challenge_map.items():
        manager = event_bus.get_manager(challenge_type)
        metadatas = manager.get_metadata(session, specifiers)
        for i, specifier in enumerate(specifiers):
            metadata = metadatas[i]
            specifier_metadata_map[specifier] = metadata

    # Finally, re-sort the metadata
    return [specifier_metadata_map[c.specifier] for c in challenges]
Example #2
0
def get_challenges(
    user_id: int,
    show_historical: bool,
    session: Session,
    event_bus: ChallengeEventBus,
) -> List[ChallengeResponse]:
    challenges_and_disbursements: List[Tuple[UserChallenge, ChallengeDisbursement]] = (
        session.query(UserChallenge, ChallengeDisbursement)
        # Need to do outerjoin because some challenges
        # may not have disbursements
        .outerjoin(
            ChallengeDisbursement,
            and_(
                ChallengeDisbursement.specifier == UserChallenge.specifier,
                ChallengeDisbursement.challenge_id == UserChallenge.challenge_id,
            ),
        ).filter(UserChallenge.user_id == user_id)
    ).all()

    # Filter to challenges that have active managers
    # (in practice, all challenge should)
    challenges_and_disbursements = [
        c
        for c in challenges_and_disbursements
        if event_bus.does_manager_exist(c[0].challenge_id)
    ]

    # Combine aggregates

    all_challenges: List[Challenge] = (session.query(Challenge)).all()
    all_challenges_map = {challenge.id: challenge for challenge in all_challenges}

    # grab user challenges
    # if not historical, filter only to *active* challenges
    existing_user_challenges: List[UserChallenge] = [
        i[0]
        for i in challenges_and_disbursements
        if show_historical or all_challenges_map[i[0].challenge_id].active
    ]
    disbursements: List[ChallengeDisbursement] = [
        i[1] for i in challenges_and_disbursements
    ]

    regular_user_challenges: List[ChallengeResponse] = []
    aggregate_user_challenges_map: DefaultDict[str, List[UserChallenge]] = defaultdict(
        lambda: []
    )
    # Get extra metadata
    existing_metadata = get_challenges_metadata(
        session, event_bus, existing_user_challenges
    )
    for i, user_challenge in enumerate(existing_user_challenges):
        parent_challenge = all_challenges_map[user_challenge.challenge_id]
        if parent_challenge.type == ChallengeType.aggregate:
            # Filter out aggregate user_challenges that aren't complete.
            # this probably shouldn't even happen (what does it mean?)
            if user_challenge.is_complete:
                aggregate_user_challenges_map[user_challenge.challenge_id].append(
                    user_challenge
                )
        else:
            # If we're a trending challenge, don't add if the user_challenge is incomplete
            if (
                parent_challenge.type == ChallengeType.trending
                and not user_challenge.is_complete
            ):
                continue

            user_challenge_dict = to_challenge_response(
                user_challenge,
                parent_challenge,
                disbursements[i],
                existing_metadata[i],
            )
            override_step_count = event_bus.get_manager(
                parent_challenge.id
            ).get_override_challenge_step_count(session, user_id)
            if override_step_count is not None and not user_challenge.is_complete:
                user_challenge_dict["current_step_count"] = override_step_count
            regular_user_challenges.append(user_challenge_dict)

    rolled_up: List[ChallengeResponse] = []
    for (challenge_id, challenges) in aggregate_user_challenges_map.items():
        parent_challenge = all_challenges_map[challenge_id]
        rolled_up.append(rollup_aggregates(challenges, parent_challenge))

    # Return empty user challenges for active challenges that are non-hidden
    # and visible for the current user
    active_non_hidden_challenges: List[Challenge] = [
        challenge
        for challenge in all_challenges
        if (
            challenge.active
            and not challenge.type == ChallengeType.trending
            and event_bus.get_manager(challenge.id).should_show_challenge_for_user(
                session, user_id
            )
        )
    ]
    existing_challenge_ids = {
        user_challenge.challenge_id for user_challenge in existing_user_challenges
    }
    needs_user_challenge = [
        challenge
        for challenge in active_non_hidden_challenges
        if challenge.id not in existing_challenge_ids
    ]
    empty_metadata = get_empty_metadata(event_bus, needs_user_challenge)
    empty_challenges = create_empty_user_challenges(
        user_id, needs_user_challenge, empty_metadata
    )

    combined = regular_user_challenges + rolled_up + empty_challenges
    return combined
Example #3
0
def get_empty_metadata(event_bus: ChallengeEventBus, challenges: List[Challenge]):
    return [event_bus.get_manager(c.id).get_default_metadata() for c in challenges]