feat: 考试集团一览与商品集团权限边界
This commit is contained in:
@@ -39,6 +39,7 @@ from backend.utils import (
|
|||||||
update_shangjia_daily
|
update_shangjia_daily
|
||||||
)
|
)
|
||||||
from jituan.services.club_context import filter_club_char_field, filter_queryset_by_club, filter_user_related_by_club, filter_user_qs_by_club, orders_for_request
|
from jituan.services.club_context import filter_club_char_field, filter_queryset_by_club, filter_user_related_by_club, filter_user_qs_by_club, orders_for_request
|
||||||
|
from jituan.services.catalog_scope import block_non_group_catalog_scope
|
||||||
from jituan.services.club_penalty import (
|
from jituan.services.club_penalty import (
|
||||||
filter_penalty_qs, resolve_penalty_club_id, filter_gsfenhong_qs,
|
filter_penalty_qs, resolve_penalty_club_id, filter_gsfenhong_qs,
|
||||||
forbid_penalty_out_of_scope, resolve_penalty_record_club_id,
|
forbid_penalty_out_of_scope, resolve_penalty_record_club_id,
|
||||||
@@ -1766,6 +1767,9 @@ class GetProductBaseDataView(APIView):
|
|||||||
return permissions
|
return permissions
|
||||||
if '2200a' not in permissions:
|
if '2200a' not in permissions:
|
||||||
return Response({'code': 403, 'msg': '无权限管理商品'})
|
return Response({'code': 403, 'msg': '无权限管理商品'})
|
||||||
|
scope_err = block_non_group_catalog_scope(request)
|
||||||
|
if scope_err:
|
||||||
|
return Response({'code': 400, 'msg': scope_err})
|
||||||
|
|
||||||
# 获取所有商品类型(按 paixu 升序)
|
# 获取所有商品类型(按 paixu 升序)
|
||||||
type_qs = ShangpinLeixing.query.all().order_by('paixu')
|
type_qs = ShangpinLeixing.query.all().order_by('paixu')
|
||||||
@@ -1854,6 +1858,9 @@ class GetProductListView(APIView):
|
|||||||
return permissions
|
return permissions
|
||||||
if '2200a' not in permissions:
|
if '2200a' not in permissions:
|
||||||
return Response({'code': 403, 'msg': '无权限管理商品'})
|
return Response({'code': 403, 'msg': '无权限管理商品'})
|
||||||
|
scope_err = block_non_group_catalog_scope(request)
|
||||||
|
if scope_err:
|
||||||
|
return Response({'code': 400, 'msg': scope_err})
|
||||||
|
|
||||||
# 获取参数
|
# 获取参数
|
||||||
leixing_id = request.data.get('leixing_id')
|
leixing_id = request.data.get('leixing_id')
|
||||||
@@ -1981,6 +1988,9 @@ class GetProductListView(APIView):
|
|||||||
return permissions
|
return permissions
|
||||||
if '2200a' not in permissions:
|
if '2200a' not in permissions:
|
||||||
return Response({'code': 403, 'msg': '无权限管理商品'})
|
return Response({'code': 403, 'msg': '无权限管理商品'})
|
||||||
|
scope_err = block_non_group_catalog_scope(request)
|
||||||
|
if scope_err:
|
||||||
|
return Response({'code': 400, 'msg': scope_err})
|
||||||
|
|
||||||
# 获取所有商品类型(按 paixu 升序)
|
# 获取所有商品类型(按 paixu 升序)
|
||||||
type_qs = ShangpinLeixing.query.all().order_by('paixu')
|
type_qs = ShangpinLeixing.query.all().order_by('paixu')
|
||||||
@@ -2059,6 +2069,9 @@ class GetProductListView(APIView):
|
|||||||
return permissions
|
return permissions
|
||||||
if '2200a' not in permissions:
|
if '2200a' not in permissions:
|
||||||
return Response({'code': 403, 'msg': '无权限管理商品'})
|
return Response({'code': 403, 'msg': '无权限管理商品'})
|
||||||
|
scope_err = block_non_group_catalog_scope(request)
|
||||||
|
if scope_err:
|
||||||
|
return Response({'code': 400, 'msg': scope_err})
|
||||||
|
|
||||||
# 获取参数
|
# 获取参数
|
||||||
leixing_id = request.data.get('leixing_id')
|
leixing_id = request.data.get('leixing_id')
|
||||||
@@ -2180,6 +2193,9 @@ class SaveProductOrderView(APIView):
|
|||||||
return permissions
|
return permissions
|
||||||
if '2200a' not in permissions:
|
if '2200a' not in permissions:
|
||||||
return Response({'code': 403, 'msg': '无权限管理商品'})
|
return Response({'code': 403, 'msg': '无权限管理商品'})
|
||||||
|
scope_err = block_non_group_catalog_scope(request)
|
||||||
|
if scope_err:
|
||||||
|
return Response({'code': 400, 'msg': scope_err})
|
||||||
|
|
||||||
sort_type = request.data.get('type', '').strip().lower()
|
sort_type = request.data.get('type', '').strip().lower()
|
||||||
if sort_type not in ('leixing', 'zhuanqu'):
|
if sort_type not in ('leixing', 'zhuanqu'):
|
||||||
@@ -2242,6 +2258,9 @@ class AddProductView(APIView):
|
|||||||
return permissions
|
return permissions
|
||||||
if '2200a' not in permissions:
|
if '2200a' not in permissions:
|
||||||
return Response({'code': 403, 'msg': '无权限管理商品'})
|
return Response({'code': 403, 'msg': '无权限管理商品'})
|
||||||
|
scope_err = block_non_group_catalog_scope(request)
|
||||||
|
if scope_err:
|
||||||
|
return Response({'code': 400, 'msg': scope_err})
|
||||||
|
|
||||||
# 获取表单字段
|
# 获取表单字段
|
||||||
biaoqian = request.data.get('biaoqian', '').strip()
|
biaoqian = request.data.get('biaoqian', '').strip()
|
||||||
@@ -2439,6 +2458,9 @@ class DeleteProductView(APIView):
|
|||||||
return permissions
|
return permissions
|
||||||
if '2200a' not in permissions:
|
if '2200a' not in permissions:
|
||||||
return Response({'code': 403, 'msg': '无权限管理商品'})
|
return Response({'code': 403, 'msg': '无权限管理商品'})
|
||||||
|
scope_err = block_non_group_catalog_scope(request)
|
||||||
|
if scope_err:
|
||||||
|
return Response({'code': 400, 'msg': scope_err})
|
||||||
|
|
||||||
# 查询商品是否存在
|
# 查询商品是否存在
|
||||||
try:
|
try:
|
||||||
@@ -2501,6 +2523,9 @@ class GetProductDetailView(APIView):
|
|||||||
return permissions
|
return permissions
|
||||||
if '2200a' not in permissions:
|
if '2200a' not in permissions:
|
||||||
return Response({'code': 403, 'msg': '无权限管理商品'})
|
return Response({'code': 403, 'msg': '无权限管理商品'})
|
||||||
|
scope_err = block_non_group_catalog_scope(request)
|
||||||
|
if scope_err:
|
||||||
|
return Response({'code': 400, 'msg': scope_err})
|
||||||
|
|
||||||
# 查询商品
|
# 查询商品
|
||||||
try:
|
try:
|
||||||
@@ -2582,6 +2607,9 @@ class UpdateProductView(APIView):
|
|||||||
return permissions
|
return permissions
|
||||||
if '2200a' not in permissions:
|
if '2200a' not in permissions:
|
||||||
return Response({'code': 403, 'msg': '无权限管理商品'})
|
return Response({'code': 403, 'msg': '无权限管理商品'})
|
||||||
|
scope_err = block_non_group_catalog_scope(request)
|
||||||
|
if scope_err:
|
||||||
|
return Response({'code': 400, 'msg': scope_err})
|
||||||
|
|
||||||
# 使用事务,将 select_for_update 放在事务内
|
# 使用事务,将 select_for_update 放在事务内
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
@@ -4515,6 +4543,9 @@ class GetProductTypeZoneView(APIView):
|
|||||||
return permissions
|
return permissions
|
||||||
if '7007a' not in permissions:
|
if '7007a' not in permissions:
|
||||||
return Response({'code': 403, 'msg': '您无权访问此页面'})
|
return Response({'code': 403, 'msg': '您无权访问此页面'})
|
||||||
|
scope_err = block_non_group_catalog_scope(request)
|
||||||
|
if scope_err:
|
||||||
|
return Response({'code': 400, 'msg': scope_err})
|
||||||
|
|
||||||
# 查询所有商品类型(含专区数量)
|
# 查询所有商品类型(含专区数量)
|
||||||
types = ShangpinLeixing.query.all().order_by('-paixu') # paixu 越大越靠前
|
types = ShangpinLeixing.query.all().order_by('-paixu') # paixu 越大越靠前
|
||||||
@@ -4592,6 +4623,9 @@ class ModifyProductTypeZoneView(APIView):
|
|||||||
return permissions
|
return permissions
|
||||||
if '7007a' not in permissions:
|
if '7007a' not in permissions:
|
||||||
return Response({'code': 403, 'msg': '您无权进行此操作'})
|
return Response({'code': 403, 'msg': '您无权进行此操作'})
|
||||||
|
scope_err = block_non_group_catalog_scope(request)
|
||||||
|
if scope_err:
|
||||||
|
return Response({'code': 400, 'msg': scope_err})
|
||||||
|
|
||||||
if obj_type == 'leixing':
|
if obj_type == 'leixing':
|
||||||
return self.handle_leixing(request, action)
|
return self.handle_leixing(request, action)
|
||||||
|
|||||||
15
jituan/services/catalog_scope.py
Normal file
15
jituan/services/catalog_scope.py
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
"""集团全局商品目录(商品/类型/专区)须在集团汇总视图操作。"""
|
||||||
|
from jituan.constants import DATA_SCOPE_ALL
|
||||||
|
from jituan.services.club_context import resolve_club_scope
|
||||||
|
|
||||||
|
GROUP_CATALOG_SCOPE_MSG = (
|
||||||
|
'商品、类型与专区为集团全局数据,请在顶栏切换为「集团汇总(全部子公司)」后操作;'
|
||||||
|
'具体小程序仅可在「小程序配置」中做上架/图标等俱乐部侧配置。'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def block_non_group_catalog_scope(request):
|
||||||
|
"""非集团汇总视图时返回错误文案,否则返回 None。"""
|
||||||
|
if resolve_club_scope(request) != DATA_SCOPE_ALL:
|
||||||
|
return GROUP_CATALOG_SCOPE_MSG
|
||||||
|
return None
|
||||||
@@ -8,6 +8,7 @@ from django.utils import timezone
|
|||||||
|
|
||||||
from jituan.constants import DATA_SCOPE_ALL
|
from jituan.constants import DATA_SCOPE_ALL
|
||||||
from jituan.models import (
|
from jituan.models import (
|
||||||
|
Club,
|
||||||
ClubDashouExamConfig,
|
ClubDashouExamConfig,
|
||||||
ClubDashouExamPass,
|
ClubDashouExamPass,
|
||||||
ClubDashouExamQuestion,
|
ClubDashouExamQuestion,
|
||||||
@@ -200,6 +201,31 @@ def mark_exam_passed(request, user):
|
|||||||
return {'club_id': club_id, 'passed': True}, None
|
return {'club_id': club_id, 'passed': True}, None
|
||||||
|
|
||||||
|
|
||||||
|
def build_group_exam_overview(request):
|
||||||
|
"""集团汇总视图:各俱乐部考试配置一览。"""
|
||||||
|
if not _scope_blocked(request):
|
||||||
|
return None, '请在集团汇总视图查看各俱乐部概览'
|
||||||
|
rows = []
|
||||||
|
for club in Club.query.filter(status=1).order_by('club_id'):
|
||||||
|
cid = club.club_id
|
||||||
|
cfg = get_or_create_config(cid)
|
||||||
|
pool = ClubDashouExamQuestion.query.filter(club_id=cid).count()
|
||||||
|
enabled_pool = ClubDashouExamQuestion.query.filter(club_id=cid, is_enabled=True).count()
|
||||||
|
passed_count = ClubDashouExamPass.query.filter(club_id=cid).count()
|
||||||
|
rows.append({
|
||||||
|
'club_id': cid,
|
||||||
|
'club_name': club.name or cid,
|
||||||
|
'is_enabled': bool(cfg.is_enabled),
|
||||||
|
'draw_count': int(cfg.draw_count or 10),
|
||||||
|
'pass_count': int(cfg.pass_count or 10),
|
||||||
|
'require_member': bool(cfg.require_member),
|
||||||
|
'pool_count': pool,
|
||||||
|
'enabled_pool_count': enabled_pool,
|
||||||
|
'passed_user_count': passed_count,
|
||||||
|
})
|
||||||
|
return {'list': rows}, None
|
||||||
|
|
||||||
|
|
||||||
def build_admin_config_payload(request):
|
def build_admin_config_payload(request):
|
||||||
if _scope_blocked(request):
|
if _scope_blocked(request):
|
||||||
return {'scope_error': SCOPE_MSG}
|
return {'scope_error': SCOPE_MSG}
|
||||||
|
|||||||
@@ -61,7 +61,16 @@ class DashouExamConfigAdminView(APIView):
|
|||||||
if EXAM_PERM not in permissions:
|
if EXAM_PERM not in permissions:
|
||||||
return Response({'code': 403, 'msg': '无权限'})
|
return Response({'code': 403, 'msg': '无权限'})
|
||||||
action = (request.data.get('action') or 'get').strip()
|
action = (request.data.get('action') or 'get').strip()
|
||||||
from jituan.services.dashou_exam import build_admin_config_payload, save_admin_config
|
from jituan.services.dashou_exam import (
|
||||||
|
build_admin_config_payload,
|
||||||
|
build_group_exam_overview,
|
||||||
|
save_admin_config,
|
||||||
|
)
|
||||||
|
if action == 'overview':
|
||||||
|
data, err = build_group_exam_overview(request)
|
||||||
|
if err:
|
||||||
|
return Response({'code': 400, 'msg': err})
|
||||||
|
return Response({'code': 0, 'data': data})
|
||||||
if action == 'save':
|
if action == 'save':
|
||||||
data, err = save_admin_config(request, request.data)
|
data, err = save_admin_config(request, request.data)
|
||||||
if err:
|
if err:
|
||||||
|
|||||||
Reference in New Issue
Block a user