diff --git a/apps/tests.py b/apps/tests.py index e9dfc1803..073ec6f9c 100755 --- a/apps/tests.py +++ b/apps/tests.py @@ -13,6 +13,9 @@ from PIL import Image, ImageDraw from django.conf import settings +from datetime import date, timedelta +from apps.views import get_top_downloaded_apps +from download.models import ReleaseDownloadsByDate from django.core.files.uploadedfile import SimpleUploadedFile from django.contrib.auth.models import User from django.test import TestCase @@ -676,4 +679,49 @@ def test_app_button_by_name_found_app(self): active=True) appobj.save() res = app_buttons.app_button_by_name('myapp') - self.assertEqual('myapp', res['app'].name) \ No newline at end of file + self.assertEqual('myapp', res['app'].name) + + +class TopDownloadedAppsTestCase(TestCase): + + def setUp(self): + self.app1 = App.objects.create(name="app1", fullname="App One", active=True) + self.app2 = App.objects.create(name="app2", fullname="App Two", active=True) + + uploaded = SimpleUploadedFile("file.jar", b"hello", content_type="text/plain") + + self.rel1 = Release.objects.create( + app=self.app1, + version="1.0", + release_file=uploaded, + active=True + ) + + self.rel2 = Release.objects.create( + app=self.app2, + version="1.0", + release_file=uploaded, + active=True + ) + + today = date.today() + + # within 24 months + ReleaseDownloadsByDate.objects.create( + release=self.rel1, + when=today - timedelta(days=100), + count=100 + ) + + # older than 24 months (ignored) + ReleaseDownloadsByDate.objects.create( + release=self.rel2, + when=today - timedelta(days=900), + count=500 + ) + + def test_top_downloads_returns_apps(self): + apps = list(get_top_downloaded_apps()) + + self.assertIn(self.app1, apps) + self.assertNotIn(self.app2, apps) \ No newline at end of file diff --git a/apps/views.py b/apps/views.py index 8569c4860..0b26956da 100755 --- a/apps/views.py +++ b/apps/views.py @@ -1,6 +1,10 @@ import re import datetime import html +from datetime import date, timedelta +from django.db.models import Case, When, IntegerField +from django.db.models import Sum +from download.models import ReleaseDownloadsByDate from urllib.parse import unquote from django.contrib.auth.models import User from django.contrib.auth.decorators import login_required @@ -79,10 +83,41 @@ def _flush_tag_caches(): class _DefaultConfig: num_of_top_apps = 6 +def get_top_downloaded_apps(limit=None): + two_years_ago = date.today() - timedelta(days=730) + + top_download_data = ( + ReleaseDownloadsByDate.objects + .filter( + when__gte=two_years_ago, + release__app__active=True, + release__active=True + ) + .values('release__app') + .annotate(total_downloads=Sum('count')) + .order_by('-total_downloads') + ) + + if limit is not None: + top_download_data = top_download_data[:limit] + + app_ids = [item['release__app'] for item in top_download_data] + + if not app_ids: + return App.objects.none() + + preserved_order = Case( + *[When(id=pk, then=pos) for pos, pk in enumerate(app_ids)], + output_field=IntegerField() + ) + + return App.objects.filter(id__in=app_ids).order_by(preserved_order) + + def apps_default(request): latest_apps = App.objects.filter(active=True).order_by('-latest_release_date')[:_DefaultConfig.num_of_top_apps] - downloaded_apps = App.objects.filter(active=True).order_by('downloads').reverse()[:_DefaultConfig.num_of_top_apps] - + # downloaded_apps = App.objects.filter(active=True).order_by('downloads').reverse()[:_DefaultConfig.num_of_top_apps] + downloaded_apps = get_top_downloaded_apps(_DefaultConfig.num_of_top_apps) c = { 'latest_apps': latest_apps, 'downloaded_apps': downloaded_apps, @@ -110,7 +145,8 @@ def all_apps_newest(request): def all_apps_downloads(request): - apps = App.objects.filter(active=True).order_by('downloads').reverse() + # apps = App.objects.filter(active=True).order_by('downloads').reverse() + apps = get_top_downloaded_apps() c = { 'apps': apps, 'navbar_selected_link': 'all',