Files

182 lines
6.3 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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})"