215 lines
7.0 KiB
Python
215 lines
7.0 KiB
Python
|
|
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})"
|