def handleAsync()

in api/models/badge.py [0:0]


    def handleAsync(self):
        one_week_ago = datetime.datetime.now() - datetime.timedelta(days=7)
        badges_to_remove = []
        badges_to_add = []
        users = self.dbs.query(User)
        badges = self.dbs.query(Badge)
        examples = self.dbs.query(Example)
        validations = self.dbs.query(Validation)
        validations_by_eid = {}
        for validation in validations:
            if validation.eid in validations_by_eid:
                validations_by_eid[validation.eid].append(validation)
            else:
                validations_by_eid[validation.eid] = [validation]
        badges_and_examples_by_uid = {}
        for badge in badges:
            if badge.uid in badges_and_examples_by_uid:
                badges_and_examples_by_uid[badge.uid]["badges"].append(badge)
            else:
                badges_and_examples_by_uid[badge.uid] = {
                    "badges": [badge],
                    "examples": [],
                }
        num_created_by_uid = {}
        max_num_created = 0
        for example in examples:
            if example.generated_datetime > one_week_ago:
                if example.uid in num_created_by_uid:
                    num_created_by_uid[example.uid] += 1
                else:
                    num_created_by_uid[example.uid] = 1
                if num_created_by_uid[example.uid] > max_num_created:
                    max_num_created = num_created_by_uid[example.uid]

            if example.uid in badges_and_examples_by_uid:
                badges_and_examples_by_uid[example.uid]["examples"].append(example)
            else:
                badges_and_examples_by_uid[example.uid] = {
                    "badges": [],
                    "examples": [example],
                }

        weekly_winners = [
            uid
            for uid, num_created in num_created_by_uid.items()
            if num_created == max_num_created
        ]

        for user in users:
            if user.metadata_json:
                metadata = util.json_decode(user.metadata_json)
            else:
                metadata = {}

            async_badges_to_award = []

            # Recompute all example streaks for a user.
            recomputed_example_streak_badge_names = []
            recomputed_day_streak_badge_names = []
            if user.id in badges_and_examples_by_uid:
                user_examples = badges_and_examples_by_uid[user.id]["examples"]
                if len(user_examples) > 0:
                    example_streak_count = 0
                    day_streak_count = 0
                    previous_example_day = user_examples[0].generated_datetime
                    for example in user_examples:
                        if example.context:
                            task = example.context.round.task
                        if example.id in validations_by_eid:
                            example_validations = validations_by_eid[example.id]
                        else:
                            example_validations = []

                        if example.context and (
                            not example.model_wrong
                            or example.retracted
                            or self.lengthOfFilteredList(
                                lambda validation: validation.label.name == "flagged",
                                example_validations,
                            )
                            >= task.num_matching_validations
                            or self.lengthOfFilteredList(
                                lambda validation: validation.label.name == "incorrect",
                                example_validations,
                            )
                            >= task.num_matching_validations
                            or self.lengthOfFilteredList(
                                lambda validation: validation.label.name == "flagged"
                                and validation.mode.name == "owner",
                                example_validations,
                            )
                            >= 1
                            or self.lengthOfFilteredList(
                                lambda validation: validation.label.name == "incorrect"
                                and validation.mode.name == "owner",
                                example_validations,
                            )
                            >= 1
                        ):
                            example_streak_count = 0
                        else:
                            example_streak_count += 1
                            one_day_passed = previous_example_day + datetime.timedelta(
                                days=1
                            )
                            two_days_passed = previous_example_day + datetime.timedelta(
                                days=2
                            )
                            if example.generated_datetime > one_day_passed:
                                if example.generated_datetime <= two_days_passed:
                                    day_streak_count += 1
                                    for (
                                        streak_type,
                                        num_required,
                                    ) in self.day_streak_type_and_num_required_days:
                                        if day_streak_count == num_required:
                                            recomputed_day_streak_badge_names.append(
                                                "DAY_STREAK_" + streak_type
                                            )
                                elif example.generated_datetime > two_days_passed:
                                    day_streak_count = 0
                                previous_example_day = example.generated_datetime

                            if example_streak_count in self.example_streak_num_required:
                                recomputed_example_streak_badge_names.append(
                                    "EXAMPLE_STREAK_" + str(example_streak_count)
                                )
                    user.streak_examples = example_streak_count
                    user.streak_days = day_streak_count

                # Remove a user's undeserved badges.
                for badge in badges_and_examples_by_uid[user.id]["badges"]:
                    for num_required in self.example_streak_num_required:
                        if badge.name == "EXAMPLE_STREAK_" + str(num_required):
                            if badge.name in recomputed_example_streak_badge_names:
                                recomputed_example_streak_badge_names.remove(badge.name)
                            else:
                                badges_to_remove.append(badge)
                    for (
                        streak_type,
                        num_required,
                    ) in self.day_streak_type_and_num_required_days:
                        if badge.name == "DAY_STREAK_" + streak_type:
                            if badge.name in recomputed_day_streak_badge_names:
                                recomputed_day_streak_badge_names.remove(badge.name)
                            else:
                                badges_to_remove.append(badge)

                    num_created_by_task = self.getFieldsFromMetadata(
                        metadata,
                        0,
                        [
                            task_name + "_fooling_no_verified_incorrect_or_flagged"
                            for task_name in self.task_code_to_badge_name
                        ],
                    )

                    for (
                        contributor_type,
                        num_required_creations,
                        _,
                    ) in self.contributor_type_num_required_creations_and_validations:
                        if badge.name == "DYNABENCH_" + contributor_type:
                            if sum(num_created_by_task) < num_required_creations:
                                badges_to_remove.append(badge)

                    if badge.name == "ALL_TASKS_COVERED" and 0 in num_created_by_task:
                        badges_to_remove.append(badge)

                    for task_name in self.task_code_to_badge_name:
                        for (
                            contributor_type,
                            num_required_creations,
                        ) in self.task_contributor_type_and_num_required_creations:
                            if (
                                badge.name
                                == "DYNABENCH_"
                                + self.task_code_to_badge_name[task_name]
                                + "_"
                                + contributor_type
                            ):
                                if (
                                    task_name
                                    + "_fooling_no_verified_incorrect_or_flagged"
                                    in metadata
                                ):
                                    if (
                                        metadata[
                                            task_name
                                            + "_fooling_no_verified_incorrect_"
                                            + "or_flagged"
                                        ]
                                        < num_required_creations
                                    ):
                                        badges_to_remove.append(badge)
                                else:
                                    badges_to_remove.append(badge)

            else:
                badges_and_examples_by_uid[user.id] = {"badges": [], "examples": []}

            # Award streak badges that result from the removal of other streak badges.
            # (e.g., if a 20 example streak is undeserved, a 5 example streak might
            # be deserved instead)
            for badge_name in recomputed_example_streak_badge_names:
                async_badges_to_award.append(badge_name)
            for badge_name in recomputed_day_streak_badge_names:
                async_badges_to_award.append(badge_name)

            # Award badges that must be computed asynchronously.
            if user.total_verified_fooled > 0 and "FIRST_VALIDATED_FOOLING" not in [
                badge.name for badge in badges_and_examples_by_uid[user.id]["badges"]
            ]:
                async_badges_to_award.append("FIRST_VALIDATED_FOOLING")

            if (
                len(badges_and_examples_by_uid[user.id]["examples"]) > 1
                and badges_and_examples_by_uid[user.id]["examples"][
                    -1
                ].generated_datetime
                - badges_and_examples_by_uid[user.id]["examples"][0].generated_datetime
                > datetime.timedelta(days=1)
                and "FIRST_STEPS"
                not in [
                    badge.name
                    for badge in badges_and_examples_by_uid[user.id]["badges"]
                ]
            ):
                async_badges_to_award.append("FIRST_STEPS")

            if user.id in weekly_winners and datetime.date.today().weekday() == 0:
                async_badges_to_award.append("WEEKLY_WINNER")

            for name in async_badges_to_award:
                badges_to_add.append(self._badgeobj(user.id, name))

            if "async_badges_to_award" not in metadata:
                metadata["async_badges_to_award"] = async_badges_to_award
            else:
                metadata["async_badges_to_award"] += async_badges_to_award
            user.metadata_json = util.json_encode(metadata)

        self.createNotificationsAndRemoveBadges(
            badges_to_remove, "BADGE_REMOVED_STREAK"
        )
        self.createNotificationsAndAddBadges(badges_to_add)
        print("Completed job")