feat(gerp/mail): 支持用户注册多个企业邮箱,上限 5 个
- MailApply 上限由 1 改 5,超出提示"邮箱数量已达上限" - MyMailbox 返回 MailboxList 数组(按创建时间倒序),替代单 Mailbox - ChangePassword/Login 支持可选 MailboxName 指定目标邮箱,缺省取第一个
This commit is contained in:
1 parent
0302e3a2b2
commit
838b0a18e7
1 file changed
+26
-24
@@ -41,6 +41,8 @@ _MAIL_TOKEN_TTL = 24 * 3600 # token 有效期 24 小时
|
||||
_MAIL_TOKEN_STORE = {} # token -> {"email": str, "password": str, "exp": float}
|
||||
_MAIL_TOKEN_LOCK = threading.Lock()
|
||||
|
||||
_MAILBOX_LIMIT = 5 # 每个用户最多申请的企业邮箱数
|
||||
|
||||
|
||||
def _PurgeMailTokens():
|
||||
"""清理已过期 token。"""
|
||||
@@ -218,9 +220,9 @@ class MailApplyView(ELTAuthenticatedAPIView):
|
||||
if not user_bytes:
|
||||
return Response({'code': 1, 'msg': '无法识别当前用户'}, status=401)
|
||||
|
||||
# 每个用户最多一个邮箱
|
||||
if UserMailbox.objects.filter(UserUUID=request.user).exists():
|
||||
return Response({'code': 1, 'msg': '您已拥有邮箱,一个用户只能申请一个'}, status=400)
|
||||
# 每个用户最多申请 _MAILBOX_LIMIT 个邮箱
|
||||
if UserMailbox.objects.filter(UserUUID=request.user).count() >= _MAILBOX_LIMIT:
|
||||
return Response({'code': 1, 'msg': f'邮箱数量已达上限(最多 {_MAILBOX_LIMIT} 个)'}, status=400)
|
||||
|
||||
mailbox_name = (request.data.get('MailboxName') or '').strip()
|
||||
password = request.data.get('Password') or ''
|
||||
@@ -291,9 +293,11 @@ class MailChangePasswordView(ELTAuthenticatedAPIView):
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def post(self, request):
|
||||
mailbox = UserMailbox.objects.filter(UserUUID=request.user, Status=1).first()
|
||||
mailbox_name = (request.data.get('MailboxName') or '').strip()
|
||||
queryset = UserMailbox.objects.filter(UserUUID=request.user, Status=1)
|
||||
mailbox = queryset.filter(MailboxName=mailbox_name).first() if mailbox_name else queryset.first()
|
||||
if mailbox is None:
|
||||
return Response({'code': 1, 'msg': '您尚未申请邮箱'}, status=404)
|
||||
return Response({'code': 1, 'msg': '未找到该邮箱' if mailbox_name else '您尚未申请邮箱'}, status=404)
|
||||
# 安全:改密必须先验证当前邮箱密码,防止已登录会话被劫持后直接改密
|
||||
old_password = request.data.get('OldPassword') or ''
|
||||
if not old_password:
|
||||
@@ -315,27 +319,23 @@ class MailChangePasswordView(ELTAuthenticatedAPIView):
|
||||
|
||||
|
||||
class MailMyMailboxView(ELTAuthenticatedAPIView):
|
||||
"""我的邮箱信息 + JMAP 连接配置(供浏览器直连)。"""
|
||||
"""我的邮箱列表 + JMAP 连接配置(供浏览器直连)。"""
|
||||
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def get(self, request):
|
||||
mailbox = UserMailbox.objects.filter(UserUUID=request.user).first()
|
||||
session = StalwartMailManager.SessionConfig()
|
||||
if mailbox is None:
|
||||
return Response({'code': 0, 'data': {'Mailbox': None, 'Session': session}})
|
||||
return Response({
|
||||
'code': 0,
|
||||
'data': {
|
||||
'Mailbox': {
|
||||
'MailboxName': mailbox.MailboxName,
|
||||
'QuotaMB': mailbox.QuotaMB,
|
||||
'Status': mailbox.Status,
|
||||
'CreateTime': mailbox.CreateTime.isoformat() if mailbox.CreateTime else None,
|
||||
},
|
||||
'Session': session,
|
||||
},
|
||||
})
|
||||
rows = list(UserMailbox.objects.filter(UserUUID=request.user).order_by('-CreateTime'))
|
||||
mailbox_list = [
|
||||
{
|
||||
'MailboxName': m.MailboxName,
|
||||
'QuotaMB': m.QuotaMB,
|
||||
'Status': m.Status,
|
||||
'CreateTime': m.CreateTime.isoformat() if m.CreateTime else None,
|
||||
}
|
||||
for m in rows
|
||||
]
|
||||
return Response({'code': 0, 'data': {'MailboxList': mailbox_list, 'Session': session}})
|
||||
|
||||
|
||||
class MailAdminListView(ELTAuthenticatedAPIView):
|
||||
@@ -403,16 +403,18 @@ class MailLoginView(ELTAuthenticatedAPIView):
|
||||
密码仅在本次请求明文传输一次;后端校验通过后把凭据存入进程内存,
|
||||
返回 token,后续 JMAP 调用只携带 token(见 MailJmapView)。
|
||||
|
||||
请求体:Password
|
||||
请求体:Password, MailboxName(可选,多邮箱时指定登录哪个;缺省取第一个)
|
||||
响应:{code: 0, data: {Token, MailboxName}}
|
||||
"""
|
||||
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def post(self, request):
|
||||
mailbox = UserMailbox.objects.filter(UserUUID=request.user, Status=1).first()
|
||||
mailbox_name = (request.data.get('MailboxName') or '').strip()
|
||||
queryset = UserMailbox.objects.filter(UserUUID=request.user, Status=1)
|
||||
mailbox = queryset.filter(MailboxName=mailbox_name).first() if mailbox_name else queryset.first()
|
||||
if mailbox is None:
|
||||
return Response({'code': 1, 'msg': '您尚未申请邮箱'}, status=404)
|
||||
return Response({'code': 1, 'msg': '未找到该邮箱' if mailbox_name else '您尚未申请邮箱'}, status=404)
|
||||
password = request.data.get('Password') or ''
|
||||
if not password:
|
||||
return Response({'code': 1, 'msg': '请输入邮箱密码'}, status=400)
|
||||
|
||||
Reference in new issue
Block a user