feat: add client release force update flag
This commit is contained in:
+52
-2
@@ -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",
|
||||
|
||||
@@ -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(),
|
||||
},
|
||||
},
|
||||
|
||||
@@ -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='强制更新'),
|
||||
),
|
||||
]
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user