141 lines
4.7 KiB
Python
141 lines
4.7 KiB
Python
from django.core.exceptions import ValidationError
|
|
from django.core.validators import MinValueValidator, RegexValidator
|
|
from django.db import models, transaction
|
|
|
|
|
|
class DownloadRelease(models.Model):
|
|
class Platform(models.TextChoices):
|
|
WINDOWS = "windows", "Windows"
|
|
MACOS = "macos", "macOS"
|
|
LINUX = "linux", "Linux"
|
|
|
|
platform = models.CharField("平台", max_length=32, choices=Platform.choices)
|
|
version = models.CharField("版本", max_length=64)
|
|
file = models.FileField("安装包文件", upload_to="downloads/", blank=True)
|
|
external_url = models.URLField("外部下载地址", blank=True)
|
|
size_bytes = models.PositiveBigIntegerField(
|
|
"文件大小字节数",
|
|
null=True,
|
|
blank=True,
|
|
validators=[MinValueValidator(1)],
|
|
help_text="客户端下载文件大小,单位字节;桌面端用于下载后校验。",
|
|
)
|
|
sha256 = models.CharField(
|
|
"SHA256",
|
|
max_length=64,
|
|
blank=True,
|
|
validators=[
|
|
RegexValidator(
|
|
regex=r"^[A-Fa-f0-9]{64}$",
|
|
message="SHA256 必须是 64 位十六进制字符。",
|
|
)
|
|
],
|
|
)
|
|
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)
|
|
|
|
class Meta:
|
|
db_table = "download_release"
|
|
verbose_name = "客户端下载版本"
|
|
verbose_name_plural = "客户端下载版本"
|
|
ordering = ("platform", "-is_current", "-created_at", "-id")
|
|
indexes = [
|
|
models.Index(
|
|
fields=("platform", "is_current"),
|
|
name="dl_platform_current_idx",
|
|
),
|
|
]
|
|
|
|
def __str__(self):
|
|
return f"{self.get_platform_display()} {self.version}"
|
|
|
|
@property
|
|
def download_url(self) -> str:
|
|
if self.external_url:
|
|
return self.external_url
|
|
if self.file:
|
|
return self.file.url
|
|
return ""
|
|
|
|
@property
|
|
def has_download(self) -> bool:
|
|
return bool(self.download_url)
|
|
|
|
def clean(self):
|
|
super().clean()
|
|
if not self.file and not self.external_url:
|
|
raise ValidationError("安装包文件和外部下载地址至少填写一个。")
|
|
|
|
def save(self, *args, **kwargs):
|
|
with transaction.atomic():
|
|
super().save(*args, **kwargs)
|
|
if self.is_current:
|
|
type(self).objects.filter(
|
|
platform=self.platform,
|
|
is_current=True,
|
|
).exclude(pk=self.pk).update(is_current=False)
|
|
|
|
|
|
class ImportTemplate(models.Model):
|
|
name = models.CharField("模板名称", max_length=128)
|
|
file = models.FileField("模板文件", upload_to="import_templates/", blank=True)
|
|
external_url = models.URLField("外部下载地址", blank=True)
|
|
sha256 = models.CharField(
|
|
"SHA256",
|
|
max_length=64,
|
|
blank=True,
|
|
validators=[
|
|
RegexValidator(
|
|
regex=r"^[A-Fa-f0-9]{64}$",
|
|
message="SHA256 必须是 64 位十六进制字符。",
|
|
)
|
|
],
|
|
)
|
|
is_current = models.BooleanField("当前模板", default=False)
|
|
notes = models.TextField("说明", blank=True)
|
|
created_at = models.DateTimeField("创建时间", auto_now_add=True)
|
|
updated_at = models.DateTimeField("更新时间", auto_now=True)
|
|
|
|
class Meta:
|
|
db_table = "import_template"
|
|
verbose_name = "导入模板"
|
|
verbose_name_plural = "导入模板"
|
|
ordering = ("-is_current", "-created_at", "-id")
|
|
indexes = [
|
|
models.Index(
|
|
fields=("is_current",),
|
|
name="it_current_idx",
|
|
),
|
|
]
|
|
|
|
def __str__(self):
|
|
return self.name
|
|
|
|
@property
|
|
def download_url(self) -> str:
|
|
if self.external_url:
|
|
return self.external_url
|
|
if self.file:
|
|
return self.file.url
|
|
return ""
|
|
|
|
@property
|
|
def has_download(self) -> bool:
|
|
return bool(self.download_url)
|
|
|
|
def clean(self):
|
|
super().clean()
|
|
if not self.file and not self.external_url:
|
|
raise ValidationError("模板文件和外部下载地址至少填写一个。")
|
|
|
|
def save(self, *args, **kwargs):
|
|
with transaction.atomic():
|
|
super().save(*args, **kwargs)
|
|
if self.is_current:
|
|
type(self).objects.filter(is_current=True).exclude(pk=self.pk).update(
|
|
is_current=False
|
|
)
|