feat: add client release force update flag

This commit is contained in:
QiuSW
2026-07-08 15:38:59 +08:00
parent 30d9df34eb
commit 6646c64a76
14 changed files with 130 additions and 29 deletions
+52 -2
View File
@@ -9,6 +9,7 @@ from unittest.mock import patch
import requests
from cryptography.fernet import Fernet
from django.conf import settings
from django.contrib import admin
from django.contrib.auth import get_user_model
from django.core.cache import cache
from django.test import TestCase, override_settings
@@ -423,6 +424,7 @@ class ClientLatestReleaseApiTests(TestCase):
file_name: str = "",
sha256: str = "a" * 64,
release_notes: str = "首版 Windows 客户端",
force_update: bool = False,
) -> DownloadRelease:
return DownloadRelease.objects.create(
platform=platform,
@@ -432,6 +434,7 @@ class ClientLatestReleaseApiTests(TestCase):
file=file_name,
sha256=sha256,
release_notes=release_notes,
force_update=force_update,
)
def test_latest_release_is_public_without_api_key_and_returns_current_release(self):
@@ -449,9 +452,17 @@ class ClientLatestReleaseApiTests(TestCase):
self.assertEqual(response.data["platform"], "windows")
self.assertEqual(
set(response.data["release"]),
{"version", "download_url", "sha256", "release_notes", "published_at"},
{
"version",
"download_url",
"sha256",
"release_notes",
"force_update",
"published_at",
},
)
self.assertEqual(response.data["release"]["version"], "1.2.3")
self.assertFalse(response.data["release"]["force_update"])
self.assertEqual(
response.data["release"]["download_url"],
"https://download.example.com/cmhub-1.2.3.exe",
@@ -466,6 +477,29 @@ class ClientLatestReleaseApiTests(TestCase):
timezone.localtime(release.updated_at).isoformat(),
)
def test_latest_release_returns_force_update_true(self):
self.create_release(
version="0.1.1",
external_url="https://download.example.com/cmhub-0.1.1.zip",
release_notes="优化了ai模块的生图的功能",
force_update=True,
)
response = self.client.get(f"{self.url}?platform=windows")
self.assertEqual(response.status_code, 200)
self.assertEqual(response.data["platform"], "windows")
self.assertEqual(response.data["release"]["version"], "0.1.1")
self.assertEqual(
response.data["release"]["download_url"],
"https://download.example.com/cmhub-0.1.1.zip",
)
self.assertEqual(
response.data["release"]["release_notes"],
"优化了ai模块的生图的功能",
)
self.assertTrue(response.data["release"]["force_update"])
def test_latest_release_ignores_web_session_and_does_not_return_user_data(self):
user = get_user_model().objects.create_user(
username="release-session-user",
@@ -538,6 +572,7 @@ class ClientLatestReleaseApiTests(TestCase):
self.assertEqual(response.status_code, 200)
self.assertIsNone(response.data["release"])
self.assertEqual(response.data["message"], "暂未发布")
self.assertNotIn("force_update", response.data)
def test_latest_release_rejects_invalid_platform(self):
response = self.client.get(f"{self.url}?platform=android")
@@ -572,7 +607,14 @@ class ClientLatestReleaseApiTests(TestCase):
self.assertEqual(set(response.data), {"platform", "release"})
self.assertEqual(
set(response.data["release"]),
{"version", "download_url", "sha256", "release_notes", "published_at"},
{
"version",
"download_url",
"sha256",
"release_notes",
"force_update",
"published_at",
},
)
response_body = json.dumps(response.data, ensure_ascii=False)
for forbidden in (
@@ -590,6 +632,14 @@ class ClientLatestReleaseApiTests(TestCase):
):
self.assertNotIn(forbidden, response_body)
def test_download_release_admin_exposes_force_update(self):
registered_admin = admin.site._registry[DownloadRelease]
self.assertIn("force_update", registered_admin.list_display)
self.assertIn("force_update", registered_admin.list_filter)
version_fields = registered_admin.fieldsets[0][1]["fields"]
self.assertIn("force_update", version_fields)
@override_settings(
PAYMENT_CALLBACK_MODE="mock",
+1
View File
@@ -191,6 +191,7 @@ class ClientLatestReleaseView(APIView):
"download_url": download_url,
"sha256": release.sha256,
"release_notes": release.release_notes,
"force_update": release.force_update,
"published_at": timezone.localtime(release.updated_at).isoformat(),
},
},
+3 -1
View File
@@ -9,11 +9,12 @@ class DownloadReleaseAdmin(admin.ModelAdmin):
"platform",
"version",
"is_current",
"force_update",
"download_source",
"sha256_short",
"updated_at",
)
list_filter = ("platform", "is_current")
list_filter = ("platform", "is_current", "force_update")
search_fields = ("version", "sha256", "external_url", "file")
readonly_fields = ("created_at", "updated_at")
fieldsets = (
@@ -24,6 +25,7 @@ class DownloadReleaseAdmin(admin.ModelAdmin):
"platform",
"version",
"is_current",
"force_update",
"release_notes",
)
},
@@ -0,0 +1,18 @@
# Generated by Django 5.2.15 on 2026-07-08 07:21
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('portal', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='downloadrelease',
name='force_update',
field=models.BooleanField(default=False, verbose_name='强制更新'),
),
]
+1
View File
@@ -25,6 +25,7 @@ class DownloadRelease(models.Model):
],
)
is_current = models.BooleanField("当前版本", default=False)
force_update = models.BooleanField("强制更新", default=False)
release_notes = models.TextField("发布说明", blank=True)
created_at = models.DateTimeField("创建时间", auto_now_add=True)
updated_at = models.DateTimeField("更新时间", auto_now=True)