feat: 考试权限dsks666、页面内切俱乐部、商品板块仅集团可改
This commit is contained in:
@@ -6,7 +6,8 @@ import uuid
|
||||
|
||||
from django.utils import timezone
|
||||
|
||||
from jituan.constants import DATA_SCOPE_ALL
|
||||
from jituan.services.admin_context import build_admin_club_context
|
||||
from jituan.constants import CLUB_ID_DEFAULT, DATA_SCOPE_ALL
|
||||
from jituan.models import (
|
||||
Club,
|
||||
ClubDashouExamConfig,
|
||||
@@ -26,10 +27,54 @@ from utils.oss_utils import delete_from_oss, upload_to_oss, validate_image
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
SCOPE_MSG = '请切换到具体小程序/俱乐部后再操作'
|
||||
EXAM_MANAGE_PERMS = frozenset({'dsks666', '8080a'})
|
||||
OPTION_FIELDS = [f'option_{i}' for i in range(1, 7)]
|
||||
CORRECT_FIELDS = [f'correct_{i}' for i in range(1, 7)]
|
||||
|
||||
|
||||
def has_exam_manage_perm(permissions):
|
||||
return any(code in permissions for code in EXAM_MANAGE_PERMS)
|
||||
|
||||
|
||||
def resolve_exam_target_club_id(request, user, data=None):
|
||||
"""
|
||||
后台考试管理目标俱乐部。
|
||||
优先 request 中的 target_club_id,须在用户可见俱乐部列表内。
|
||||
集团身份可在页面内切换俱乐部,不依赖顶栏视图。
|
||||
"""
|
||||
payload = data if data is not None else (getattr(request, 'data', None) or {})
|
||||
target = (payload.get('target_club_id') or payload.get('club_id') or '').strip()
|
||||
ctx = build_admin_club_context(user)
|
||||
visible_ids = {c['club_id'] for c in ctx.get('clubs', [])}
|
||||
|
||||
if target:
|
||||
if target not in visible_ids:
|
||||
return None, '无权管理该俱乐部的考试'
|
||||
return target, None
|
||||
|
||||
if ctx.get('scope') == DATA_SCOPE_ALL:
|
||||
default = (ctx.get('club_id') or CLUB_ID_DEFAULT).strip()
|
||||
if default in visible_ids:
|
||||
return default, None
|
||||
if visible_ids:
|
||||
return sorted(visible_ids)[0], None
|
||||
return None, '请选择俱乐部'
|
||||
|
||||
club_id = resolve_club_id_from_request(request)
|
||||
if club_id not in visible_ids:
|
||||
return None, '无权管理该俱乐部的考试'
|
||||
return club_id, None
|
||||
|
||||
|
||||
def exam_admin_clubs_payload(user):
|
||||
ctx = build_admin_club_context(user)
|
||||
return {
|
||||
'clubs': ctx.get('clubs', []),
|
||||
'can_switch_club': bool(ctx.get('can_switch_club')),
|
||||
'is_group_admin': bool(ctx.get('is_group_admin')),
|
||||
}
|
||||
|
||||
|
||||
def _scope_blocked(request):
|
||||
return resolve_club_scope(request) == DATA_SCOPE_ALL
|
||||
|
||||
@@ -226,14 +271,16 @@ def build_group_exam_overview(request):
|
||||
return {'list': rows}, None
|
||||
|
||||
|
||||
def build_admin_config_payload(request):
|
||||
if _scope_blocked(request):
|
||||
return {'scope_error': SCOPE_MSG}
|
||||
club_id = resolve_club_id_from_request(request)
|
||||
def build_admin_config_payload(request, user, data=None):
|
||||
clubs_info = exam_admin_clubs_payload(user)
|
||||
club_id, err = resolve_exam_target_club_id(request, user, data)
|
||||
if err:
|
||||
return {**clubs_info, 'scope_error': err}
|
||||
cfg = get_or_create_config(club_id)
|
||||
pool = ClubDashouExamQuestion.query.filter(club_id=club_id).count()
|
||||
enabled_pool = ClubDashouExamQuestion.query.filter(club_id=club_id, is_enabled=True).count()
|
||||
return {
|
||||
**clubs_info,
|
||||
'club_id': club_id,
|
||||
'config': config_to_dict(cfg),
|
||||
'pool_count': pool,
|
||||
@@ -241,10 +288,10 @@ def build_admin_config_payload(request):
|
||||
}
|
||||
|
||||
|
||||
def save_admin_config(request, data):
|
||||
if _scope_blocked(request):
|
||||
return None, SCOPE_MSG
|
||||
club_id = club_id_for_write(request)
|
||||
def save_admin_config(request, user, data):
|
||||
club_id, err = resolve_exam_target_club_id(request, user, data)
|
||||
if err:
|
||||
return None, err
|
||||
draw = int(data.get('draw_count') or 10)
|
||||
pass_cnt = int(data.get('pass_count') or draw)
|
||||
if draw < 1:
|
||||
@@ -260,10 +307,10 @@ def save_admin_config(request, data):
|
||||
return config_to_dict(cfg), None
|
||||
|
||||
|
||||
def list_admin_questions(request):
|
||||
if _scope_blocked(request):
|
||||
return {'list': [], 'scope_error': SCOPE_MSG}
|
||||
club_id = resolve_club_id_from_request(request)
|
||||
def list_admin_questions(request, user, data=None):
|
||||
club_id, err = resolve_exam_target_club_id(request, user, data)
|
||||
if err:
|
||||
return {**exam_admin_clubs_payload(user), 'list': [], 'scope_error': err}
|
||||
rows = ClubDashouExamQuestion.query.filter(club_id=club_id).order_by('-sort_order', 'id')
|
||||
out = []
|
||||
for q in rows:
|
||||
@@ -274,16 +321,16 @@ def list_admin_questions(request):
|
||||
).order_by('sort_order', 'id')
|
||||
]
|
||||
out.append(question_to_admin_dict(q, imgs))
|
||||
return {'club_id': club_id, 'list': out}
|
||||
return {**exam_admin_clubs_payload(user), 'club_id': club_id, 'list': out}
|
||||
|
||||
|
||||
def create_question(request, data):
|
||||
if _scope_blocked(request):
|
||||
return None, SCOPE_MSG
|
||||
def create_question(request, user, data):
|
||||
club_id, err = resolve_exam_target_club_id(request, user, data)
|
||||
if err:
|
||||
return None, err
|
||||
err = validate_question_payload(data)
|
||||
if err:
|
||||
return None, err
|
||||
club_id = club_id_for_write(request)
|
||||
q = ClubDashouExamQuestion.query.create(
|
||||
club_id=club_id,
|
||||
stem=data.get('stem', '').strip(),
|
||||
@@ -297,10 +344,10 @@ def create_question(request, data):
|
||||
return {'id': q.id}, None
|
||||
|
||||
|
||||
def update_question(request, question_id, data):
|
||||
if _scope_blocked(request):
|
||||
return None, SCOPE_MSG
|
||||
club_id = club_id_for_write(request)
|
||||
def update_question(request, user, question_id, data):
|
||||
club_id, err = resolve_exam_target_club_id(request, user, data)
|
||||
if err:
|
||||
return None, err
|
||||
try:
|
||||
q = ClubDashouExamQuestion.query.get(id=question_id, club_id=club_id)
|
||||
except ClubDashouExamQuestion.DoesNotExist:
|
||||
@@ -324,10 +371,10 @@ def update_question(request, question_id, data):
|
||||
return {'id': q.id}, None
|
||||
|
||||
|
||||
def delete_question(request, question_id):
|
||||
if _scope_blocked(request):
|
||||
return None, SCOPE_MSG
|
||||
club_id = club_id_for_write(request)
|
||||
def delete_question(request, user, question_id, data=None):
|
||||
club_id, err = resolve_exam_target_club_id(request, user, data)
|
||||
if err:
|
||||
return None, err
|
||||
try:
|
||||
q = ClubDashouExamQuestion.query.get(id=question_id, club_id=club_id)
|
||||
except ClubDashouExamQuestion.DoesNotExist:
|
||||
@@ -340,10 +387,10 @@ def delete_question(request, question_id):
|
||||
return {'id': question_id}, None
|
||||
|
||||
|
||||
def upload_question_image(request, question_id, file_obj):
|
||||
if _scope_blocked(request):
|
||||
return None, SCOPE_MSG
|
||||
club_id = club_id_for_write(request)
|
||||
def upload_question_image(request, user, question_id, file_obj, data=None):
|
||||
club_id, err = resolve_exam_target_club_id(request, user, data)
|
||||
if err:
|
||||
return None, err
|
||||
if not ClubDashouExamQuestion.query.filter(id=question_id, club_id=club_id).exists():
|
||||
return None, '题目不存在'
|
||||
ok, msg = validate_image(file_obj)
|
||||
@@ -364,10 +411,10 @@ def upload_question_image(request, question_id, file_obj):
|
||||
return {'id': row.id, 'image_url': oss_path}, None
|
||||
|
||||
|
||||
def delete_question_image(request, image_id):
|
||||
if _scope_blocked(request):
|
||||
return None, SCOPE_MSG
|
||||
club_id = club_id_for_write(request)
|
||||
def delete_question_image(request, user, image_id, data=None):
|
||||
club_id, err = resolve_exam_target_club_id(request, user, data)
|
||||
if err:
|
||||
return None, err
|
||||
try:
|
||||
img = ClubDashouExamQuestionImage.query.get(id=image_id, club_id=club_id)
|
||||
except ClubDashouExamQuestionImage.DoesNotExist:
|
||||
|
||||
Reference in New Issue
Block a user