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