Skip to content

Conversation

@lsabor
Copy link
Contributor

@lsabor lsabor commented Nov 13, 2025

closes #3357

updates the available indexes in the front end

updates a little bit of logic on the back end

mostly, this is required to be launched in tandum with running code to generate new leaderbaords / fill in missing ones:

# create and update misssing global leaderboards

from datetime import datetime, timezone as dt_timezone

from posts.services.common import update_global_leaderboard_tags
from posts.models import Post
from projects.models import Project
from scoring.constants import LeaderboardScoreTypes
from scoring.models import Leaderboard
from scoring.utils import update_project_leaderboard

leaderboard_dates = [
    # 1 year leaderboards
    # new
    (
        datetime(2026, 1, 1, tzinfo=dt_timezone.utc),
        datetime(2027, 1, 1, tzinfo=dt_timezone.utc),
    ),
    # 2 year leaderboards
    # missing
    (
        datetime(2021, 1, 1, tzinfo=dt_timezone.utc),
        datetime(2023, 1, 1, tzinfo=dt_timezone.utc),
    ),
    (
        datetime(2023, 1, 1, tzinfo=dt_timezone.utc),
        datetime(2025, 1, 1, tzinfo=dt_timezone.utc),
    ),
    (
        datetime(2025, 1, 1, tzinfo=dt_timezone.utc),
        datetime(2027, 1, 1, tzinfo=dt_timezone.utc),
    ),
    # new
    (
        datetime(2026, 1, 1, tzinfo=dt_timezone.utc),
        datetime(2028, 1, 1, tzinfo=dt_timezone.utc),
    ),
    # 5 year leaderboards
    # new
    (
        datetime(2026, 1, 1, tzinfo=dt_timezone.utc),
        datetime(2031, 1, 1, tzinfo=dt_timezone.utc),
    ),
    # 10 year leaderboards
    # new
    (
        datetime(2026, 1, 1, tzinfo=dt_timezone.utc),
        datetime(2036, 1, 1, tzinfo=dt_timezone.utc),
    ),
]

site_main_project = Project.objects.filter(type="site_main").first()
if not site_main_project:
    raise ValueError("No site main project found.")
close_grace_period = timedelta(days=3)
resolve_grace_period = timedelta(days=100)

for start, end in leaderboard_dates:
    duration = end.year - start.year
    if end.year <= 2024:
        # legacy peer global
        Leaderboard.objects.get_or_create(
            score_type=LeaderboardScoreTypes.PEER_GLOBAL_LEGACY,
            start_time=start,
            end_time=end,
            finalize_time=end + resolve_grace_period,
            name=f"{start.year}: {duration} year peer_global_legacy",
            project=site_main_project,
        )
    else:
        Leaderboard.objects.get_or_create(
            score_type=LeaderboardScoreTypes.PEER_GLOBAL,
            start_time=start,
            end_time=end,
            finalize_time=end + resolve_grace_period,
            name=f"{start.year}: {duration} year peer_global",
            project=site_main_project,
        )
    Leaderboard.objects.get_or_create(
        score_type=LeaderboardScoreTypes.BASELINE_GLOBAL,
        start_time=start,
        end_time=end,
        finalize_time=end + resolve_grace_period,
        name=f"{start.year}: {duration} year baseline_global",
        project=site_main_project,
    )

    if duration == 1:
        # create question writing and comment insight leaderboards, too
        Leaderboard.objects.get_or_create(
            score_type=LeaderboardScoreTypes.QUESTION_WRITING,
            start_time=start,
            end_time=end,
            finalize_time=end,  # no grace period
            name=f"{start.year}: {duration} year question_writing",
            project=site_main_project,
        )
        Leaderboard.objects.get_or_create(
            score_type=LeaderboardScoreTypes.COMMENT_INSIGHT,
            start_time=start,
            end_time=end,
            finalize_time=end,  # no grace period
            name=f"{start.year}: {duration} year comment_insight",
            project=site_main_project,
        )

# update global leaderboards!
all_leaderboards = site_main_project.leaderboards.filter(finalized=False).order_by(
    "name"
)
c = len(all_leaderboards)
for i, leaderboard in enumerate(all_leaderboards, 1):
    print(f"Updating leaderboard {i}/{c} ({leaderboard.name})...", end="\r")
    update_project_leaderboard(leaderboard=leaderboard, force_update=True)
    print(f"Updating leaderboard {i}/{c} ({leaderboard.name})... DONE")

# update leaderboard tags for posts that might be effected
for start, end in [
    (
        datetime(2021, 1, 1, tzinfo=dt_timezone.utc),
        datetime(2026, 1, 1, tzinfo=dt_timezone.utc),
    ),
]:
    duration = end.year - start.year
    if duration == 1:
        leaderboard_tag = Project.objects.get(
            name=f"{start.year} Leaderboard",
            type=Project.ProjectTypes.LEADERBOARD_TAG,
        )
    else:
        leaderboard_tag = Project.objects.get(
            name=f"{start.year}-{end.year -1} Leaderboard",
            type=Project.ProjectTypes.LEADERBOARD_TAG,
        )
    posts = Post.objects.filter(projects=leaderboard_tag).distinct()
    c = posts.count()
    print(f"updating {c} posts for {leaderboard_tag.name}")
    for post in posts:
        old_tags = post.projects.filter(type=Project.ProjectTypes.LEADERBOARD_TAG)
        update_global_leaderboard_tags(post)
        post.refresh_from_db()
        new_tags = post.projects.filter(type=Project.ProjectTypes.LEADERBOARD_TAG)
        if not new_tags:
            print(
                f"Post {post.id} lost its leaderboard tag after "
                "update_global_leaderboard_tags"
            )
        elif set(old_tags) != set(new_tags):
            print(
                f"Post {post.id} changed leaderboard tag from {old_tags} to {new_tags}"
            )
untagged_posts = (
    Post.objects.filter_public()
    .filter(curation_status="approved")
    .exclude(projects__type=Project.ProjectTypes.LEADERBOARD_TAG)
)
c = untagged_posts.count()
print(f"updating {c} untagged posts for global leaderboards")
for i, post in enumerate(untagged_posts, 1):
    print(f"Processing post {i}/{c}", end="\r")
    update_global_leaderboard_tags(post)
    post.refresh_from_db()
    new_tags = post.projects.filter(type=Project.ProjectTypes.LEADERBOARD_TAG)
    if not new_tags:
        print(
            f"Processing post {i}/{c}. Post {post.id} remains untagged after "
            "update_global_leaderboard_tags",
            end="\r",
        )
    else:
        print(f"Processing post {i}/{c}. Post {post.id} tagged with {new_tags}")

@lsabor
Copy link
Contributor Author

lsabor commented Nov 13, 2025

backend reviewers, please review the quoted code in the top comment.
This won't be saved on platform (unless requested) but will be run.
This code was run locally and verified. Once it passes review, I'll be launching this on Play or Dev for QA from product. Then finally launching.

…lus/metaculus into feat/3357/new-global-leaderboards
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add the missing 2021-2022, 2023-2024 and 2025-2026 leaderboards

4 participants