def top_contributors_questions()

in kitsune/community/utils.py [0:0]


def top_contributors_questions(start=None, end=None, locale=None, product=None, count=10, page=1):
    """Get the top Support Forum contributors."""

    search = AnswerDocument.search()

    search = (
        search.filter(
            # filter out answers by the question author
            "script",
            script="doc['creator_id'].value != doc['question_creator_id'].value",
        ).filter(
            # filter answers created between `start` and `end`, or within the last 90 days
            "range",
            created={"gte": start or datetime.now() - timedelta(days=90), "lte": end},
        )
        # set the query size to 0 because we don't care about the results
        # we're just filtering for the aggregations defined below
        .extra(size=0)
    )
    if locale:
        search = search.filter("term", locale=locale)
    if product:
        search = search.filter("term", question_product_id=product.id)

    # our filters above aren't perfect, and don't only return answers from contributors
    # so we need to collect more buckets than `count`, so we can hopefully find `count`
    # number of contributors within
    search.aggs.bucket(
        # create buckets for the `count * 10` most active users
        "contributions",
        A("terms", field="creator_id", size=count * 10),
    ).bucket(
        # within each of those, create a bucket for the most recent answer, and extract its date
        "latest",
        A(
            "top_hits",
            sort={"created": {"order": "desc"}},
            _source={"includes": "created"},
            size=1,
        ),
    )

    contribution_buckets = search.execute().aggregations.contributions.buckets

    if not contribution_buckets:
        return [], 0

    user_ids = [bucket.key for bucket in contribution_buckets]
    contributor_group_ids = list(
        Group.objects.filter(name__in=ContributionAreas.get_groups()).values_list("id", flat=True)
    )

    # fetch all the users returned by the aggregation which are in the contributor groups
    user_hits = (
        ProfileDocument.search()
        .query("terms", **{"_id": user_ids})
        .query("terms", group_ids=contributor_group_ids)
        .extra(size=len(user_ids))
        .execute()
        .hits
    )
    users = {hit.meta.id: hit for hit in user_hits}

    total_contributors = len(user_hits)
    top_contributors = []
    for bucket in contribution_buckets:
        if len(top_contributors) == page * count:
            # stop once we've collected enough contributors
            break
        user = users.get(bucket.key)
        if user is None:
            continue
        last_activity = datetime.fromisoformat(bucket.latest.hits.hits[0]._source.created)
        days_since_last_activity = (datetime.now(tz=timezone.utc) - last_activity).days
        top_contributors.append(
            {
                "count": bucket.doc_count,
                "term": bucket.key,
                "user": {
                    "id": user.meta.id,
                    "username": user.username,
                    "display_name": user.name,
                    "avatar": getattr(getattr(user, "avatar", None), "url", None),
                    "days_since_last_activity": days_since_last_activity,
                },
            }
        )

    return top_contributors[count * (page - 1) :], total_contributors