263 lines
10 KiB
Python
263 lines
10 KiB
Python
"""小程序展示配置:轮播图 / 公告(按俱乐部)。"""
|
|
import os
|
|
import random
|
|
import string
|
|
|
|
from rest_framework.parsers import FormParser, JSONParser, MultiPartParser
|
|
from rest_framework.permissions import IsAuthenticated
|
|
from rest_framework.response import Response
|
|
from rest_framework.views import APIView
|
|
|
|
from backend.utils import verify_kefu_permission
|
|
from jituan.services.club_context import resolve_effective_club_id
|
|
from jituan.services.display_config import (
|
|
forbid_display_write_in_all_scope,
|
|
get_gonggao_content,
|
|
get_lunbo_urls,
|
|
list_response_meta,
|
|
list_tupianpeizhi_by_type,
|
|
LUNBO_PAGE_DASHOU_CENTER,
|
|
LUNBO_PAGE_OPTIONS,
|
|
normalize_page_key,
|
|
TUPIAN_TYPE_LABELS,
|
|
upsert_tupianpeizhi_single,
|
|
)
|
|
from config.models import Gonggao, Lunbo, Tupianpeizhi
|
|
from products.views import delete_from_oss, upload_to_oss, validate_image
|
|
|
|
POPUP_PERM = '8080a'
|
|
|
|
|
|
class ClubLunboListView(APIView):
|
|
"""GET 轮播列表 POST /jituan/houtai/lunbo-list"""
|
|
permission_classes = [IsAuthenticated]
|
|
parser_classes = [JSONParser]
|
|
|
|
def post(self, request):
|
|
phone = (request.data.get('phone') or request.data.get('username') or '').strip()
|
|
if not phone:
|
|
return Response({'code': 401, 'msg': '缺少客服账号'})
|
|
kefu, permissions = verify_kefu_permission(request, phone)
|
|
if kefu is None:
|
|
return permissions
|
|
if POPUP_PERM not in permissions:
|
|
return Response({'code': 403, 'msg': '无权限管理轮播图'})
|
|
|
|
page_key = normalize_page_key(request.data.get('page_key'), image_type=1)
|
|
image_type = 2 if page_key == LUNBO_PAGE_DASHOU_CENTER else 1
|
|
urls = get_lunbo_urls(request, page_key=page_key, image_type=image_type)
|
|
return Response({
|
|
'code': 0,
|
|
'data': {
|
|
'page_key': page_key,
|
|
'list': urls,
|
|
'page_options': [{'key': k, 'label': v} for k, v in LUNBO_PAGE_OPTIONS],
|
|
**list_response_meta(request),
|
|
},
|
|
})
|
|
|
|
|
|
class ClubLunboManageView(APIView):
|
|
"""轮播增删 POST /jituan/houtai/lunbo-manage"""
|
|
permission_classes = [IsAuthenticated]
|
|
parser_classes = [MultiPartParser, FormParser, JSONParser]
|
|
|
|
def post(self, request):
|
|
phone = (request.data.get('phone') or request.data.get('username') or '').strip()
|
|
if not phone:
|
|
return Response({'code': 401, 'msg': '缺少客服账号'})
|
|
kefu, permissions = verify_kefu_permission(request, phone)
|
|
if kefu is None:
|
|
return permissions
|
|
if POPUP_PERM not in permissions:
|
|
return Response({'code': 403, 'msg': '无权限管理轮播图'})
|
|
|
|
deny = forbid_display_write_in_all_scope(request)
|
|
if deny:
|
|
return deny
|
|
|
|
action = (request.data.get('action') or '').strip()
|
|
club_id = resolve_effective_club_id(request, request.user)
|
|
page_key = normalize_page_key(request.data.get('page_key'), image_type=1)
|
|
image_type = 2 if page_key == LUNBO_PAGE_DASHOU_CENTER else 1
|
|
|
|
if action == 'delete':
|
|
tupian_url = (request.data.get('tupian_url') or '').strip()
|
|
if not tupian_url:
|
|
return Response({'code': 400, 'msg': '图片URL不能为空'})
|
|
row = Lunbo.query.filter(
|
|
club_id=club_id, ImageURL=tupian_url, ImageType=image_type, page_key=page_key,
|
|
).first()
|
|
if not row:
|
|
return Response({'code': 404, 'msg': '轮播图不存在'})
|
|
delete_from_oss(tupian_url)
|
|
row.delete()
|
|
return Response({'code': 0, 'msg': '删除成功'})
|
|
|
|
if action == 'add':
|
|
file_obj = request.FILES.get('file')
|
|
if not file_obj:
|
|
return Response({'code': 400, 'msg': '请上传图片'})
|
|
ok, msg = validate_image(file_obj)
|
|
if not ok:
|
|
return Response({'code': 400, 'msg': msg})
|
|
ext = os.path.splitext(file_obj.name)[1].lower() or '.jpg'
|
|
random_str = ''.join(random.choices(string.ascii_lowercase + string.digits, k=6))
|
|
oss_file_path = f"a_long/lunbo/{random_str}{ext}"
|
|
if not upload_to_oss(file_obj, oss_file_path):
|
|
return Response({'code': 500, 'msg': '图片上传失败'})
|
|
Lunbo.query.create(
|
|
club_id=club_id,
|
|
page_key=page_key,
|
|
ImageURL=oss_file_path,
|
|
ImageType=image_type,
|
|
)
|
|
return Response({'code': 0, 'msg': '添加成功', 'data': {'tupian_url': oss_file_path}})
|
|
|
|
return Response({'code': 400, 'msg': 'action 必须为 add 或 delete'})
|
|
|
|
|
|
class ClubGonggaoView(APIView):
|
|
"""公告读写 POST /jituan/houtai/gonggao"""
|
|
permission_classes = [IsAuthenticated]
|
|
parser_classes = [JSONParser]
|
|
|
|
def post(self, request):
|
|
phone = (request.data.get('phone') or request.data.get('username') or '').strip()
|
|
if not phone:
|
|
return Response({'code': 401, 'msg': '缺少客服账号'})
|
|
kefu, permissions = verify_kefu_permission(request, phone)
|
|
if kefu is None:
|
|
return permissions
|
|
if POPUP_PERM not in permissions:
|
|
return Response({'code': 403, 'msg': '无权限管理公告'})
|
|
|
|
notice_type = int(request.data.get('notice_type', 1) or 1)
|
|
club_id = resolve_effective_club_id(request, request.user)
|
|
|
|
content = request.data.get('content')
|
|
if content is None:
|
|
return Response({
|
|
'code': 0,
|
|
'data': {
|
|
'content': get_gonggao_content(request, notice_type=notice_type),
|
|
'notice_type': notice_type,
|
|
**list_response_meta(request),
|
|
},
|
|
})
|
|
|
|
deny = forbid_display_write_in_all_scope(request)
|
|
if deny:
|
|
return deny
|
|
|
|
row, _ = Gonggao.query.get_or_create(
|
|
club_id=club_id,
|
|
NoticeType=notice_type,
|
|
defaults={'Content': content},
|
|
)
|
|
row.Content = content
|
|
row.save(update_fields=['Content', 'UpdateTime'])
|
|
return Response({'code': 0, 'msg': '保存成功'})
|
|
|
|
|
|
class ClubTupianListView(APIView):
|
|
"""杂项图片配置列表 POST /jituan/houtai/tupian-list"""
|
|
permission_classes = [IsAuthenticated]
|
|
parser_classes = [JSONParser]
|
|
|
|
def post(self, request):
|
|
phone = (request.data.get('phone') or request.data.get('username') or '').strip()
|
|
if not phone:
|
|
return Response({'code': 401, 'msg': '缺少客服账号'})
|
|
kefu, permissions = verify_kefu_permission(request, phone)
|
|
if kefu is None:
|
|
return permissions
|
|
if POPUP_PERM not in permissions:
|
|
return Response({'code': 403, 'msg': '无权限管理小程序图片'})
|
|
|
|
club_id = resolve_effective_club_id(request, request.user)
|
|
data = {}
|
|
for t, label in TUPIAN_TYPE_LABELS.items():
|
|
data[str(t)] = {
|
|
'label': label,
|
|
'multi': t == 3,
|
|
'list': list_tupianpeizhi_by_type(club_id, t),
|
|
}
|
|
return Response({
|
|
'code': 0,
|
|
'data': {
|
|
'types': data,
|
|
**list_response_meta(request),
|
|
},
|
|
})
|
|
|
|
|
|
class ClubTupianManageView(APIView):
|
|
"""杂项图片上传/删除 POST /jituan/houtai/tupian-manage"""
|
|
permission_classes = [IsAuthenticated]
|
|
parser_classes = [MultiPartParser, FormParser, JSONParser]
|
|
|
|
def post(self, request):
|
|
phone = (request.data.get('phone') or request.data.get('username') or '').strip()
|
|
if not phone:
|
|
return Response({'code': 401, 'msg': '缺少客服账号'})
|
|
kefu, permissions = verify_kefu_permission(request, phone)
|
|
if kefu is None:
|
|
return permissions
|
|
if POPUP_PERM not in permissions:
|
|
return Response({'code': 403, 'msg': '无权限管理小程序图片'})
|
|
|
|
deny = forbid_display_write_in_all_scope(request)
|
|
if deny:
|
|
return deny
|
|
|
|
action = (request.data.get('action') or '').strip()
|
|
image_type = int(request.data.get('image_type') or 0)
|
|
if image_type not in TUPIAN_TYPE_LABELS:
|
|
return Response({'code': 400, 'msg': 'image_type 无效'})
|
|
|
|
club_id = resolve_effective_club_id(request, request.user)
|
|
|
|
if action == 'delete':
|
|
row_id = request.data.get('id')
|
|
image_url = (request.data.get('image_url') or '').strip()
|
|
qs = Tupianpeizhi.query.filter(club_id=club_id, ImageType=image_type)
|
|
if row_id:
|
|
row = qs.filter(id=row_id).first()
|
|
elif image_url:
|
|
row = qs.filter(ImageURL=image_url).first()
|
|
else:
|
|
return Response({'code': 400, 'msg': '缺少 id 或 image_url'})
|
|
if not row:
|
|
return Response({'code': 404, 'msg': '图片不存在'})
|
|
if row.ImageURL:
|
|
delete_from_oss(row.ImageURL)
|
|
row.delete()
|
|
return Response({'code': 0, 'msg': '删除成功'})
|
|
|
|
if action == 'add':
|
|
file_obj = request.FILES.get('file')
|
|
if not file_obj:
|
|
return Response({'code': 400, 'msg': '请上传图片'})
|
|
ok, msg = validate_image(file_obj)
|
|
if not ok:
|
|
return Response({'code': 400, 'msg': msg})
|
|
ext = os.path.splitext(file_obj.name)[1].lower() or '.jpg'
|
|
random_str = ''.join(random.choices(string.ascii_lowercase + string.digits, k=6))
|
|
folder = 'guanzhu' if image_type == 3 else 'misc'
|
|
oss_file_path = f"beijing/{folder}/{club_id}_{random_str}{ext}"
|
|
if not upload_to_oss(file_obj, oss_file_path):
|
|
return Response({'code': 500, 'msg': '图片上传失败'})
|
|
if image_type in (1, 2):
|
|
upsert_tupianpeizhi_single(club_id, image_type, oss_file_path)
|
|
else:
|
|
Tupianpeizhi.query.create(
|
|
club_id=club_id,
|
|
ImageType=image_type,
|
|
ImageURL=oss_file_path,
|
|
AccessCount=0,
|
|
)
|
|
return Response({'code': 0, 'msg': '上传成功', 'data': {'image_url': oss_file_path}})
|
|
|
|
return Response({'code': 400, 'msg': 'action 必须为 add 或 delete'})
|