from django.db import models from django.utils import timezone class Region(models.Model): """版块/区域表 - 省市区乡镇村层级结构""" LEVEL_CHOICES = [ ('province', '省级'), ('city', '市级'), ('county', '县级'), ('town', '镇级'), ('village', '村级'), ] name = models.CharField('名称', max_length=100) level = models.CharField('级别', max_length=20, choices=LEVEL_CHOICES) parent = models.ForeignKey( 'self', null=True, blank=True, on_delete=models.CASCADE, related_name='children', verbose_name='上级区域' ) code = models.CharField('行政区划代码', max_length=20, blank=True) description = models.TextField('描述', blank=True) created_at = models.DateTimeField('创建时间', auto_now_add=True) updated_at = models.DateTimeField('更新时间', auto_now=True) is_active = models.BooleanField('是否启用', default=True) class Meta: verbose_name = '区域' verbose_name_plural = '区域' ordering = ['level', 'name'] def __str__(self): return f"{self.name} ({self.get_level_display()})" def get_full_path(self): """获取完整路径""" path = [self.name] current = self.parent while current: path.append(current.name) current = current.parent return ' > '.join(reversed(path)) class ModeratorApplication(models.Model): """版主申请表""" STATUS_CHOICES = [ ('pending', '待审核'), ('approved', '已通过'), ('rejected', '已拒绝'), ('cancelled', '已取消'), ] applicant = models.ForeignKey( 'users.User', on_delete=models.CASCADE, related_name='moderator_applications', verbose_name='申请者' ) region = models.ForeignKey( Region, on_delete=models.CASCADE, related_name='moderator_applications', verbose_name='申请区域' ) application_reason = models.TextField('申请理由', blank=True) support_count = models.PositiveIntegerField('支持人数', default=0) required_support = models.PositiveIntegerField('所需支持人数', default=10) deadline = models.DateTimeField('截止时间') status = models.CharField('状态', max_length=20, choices=STATUS_CHOICES, default='pending') reviewer = models.ForeignKey( 'users.User', null=True, blank=True, on_delete=models.SET_NULL, related_name='reviewed_applications', verbose_name='审核人' ) reviewed_at = models.DateTimeField('审核时间', null=True, blank=True) review_comment = models.TextField('审核意见', blank=True) created_at = models.DateTimeField('申请时间', auto_now_add=True) class Meta: verbose_name = '版主申请' verbose_name_plural = '版主申请' ordering = ['-created_at'] def __str__(self): return f"{self.applicant.username} 申请 {self.region.name} 版主" def is_expired(self): return timezone.now() > self.deadline def auto_cancel_if_failed(self): """如果截止且支持人数不足,自动取消""" if self.is_expired() and self.status == 'pending' and self.support_count < self.required_support: self.status = 'cancelled' self.save() return True return False class ModeratorSupport(models.Model): """版主申请支持表""" supporter = models.ForeignKey( 'users.User', on_delete=models.CASCADE, related_name='moderator_supports', verbose_name='支持者' ) application = models.ForeignKey( ModeratorApplication, on_delete=models.CASCADE, related_name='supports', verbose_name='申请' ) created_at = models.DateTimeField('支持时间', auto_now_add=True) class Meta: verbose_name = '支持记录' verbose_name_plural = '支持记录' unique_together = ['supporter', 'application'] def __str__(self): return f"{self.supporter.username} 支持 {self.application}" class ModeratorPermission(models.Model): """版主权限表""" RANK_CHOICES = [ ('general', '将军'), # 省级 ('colonel', '校官'), # 市级 ('lieutenant', '尉官'), # 县级 ('soldier', '士兵'), # 镇村级 ] STATUS_CHOICES = [ ('active', '正常'), ('restricted', '限制'), ('revoked', '取消'), ] moderator = models.ForeignKey( 'users.User', on_delete=models.CASCADE, related_name='moderator_permissions', verbose_name='版主' ) region = models.ForeignKey( Region, on_delete=models.CASCADE, related_name='moderator_permissions', verbose_name='管辖区域' ) rank = models.CharField('军衔', max_length=20, choices=RANK_CHOICES) status = models.CharField('状态', max_length=20, choices=STATUS_CHOICES, default='active') created_at = models.DateTimeField('授权时间', auto_now_add=True) restricted_until = models.DateTimeField('限制截止时间', null=True, blank=True) class Meta: verbose_name = '版主权限' verbose_name_plural = '版主权限' unique_together = ['moderator', 'region'] def __str__(self): return f"{self.moderator.username} - {self.region.name} ({self.get_rank_display()})" def can_moderate(self, content_region): """判断是否可以审核某个区域的内容""" if self.status != 'active': return False # 检查是否在管辖范围内 current = content_region while current: if current.id == self.region.id: return True current = current.parent return False class PermissionRestriction(models.Model): """权限限制表""" operator = models.ForeignKey( 'users.User', on_delete=models.CASCADE, related_name='permission_restrictions_made', verbose_name='操作者' ) restricted_moderator = models.ForeignKey( 'users.User', on_delete=models.CASCADE, related_name='permission_restrictions', verbose_name='被限制版主' ) restriction_type = models.CharField('限制类型', max_length=20, choices=[ ('partial', '部分限制'), ('full', '完全限制'), ]) started_at = models.DateTimeField('限制开始时间', auto_now_add=True) ended_at = models.DateTimeField('限制结束时间', null=True, blank=True) reason = models.TextField('限制原因', blank=True) class Meta: verbose_name = '权限限制' verbose_name_plural = '权限限制' ordering = ['-started_at'] def __str__(self): return f"{self.restricted_moderator.username} 被限制 ({self.restriction_type})"