diff --git a/passbook/admin/settings.py b/passbook/admin/settings.py new file mode 100644 index 000000000..d6690770a --- /dev/null +++ b/passbook/admin/settings.py @@ -0,0 +1,10 @@ +"""passbook admin settings""" +from celery.schedules import crontab + +CELERY_BEAT_SCHEDULE = { + "admin_latest_version": { + "task": "passbook.admin.tasks.update_latest_version", + "schedule": crontab(minute=0), # Run every hour + "options": {"queue": "passbook_scheduled"}, + } +} diff --git a/passbook/admin/tasks.py b/passbook/admin/tasks.py new file mode 100644 index 000000000..931be54ea --- /dev/null +++ b/passbook/admin/tasks.py @@ -0,0 +1,23 @@ +"""passbook admin tasks""" +from django.core.cache import cache +from requests import RequestException, get +from structlog import get_logger + +from passbook.root.celery import CELERY_APP + +LOGGER = get_logger() +VERSION_CACHE_KEY = "passbook_latest_version" +VERSION_CACHE_TIMEOUT = 2 * 60 * 60 # 2 hours + + +@CELERY_APP.task() +def update_latest_version(): + """Update latest version info""" + try: + data = get( + "https://api.github.com/repos/beryju/passbook/releases/latest" + ).json() + tag_name = data.get("tag_name") + cache.set(VERSION_CACHE_KEY, tag_name.split("/")[1], VERSION_CACHE_TIMEOUT) + except (RequestException, IndexError): + cache.set(VERSION_CACHE_KEY, "0.0.0", VERSION_CACHE_TIMEOUT) diff --git a/passbook/admin/views/overview.py b/passbook/admin/views/overview.py index c0421f8a9..d2c66ca96 100644 --- a/passbook/admin/views/overview.py +++ b/passbook/admin/views/overview.py @@ -5,32 +5,16 @@ from django.core.cache import cache from django.shortcuts import redirect, reverse from django.views.generic import TemplateView from packaging.version import LegacyVersion, Version, parse -from requests import RequestException, get from passbook import __version__ from passbook.admin.mixins import AdminRequiredMixin +from passbook.admin.tasks import VERSION_CACHE_KEY, update_latest_version from passbook.core.models import Application, Provider, Source, User from passbook.flows.models import Flow, Stage from passbook.policies.models import Policy from passbook.root.celery import CELERY_APP from passbook.stages.invitation.models import Invitation -VERSION_CACHE_KEY = "passbook_latest_version" - - -def latest_version() -> Union[LegacyVersion, Version]: - """Get latest release from GitHub, cached""" - if not cache.get(VERSION_CACHE_KEY): - try: - data = get( - "https://api.github.com/repos/beryju/passbook/releases/latest" - ).json() - tag_name = data.get("tag_name") - cache.set(VERSION_CACHE_KEY, tag_name.split("/")[1], 30) - except (RequestException, IndexError): - cache.set(VERSION_CACHE_KEY, "0.0.0", 30) - return parse(cache.get(VERSION_CACHE_KEY)) - class AdministrationOverviewView(AdminRequiredMixin, TemplateView): """Overview View""" @@ -44,6 +28,14 @@ class AdministrationOverviewView(AdminRequiredMixin, TemplateView): return redirect(reverse("passbook_flows:default-authentication")) return self.get(*args, **kwargs) + def get_latest_version(self) -> Union[LegacyVersion, Version]: + """Get latest version from cache""" + version_in_cache = cache.get(VERSION_CACHE_KEY) + if not version_in_cache: + update_latest_version.delay() + return parse(__version__) + return parse(version_in_cache) + def get_context_data(self, **kwargs): kwargs["application_count"] = len(Application.objects.all()) kwargs["policy_count"] = len(Policy.objects.all()) @@ -54,7 +46,7 @@ class AdministrationOverviewView(AdminRequiredMixin, TemplateView): kwargs["flow_count"] = len(Flow.objects.all()) kwargs["invitation_count"] = len(Invitation.objects.all()) kwargs["version"] = parse(__version__) - kwargs["version_latest"] = latest_version() + kwargs["version_latest"] = self.get_latest_version() kwargs["worker_count"] = len(CELERY_APP.control.ping(timeout=0.5)) kwargs["providers_without_application"] = Provider.objects.filter( application=None