182 lines
6.3 KiB
Python
182 lines
6.3 KiB
Python
import secrets
|
||
|
||
from django.conf import settings
|
||
from django.db import models
|
||
|
||
|
||
|
||
# GitHub Actions 运行状态 -> 中文展示文案
|
||
STATUS_LABELS = {
|
||
"Starting generator...please wait": "正在启动构建任务",
|
||
"queued": "排队中",
|
||
"in_progress": "构建中",
|
||
"success": "构建成功",
|
||
"failure": "构建失败",
|
||
"cancelled": "已取消",
|
||
"timed_out": "已超时",
|
||
"skipped": "已跳过",
|
||
"action_required": "等待人工处理",
|
||
}
|
||
|
||
# 状态对应的徽标样式(模板中使用)
|
||
STATUS_BADGE = {
|
||
"Starting generator...please wait": "badge-info",
|
||
"queued": "badge-info",
|
||
"in_progress": "badge-info",
|
||
"success": "badge-success",
|
||
"failure": "badge-danger",
|
||
"cancelled": "badge-warning",
|
||
"timed_out": "badge-warning",
|
||
"skipped": "badge-secondary",
|
||
"action_required": "badge-warning",
|
||
}
|
||
|
||
PLATFORM_LABELS = {
|
||
"windows": "Windows 64 位",
|
||
"windows-x86": "Windows 32 位",
|
||
"linux": "Linux",
|
||
"android": "Android",
|
||
"macos": "macOS",
|
||
}
|
||
|
||
|
||
def generate_token_key():
|
||
return secrets.token_hex(20)
|
||
|
||
|
||
class GithubRun(models.Model):
|
||
uuid = models.CharField("任务 UUID", max_length=100, db_index=True)
|
||
status = models.CharField("构建状态", max_length=100, default="queued")
|
||
github_run_id = models.BigIntegerField("GitHub 运行编号", null=True, blank=True)
|
||
# 构建平台:github / gitea;历史任务默认 github。切换平台后旧任务仍按此值查询状态
|
||
backend = models.CharField("构建平台", max_length=20, default="github")
|
||
platform = models.CharField("目标平台", max_length=20, blank=True, default="")
|
||
filename = models.CharField("文件名", max_length=200, blank=True, default="")
|
||
# 提交时的表单快照(纯字符串/数值,图片为 data URL),供失败后「一键重试」重新派发
|
||
config_data = models.JSONField("构建配置快照", blank=True, default=dict)
|
||
created_by = models.ForeignKey(
|
||
settings.AUTH_USER_MODEL,
|
||
verbose_name="提交用户",
|
||
null=True,
|
||
blank=True,
|
||
on_delete=models.SET_NULL,
|
||
related_name="builds",
|
||
)
|
||
created_at = models.DateTimeField("提交时间", auto_now_add=True)
|
||
updated_at = models.DateTimeField("更新时间", auto_now=True)
|
||
|
||
class Meta:
|
||
verbose_name = "构建任务"
|
||
verbose_name_plural = "构建任务"
|
||
ordering = ["-created_at"]
|
||
|
||
def __str__(self):
|
||
return f"{self.filename or self.uuid}({self.status_label()})"
|
||
|
||
def status_label(self):
|
||
return STATUS_LABELS.get(self.status, self.status)
|
||
|
||
def status_badge(self):
|
||
return STATUS_BADGE.get(self.status, "badge-secondary")
|
||
|
||
def platform_label(self):
|
||
return PLATFORM_LABELS.get(self.platform, self.platform or "未知平台")
|
||
|
||
def is_finished(self):
|
||
return self.status in ("success", "failure", "cancelled", "timed_out", "skipped")
|
||
|
||
@property
|
||
def github_log_url(self):
|
||
if self.github_run_id:
|
||
# 局部导入避免循环依赖;按任务记录的平台生成对应站点的日志链接
|
||
from .build_backends import get_backend
|
||
return get_backend(self.backend or 'github').log_url(self.github_run_id)
|
||
return ""
|
||
|
||
@property
|
||
def backend_label(self):
|
||
"""任务所属构建平台的展示名(用于日志链接等文案)。"""
|
||
return "Gitea Actions" if (self.backend or "github") == "gitea" else "GitHub Actions"
|
||
|
||
@property
|
||
def backend_badge_class(self):
|
||
"""任务所属构建平台对应的徽章样式类。"""
|
||
return "badge-gitea" if (self.backend or "github") == "gitea" else "badge-github"
|
||
|
||
def short_uuid(self):
|
||
return self.uuid[:8] if len(self.uuid) >= 8 else self.uuid
|
||
|
||
|
||
class SiteSetting(models.Model):
|
||
"""后台可改的站点配置(键值存储)。
|
||
|
||
取值优先级由 app_settings 统一处理:后台配置(本表)→ 环境变量 → 默认值,
|
||
因此历史的环境变量部署方式继续有效。
|
||
"""
|
||
|
||
key = models.CharField("配置项", max_length=50, primary_key=True)
|
||
value = models.TextField("配置值", blank=True, default='')
|
||
updated_at = models.DateTimeField("更新时间", auto_now=True)
|
||
|
||
class Meta:
|
||
verbose_name = "站点配置"
|
||
verbose_name_plural = "站点配置"
|
||
|
||
def __str__(self):
|
||
return self.key
|
||
|
||
|
||
class SavedConfig(models.Model):
|
||
"""用户保存的客户端构建配置方案(与账号绑定,可在定制页直接载入、可导出/导入)。"""
|
||
|
||
owner = models.ForeignKey(
|
||
settings.AUTH_USER_MODEL,
|
||
verbose_name="所属用户",
|
||
on_delete=models.CASCADE,
|
||
related_name="saved_configs",
|
||
)
|
||
name = models.CharField("方案名称", max_length=100)
|
||
data = models.JSONField("配置内容", default=dict)
|
||
created_at = models.DateTimeField("创建时间", auto_now_add=True)
|
||
updated_at = models.DateTimeField("更新时间", auto_now=True)
|
||
|
||
class Meta:
|
||
verbose_name = "构建配置方案"
|
||
verbose_name_plural = "构建配置方案"
|
||
unique_together = [('owner', 'name')]
|
||
ordering = ["-updated_at"]
|
||
|
||
def __str__(self):
|
||
return f"{self.name}({self.owner})"
|
||
|
||
def platform_label(self):
|
||
return PLATFORM_LABELS.get(self.data.get('platform', ''), '未指定平台')
|
||
|
||
@property
|
||
def version_label(self):
|
||
return self.data.get('version', '') or '未指定版本'
|
||
|
||
|
||
class ApiToken(models.Model):
|
||
"""供 JSON API(如 rdgen-cli)使用的个人访问令牌"""
|
||
|
||
key = models.CharField("令牌", max_length=64, primary_key=True, default=generate_token_key, editable=False)
|
||
name = models.CharField("令牌名称", max_length=100, help_text="便于识别用途,例如:CI 构建机")
|
||
user = models.ForeignKey(
|
||
settings.AUTH_USER_MODEL,
|
||
verbose_name="所属用户",
|
||
on_delete=models.CASCADE,
|
||
related_name="api_tokens",
|
||
)
|
||
is_active = models.BooleanField("启用", default=True)
|
||
created_at = models.DateTimeField("创建时间", auto_now_add=True)
|
||
last_used_at = models.DateTimeField("最后使用时间", null=True, blank=True)
|
||
|
||
class Meta:
|
||
verbose_name = "API 令牌"
|
||
verbose_name_plural = "API 令牌"
|
||
ordering = ["-created_at"]
|
||
|
||
def __str__(self):
|
||
return f"{self.name}({self.user})"
|