From f76a80d8fdaa558aaef3508c15e931b81137bb49 Mon Sep 17 00:00:00 2001 From: KavyanshKhaitan2 Date: Sat, 19 Sep 2026 08:41:57 +0530 Subject: [PATCH 1/2] Make country cached for 3h per user --- twisted/twisted_site/hca.py | 8 ++----- ...le_country_profile_country_cached_until.py | 23 ++++++++++++++++++ twisted/twisted_site/models.py | 24 +++++++++++++++++-- twisted/twisted_site/views/admin/dashboard.py | 6 +---- 4 files changed, 48 insertions(+), 13 deletions(-) create mode 100644 twisted/twisted_site/migrations/0034_profile_country_profile_country_cached_until.py diff --git a/twisted/twisted_site/hca.py b/twisted/twisted_site/hca.py index 71e2867..5f29479 100644 --- a/twisted/twisted_site/hca.py +++ b/twisted/twisted_site/hca.py @@ -3,8 +3,6 @@ import requests -from .models import Profile - HCA_BASE_URL = "https://auth.hackclub.com/api/v1" @@ -45,10 +43,8 @@ def get_auth_headers(access_token: str, headers: dict[str, str] | None = None) - return {"Authorization": f"Bearer {access_token}", **headers} -def get_user_data(profile: Profile) -> Identity: - access_token = profile.hca_access_token - - headers = get_auth_headers(access_token) # ty: ignore[invalid-argument-type] +def get_user_data(access_token: str) -> Identity: + headers = get_auth_headers(access_token) r = requests.get(HCA_BASE_URL + "/me", headers=headers, timeout=10) r.raise_for_status() diff --git a/twisted/twisted_site/migrations/0034_profile_country_profile_country_cached_until.py b/twisted/twisted_site/migrations/0034_profile_country_profile_country_cached_until.py new file mode 100644 index 0000000..4e46c5e --- /dev/null +++ b/twisted/twisted_site/migrations/0034_profile_country_profile_country_cached_until.py @@ -0,0 +1,23 @@ +# Generated by Django 6.0.7 on 2026-09-19 03:10 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('twisted_site', '0033_project_hackatime_project_names'), + ] + + operations = [ + migrations.AddField( + model_name='profile', + name='country', + field=models.CharField(blank=True, default='', max_length=20), + ), + migrations.AddField( + model_name='profile', + name='country_cached_until', + field=models.DateTimeField(default=None, null=True), + ), + ] diff --git a/twisted/twisted_site/models.py b/twisted/twisted_site/models.py index 01fd746..b6ce982 100644 --- a/twisted/twisted_site/models.py +++ b/twisted/twisted_site/models.py @@ -1,3 +1,5 @@ +import logging +from requests import HTTPError from typing import TYPE_CHECKING, Any, cast, override from django.contrib.auth import get_user_model @@ -7,7 +9,7 @@ from django.db.models import TextField from django.utils import timezone -from . import hackatime +from . import hackatime, hca if TYPE_CHECKING: from datetime import datetime @@ -67,9 +69,27 @@ class Profile(models.Model): ) my_referral_code = models.CharField(max_length=200, blank=True, default="") + country = models.CharField(max_length=20, default="", blank=True) + country_cached_until = models.DateTimeField(null=True, default=None) + @override def __str__(self) -> str: - return cast("str", self.user.username) # pyrefly: ignore[missing-attribute] + return cast("str", self.user.username) # pyrefly: ignore[missing-attribute] # ty: ignore[unresolved-attribute] + + def get_country(self) -> str: + if self.country_cached_until is not None and self.country_cached_until > timezone.now(): + return str(self.country) + try: + user_data = hca.get_user_data(self.hca_access_token) # ty: ignore[invalid-argument-type] + country = user_data.primary_address.country if user_data.primary_address else "Unknown" + except HTTPError: + country = "Unknown" + + self.country = country # ty: ignore[invalid-assignment] + self.country_cached_until = timezone.now() + timezone.timedelta(hours=3) + self.save() + + return country def shipped_projects(self) -> list["Project"]: return [ diff --git a/twisted/twisted_site/views/admin/dashboard.py b/twisted/twisted_site/views/admin/dashboard.py index 93e5a15..b21b48c 100644 --- a/twisted/twisted_site/views/admin/dashboard.py +++ b/twisted/twisted_site/views/admin/dashboard.py @@ -35,11 +35,7 @@ def get(self, request: HttpRequest) -> HttpResponse: logged_project_type[journal.project.get_project_type_display()] += hours - try: - iden = hca.get_user_data(journal.project.user.profile) - country = iden.primary_address.country if iden.primary_address else "Unknown" - except HTTPError: - country = "Unknown" + country = journal.project.user.profile.get_country() logged_region_hours.setdefault(country, 0) logged_region_hours[country] += hours From 800938ad1226e287b76d9b7ea83290b890c5be12 Mon Sep 17 00:00:00 2001 From: KavyanshKhaitan2 Date: Sat, 19 Sep 2026 08:43:46 +0530 Subject: [PATCH 2/2] Make ruff pass --- twisted/twisted_site/models.py | 3 +-- twisted/twisted_site/views/admin/dashboard.py | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/twisted/twisted_site/models.py b/twisted/twisted_site/models.py index b6ce982..b89e7f5 100644 --- a/twisted/twisted_site/models.py +++ b/twisted/twisted_site/models.py @@ -1,5 +1,3 @@ -import logging -from requests import HTTPError from typing import TYPE_CHECKING, Any, cast, override from django.contrib.auth import get_user_model @@ -8,6 +6,7 @@ from django.db import models from django.db.models import TextField from django.utils import timezone +from requests import HTTPError from . import hackatime, hca diff --git a/twisted/twisted_site/views/admin/dashboard.py b/twisted/twisted_site/views/admin/dashboard.py index b21b48c..93ad6f4 100644 --- a/twisted/twisted_site/views/admin/dashboard.py +++ b/twisted/twisted_site/views/admin/dashboard.py @@ -3,9 +3,7 @@ from django.http import HttpRequest, HttpResponse from django.shortcuts import redirect from django.template.response import TemplateResponse -from requests.exceptions import HTTPError -from twisted_site import hca from twisted_site.models import Journal from .admin import AdminView