<commit_before>import logging
import datetime

# django modules
from django.core.files.base import ContentFile
from django.shortcuts import render, redirect, get_object_or_404
from django.http import HttpResponse, JsonResponse
from django.views.decorators.http import require_POST
from django.views.generic import View, TemplateView, ListView
from django.utils.decorators import method_decorator
from django.contrib import auth
from django.db.models import Q
from django.utils import timezone
from rest_framework.renderers import JSONRenderer

import json

# local modules
from app import models
from app.utils import smsUtil
from app.utils.types import parseInt
from app.utils.db import paginate
from .decorators import mala_staff_required, is_manager


logger = logging.getLogger('app')

# Create your views here.

@mala_staff_required
def index(request):
    return render(request, 'staff/index.html')

def login(request, context={}):
    if is_manager(request.user):
        return redirect('staff:index')
    return render(request, 'staff/login.html', context)

def logout(request):
    auth.logout(request)
    return redirect('staff:login')

@require_POST
def login_auth(request):
    username = request.POST.get('username')
    password = request.POST.get('password')
    goto_page = request.POST.get('next')
    logger.debug('try to login, username: '+username+', password: '+password+', goto_page: '+str(goto_page))
    # TODO: 错误信息包含‘错误码’，错误描述可能会变
    if not username or not password:
        return login(request, {'errors': '请输入用户名和密码'})
    #登录前需要先验证
    newUser=auth.authenticate(username=username,password=password)
    if newUser is not None:
        if not is_manager(newUser):
            return login(request, {'errors': '你不是管理员呀'})
        auth.login(request, newUser)
        if goto_page:
            return redirect(goto_page)
        else:
            return redirect('staff:index')
    return login(request, {'errors': '用户名或密码错误'})



class BaseStaffView(TemplateView):
    """
    Base view for staff management page views.
    """

    @method_decorator(mala_staff_required)
    def dispatch(self, request, *args, **kwargs):
        return super(BaseStaffView, self).dispatch(request, *args, **kwargs)


class BaseStaffActionView(View):
    """
    Base view for staff management action views.
    """

    defaultErrMeg = "操作失败,请稍后重试或联系管理员"

    # @method_decorator(csrf_exempt) # 不加csrf,不允许跨域访问
    @method_decorator(mala_staff_required)
    def dispatch(self, request, *args, **kwargs):
        return super(BaseStaffActionView, self).dispatch(request, *args, **kwargs)


#因为使用了listView而无法直接继承BaseStaffView
@method_decorator(mala_staff_required, name='dispatch')
class CouponsListView(ListView):
    model = models.Coupon
    template_name = 'staff/coupon/coupons_list.html'
    context_object_name = 'coupons_list'
    paginate_by = 10

    def get_context_data(self, **kwargs):
        context = super(CouponsListView, self).get_context_data(**kwargs)
        kwargs['statusList'] = [
            {'text':"状态",'value':""},
            {'text':"已使用",'value':"used"},
            {'text':"未使用",'value':"unused"},
            {'text':"已过期",'value':"expired"},
                                ]
        kwargs['typesList'] = [
            {'text':"类型",'value':""},
            {'text':"注册",'value':"reg"},
            {'text':"抽奖",'value':"lotto"},
                                ]
        kwargs['name'] = self.request.GET.get('name',None)
        kwargs['phone'] = self.request.GET.get('phone',None)
        kwargs['dateFrom'] = self.request.GET.get('dateFrom',None)
        kwargs['dateTo'] = self.request.GET.get('dateTo',None)
        kwargs['type'] = self.request.GET.get('type',None)
        kwargs['status'] = self.request.GET.get('status',None)
        return super(CouponsListView, self).get_context_data(**kwargs)

    def get_queryset(self):
        coupons_list = self.model.objects.all()
        #TODO:用字典循环取值
        # for keyword in ['name','phone','dateFrom','dateTo','type','status']:
        #     cmd = "%s = self.request.GET.get('%s',None)" % (keyword,keyword)
        #     exec(cmd)
        #     print(name)
        name = self.request.GET.get('name',None)
        phone = self.request.GET.get('phone',None)
        dateFrom = self.request.GET.get('dateFrom',None)
        dateTo = self.request.GET.get('dateTo',None)
        type = self.request.GET.get('type',None)
        status = self.request.GET.get('status',None)

        if name:
            coupons_list = coupons_list.filter(parent__user__username__icontains=name)
        if phone:
            coupons_list = coupons_list.filter(parent__user__profile__phone__contains=phone)
        if dateFrom and dateTo:
            coupons_list = coupons_list.filter(created_at__range=(dateFrom, dateTo))
        if type == 'reg':
            pass
        if type == 'reg':
            pass
        if status == 'used':
            coupons_list = coupons_list.filter(used = True)
        if status == 'unused':
            now = timezone.now()
            coupons_list = coupons_list.filter(used = False).exclude(expired_at__lt = now)
        if status == 'expired':
            now = timezone.now()
            coupons_list = coupons_list.filter(used = False).filter(expired_at__lt = now)
        return coupons_list


class TeacherView(BaseStaffView):
    template_name = 'staff/teacher/teachers.html'

    def get_context_data(self, **kwargs):
        # 把查询参数数据放到kwargs['query_data'], 以便template回显
        kwargs['query_data'] = self.request.GET.dict()
        #
        name = self.request.GET.get('name')
        phone = self.request.GET.get('phone')
        status = self.request.GET.get('status')
        reg_date_from = self.request.GET.get('reg_date_from')
        reg_date_to = self.request.GET.get('reg_date_to')
        region = self.request.GET.get('region')
        page = self.request.GET.get('page')
        query_set = models.Teacher.objects.filter()
        if name:
            query_set = query_set.filter(name__icontains = name)
        if phone:
            query_set = query_set.filter(user__profile__phone__contains = phone)
        if status and status.isdigit():
            query_set = query_set.filter(status = status)
        if reg_date_from:
            try:
                date_from = datetime.datetime.strptime(reg_date_from, '%Y-%m-%d')
                query_set = query_set.filter(user__date_joined__gte = date_from)
            except:
                pass
        if reg_date_to:
            try:
                date_to = datetime.datetime.strptime(reg_date_to, '%Y-%m-%d')
                date_to += datetime.timedelta(days=1)
                query_set = query_set.filter(user__date_joined__lte = date_to)
            except:
                pass
        if region and region.isdigit():
            query_set = query_set.filter(region_id = region)
        query_set = query_set.order_by('-user__date_joined')
        # paginate
        query_set, pager = paginate(query_set, page)
        kwargs['teachers'] = query_set
        kwargs['pager'] = pager
        # 一些固定数据
        kwargs['status_choices'] = models.Teacher.STATUS_CHOICES
        kwargs['region_list'] = models.Region.objects.filter(Q(opened=True)|Q(name='其他'))
        return super(TeacherView, self).get_context_data(**kwargs)


class TeacherUnpublishedView(BaseStaffView):
    """
    待上架老师列表view
    """
    template_name = 'staff/teacher/teachers_unpublished.html'
    list_type = 'unpublished'

    def get_context_data(self, **kwargs):
        kwargs['list_type'] = self.list_type
        # 把查询参数数据放到kwargs['query_data'], 以便template回显
        kwargs['query_data'] = self.request.GET.dict()
        #
        name = self.request.GET.get('name') and self.request.GET.get('name').strip() or ''
        phone = self.request.GET.get('phone') and self.request.GET.get('phone').strip() or ''
        # province = self.request.GET.get('province')
        # city = self.request.GET.get('city')
        # district = self.request.GET.get('district')
        # region = district and district or city and city or province
        region = self.request.GET.get('region')
        grade = self.request.GET.get('grade') and self.request.GET.get('grade').strip() or ''
        subject = self.request.GET.get('subject') and self.request.GET.get('subject').strip() or ''
        level = self.request.GET.get('level') and self.request.GET.get('level').strip() or ''
        page = self.request.GET.get('page') and self.request.GET.get('page').strip() or ''
        for_published = self.list_type == 'published'
        query_set = models.Teacher.objects.filter(status=models.Teacher.INTERVIEW_OK, published=for_published)
        if name:
            query_set = query_set.filter(name__icontains = name)
        if phone:
            query_set = query_set.filter(user__profile__phone__contains = phone)
        if region:
            query_set = query_set.filter(region_id=region)
        if grade:
            query_set = query_set.filter(Q(abilities__grade_id=grade) | Q(abilities__grade__superset_id=grade))
        if subject:
            query_set = query_set.filter(abilities__subject_id=subject)
        if level:
            query_set = query_set.filter(level_id=level)
        query_set = query_set.order_by('id')
        # paginate
        query_set, pager = paginate(query_set, page)
        kwargs['teachers'] = query_set
        kwargs['pager'] = pager
        # 一些固定数据
        # kwargs['provinces'] = models.Region.objects.filter(superset_id__isnull=True)
        kwargs['region_list'] = models.Region.objects.filter(Q(opened=True)|Q(name='其他'))
        kwargs['grades'] = models.Grade.objects.filter(superset_id__isnull=True)
        kwargs['subjects'] = models.Subject.objects.all
        kwargs['levels'] = models.Level.objects.all
        return super(TeacherUnpublishedView, self).get_context_data(**kwargs)


class TeacherPublishedView(TeacherUnpublishedView):
    """
    已上架老师列表view
    """
    list_type = 'published'
    def get_context_data(self, **kwargs):
        return super(TeacherPublishedView, self).get_context_data(**kwargs)


class TeacherUnpublishedEditView(BaseStaffView):
    """
    待上架老师编辑页面view
    """
    template_name = 'staff/teacher/teachers_unpublished_edit.html'

    def get_context_data(self, **kwargs):
        teacherId = kwargs['tid']
        teacher = get_object_or_404(models.Teacher, id=teacherId)
        kwargs['teacher'] = teacher
        # 老师科目年级
        curSubject = teacher.subject()
        if curSubject:
            kwargs['grade_ids_range'] = models.Ability.objects.filter(subject=curSubject).values_list('grade_id', flat=True)
        kwargs['teacher_grade_ids'] = [grade.id for grade in teacher.grades()]
        # 证书数据
        certification_all = models.Certificate.objects.filter(teacher=teacher)
        cert_others = []
        for cert in certification_all:
            if cert.type == models.Certificate.ID_HELD:
                kwargs['cert_id_held'] = cert
            elif cert.type == models.Certificate.ID_FRONT:
                kwargs['cert_id_front'] = cert
            elif cert.type == models.Certificate.ACADEMIC:
                kwargs['cert_academic'] = cert
            elif cert.type == models.Certificate.TEACHING:
                kwargs['cert_teaching'] = cert
            elif cert.type == models.Certificate.ENGLISH:
                kwargs['cert_english'] = cert
            else:
                cert_others.append(cert)
        kwargs['cert_others'] = cert_others
        # 地区数据
        region_dict = teacher.region and teacher.region.make_dict() or None
        kwargs['region_dict'] = region_dict
        kwargs['provinces'] = models.Region.objects.filter(superset_id__isnull=True)
        if region_dict and region_dict.get('city'):
            kwargs['cities'] = models.Region.objects.filter(superset_id=region_dict.get('city').superset_id)
        if region_dict and region_dict.get('district'):
            kwargs['districts'] = models.Region.objects.filter(superset_id=region_dict.get('district').superset_id)
        # 一些固定数据
        kwargs['gender_choices'] = models.Profile.GENDER_CHOICES
        kwargs['subjects'] = models.Subject.objects.all
        kwargs['levels'] = models.Level.objects.all
        grades_all = models.Grade.objects.all()
        _heap = {}
        grades_tree = []
        for grade in grades_all:
            if not grade.superset_id:
                _temp = {'id':grade.id, 'name':grade.name, 'children':[]}
                _heap[grade.id] = _temp
                grades_tree.append(_temp)
            else:
                _temp = _heap[grade.superset_id]
                _temp['children'].append({'id':grade.id, 'name':grade.name})
        kwargs['grades_tree'] = grades_tree
        kwargs['tags_all'] = models.Tag.objects.all
        return super(TeacherUnpublishedEditView, self).get_context_data(**kwargs)

    def post(self, request, tid):
        teacher = get_object_or_404(models.Teacher, id=tid)
        try:
            # 获取参数, 并检验
            newSubjectId = parseInt(request.POST.get('subject'), False)
            if not newSubjectId:
                return JsonResponse({'ok': False, 'msg': '请选择科目', 'code': 1})
            newGradeIds = request.POST.getlist('grade')
            if not newGradeIds:
                return JsonResponse({'ok': False, 'msg': '请选择年级', 'code': -1})
            newTagIds  = request.POST.getlist('tag')
            if not newTagIds or len(newTagIds)>3:
                return JsonResponse({'ok': False, 'msg': '风格标记 (最少选一个，最多选3个)', 'code': -1})
            certIdHeld, created = models.Certificate.objects.get_or_create(teacher=teacher, type=models.Certificate.ID_HELD,
                                                                  defaults={'name':"",'verified':False})
            profile = teacher.user.profile
            # 基本信息
            teacher.name = request.POST.get('name')
            certIdHeld.name = request.POST.get('id_num')
            profile.phone = request.POST.get('phone')
            profile.gender = request.POST.get('gender')
            province = request.POST.get('province')
            city = request.POST.get('city')
            district = request.POST.get('district')
            region = district and district or city and city or province
            region = parseInt(region, None)
            if not region:
                teacher.region = None
            else:
                teacher.region_id = region
            teacher.teaching_age = parseInt(request.POST.get('teaching_age'), 0)
            teacher.level_id = parseInt(request.POST.get('level'), 1)
            teacher.experience = parseInt(request.POST.get('experience'), 0)
            teacher.profession = parseInt(request.POST.get('profession'), 0)
            teacher.interaction = parseInt(request.POST.get('interaction'), 0)
            certIdHeld.save()
            # 科目年级 & 风格标签
            teacher.abilities.clear()
            ability_set = models.Ability.objects.filter(subject_id=newSubjectId, grade_id__in=newGradeIds)
            for ability in ability_set:
                teacher.abilities.add(ability)
            teacher.tags.clear()
            tag_set = models.Tag.objects.filter(id__in=newTagIds)
            for tag in tag_set:
                teacher.tags.add(tag)
            teacher.save()
            # 头像 & 照片
            avatarImg = None
            if request.FILES:
                avatarImg = request.FILES.get('avatarImg')
            if avatarImg:
                _img_content = ContentFile(avatarImg.read())
                profile.avatar.save("avatar"+str(teacher.id)+'_'+str(_img_content.size), _img_content)
            else:
                if request.POST.get('toDeleteAvatar'):
                    profile.avatar.delete()
            profile.save()
            stayPhotoIds = request.POST.getlist('photoId')
            stayPhotoIds = [i for i in stayPhotoIds if i]
            newPhotoImgs = request.FILES.getlist('photoImg')
            models.Photo.objects.filter(teacher_id=teacher.id).exclude(id__in=stayPhotoIds).delete()
            for photoImg in newPhotoImgs:
                photo = models.Photo(teacher=teacher, public=True)
                _img_content = ContentFile(photoImg.read())
                photo.img.save("photo"+str(teacher.id)+'_'+str(_img_content.size), _img_content)
                photo.save()
            # 提分榜
            allHsIds = request.POST.getlist('highscoreId')
            stayHsIds = [s for s in allHsIds if s and (not s.startswith('new'))]
            newHsIds = [s for s in allHsIds if s.startswith('new')]
            models.Highscore.objects.filter(teacher_id=teacher.id).exclude(id__in=stayHsIds).delete()
            for hsId in newHsIds:
                name = request.POST.get(hsId+'name')
                scores = request.POST.get(hsId+'scores')
                school_from = request.POST.get(hsId+'from')
                school_to = request.POST.get(hsId+'to')
                highscore = models.Highscore(teacher=teacher, name=name, increased_scores=scores,
                                             school_name=school_from, admitted_to=school_to)
                highscore.save()
            ### 认证
            # 身份认证
            certIdHeldOk = request.POST.get('certIdHeldOk')
            if certIdHeldOk and certIdHeldOk=='True':
                certIdHeld.verified = True
            else:
                certIdHeld.verified = False
            certIdHeldImg = None
            if request.FILES:
                certIdHeldImg = request.FILES.get('certIdHeldImg')
            if certIdHeldImg:
                _img_content = ContentFile(certIdHeldImg.read())
                certIdHeld.img.save("idHeld"+str(teacher.id)+'_'+str(_img_content.size), _img_content)
            else:
                if request.POST.get('toDeleteCertIdHeld'):
                    certIdHeld.img.delete()
            if not certIdHeld.img:
                certIdHeld.verified = False
            certIdFront, created = models.Certificate.objects.get_or_create(teacher=teacher, type=models.Certificate.ID_FRONT,
                                                              defaults={'name':"",'verified':False})
            certIdFrontImg = None
            if request.FILES:
                certIdFrontImg = request.FILES.get('certIdFrontImg')
            if certIdFrontImg:
                _img_content = ContentFile(certIdFrontImg.read())
                certIdFront.img.save("IdFront"+str(teacher.id)+'_'+str(_img_content.size), _img_content)
            else:
                if request.POST.get('toDeleteCertIdFront'):
                    certIdFront.img.delete()
            if not certIdFront.img:
                certIdHeld.verified = False
            certIdFront.save()
            certIdHeld.save()
            # 学历, 教师资格证,英语水平
            self.postSaveCert(request, teacher, models.Certificate.ACADEMIC, 'Academic')
            self.postSaveCert(request, teacher, models.Certificate.TEACHING, 'Teaching')
            self.postSaveCert(request, teacher, models.Certificate.ENGLISH, 'English')
            # 其他认证
            allCertOtherIds = request.POST.getlist('certOtherId')
            stayCertOtherIds = [s for s in allCertOtherIds if s and (not s.startswith('new'))]
            newCertOtherIds = [s for s in allCertOtherIds if s.startswith('new')]
            models.Certificate.objects.filter(teacher=teacher, type=models.Certificate.OTHER)\
                .exclude(id__in=stayCertOtherIds).delete()
            for certId in stayCertOtherIds:
                name = request.POST.get(certId+'certName')
                certOk = request.POST.get(certId+'certOk')
                certImg = None
                if request.FILES:
                    certImg = request.FILES.get(certId+'certImg')
                cert = models.Certificate.objects.get(id=certId)
                cert.name = name
                if certOk and certOk=='True':
                    cert.verified = True
                else:
                    cert.verified = False
                if certImg:
                    _img_content = ContentFile(certImg.read())
                    cert.img.save("certOther"+str(teacher.id)+'_'+str(_img_content.size), _img_content)
                cert.save()
            for certId in newCertOtherIds:
                name = request.POST.get(certId+'certName')
                certOk = request.POST.get(certId+'certOk')
                certImg = None
                if request.FILES:
                    certImg = request.FILES.get(certId+'certImg')
                if not certImg:
                    continue
                newCert = models.Certificate(teacher=teacher,name=name,type=models.Certificate.OTHER,verified=False)
                if certOk and certOk=='True':
                    newCert.verified = True
                _img_content = ContentFile(certImg.read())
                newCert.img.save("certOther"+str(teacher.id)+'_'+str(_img_content.size), _img_content)
                newCert.save()
            # TODO: 资质认证修改后, 发邮件或短信通知
            # 介绍语音, 介绍视频
            introAudio = None
            if request.FILES:
                introAudio =  request.FILES.get('introAudio')
            if introAudio:
                _tmp_content = ContentFile(introAudio.read())
                teacher.audio.save('introAudio'+str(teacher.id)+'_'+str(_tmp_content.size), _tmp_content)
            else:
                if request.POST.get('toDeleteAudio'):
                    teacher.audio.delete()
            introVideo = None
            if request.FILES:
                introVideo =  request.FILES.get('introVideo')
            if introVideo:
                _tmp_content = ContentFile(introVideo.read())
                teacher.video.save('introVideo'+str(teacher.id)+'_'+str(_tmp_content.size), _tmp_content)
            else:
                if request.POST.get('toDeleteVideo'):
                    teacher.video.delete()
            teacher.save()
            # 教学成果
            allAchieveIds = request.POST.getlist('achieveId')
            stayAchieveIds = [s for s in allAchieveIds if s and (not s.startswith('new'))]
            newAchieveIds = [s for s in allAchieveIds if s.startswith('new')]
            models.Achievement.objects.filter(teacher=teacher).exclude(id__in=stayAchieveIds).delete()
            for achId in stayAchieveIds:
                title = request.POST.get(achId+'achieveName')
                achieveImg = None
                if request.FILES:
                    achieveImg = request.FILES.get(achId+'achieveImg')
                achievement = models.Achievement.objects.get(id=achId)
                achievement.title = title
                if achieveImg:
                    _img_content = ContentFile(achieveImg.read())
                    achievement.img.save("achievement"+str(teacher.id)+'_'+str(_img_content.size), _img_content)
                achievement.save()
            for achId in newAchieveIds:
                title = request.POST.get(achId+'achieveName')
                achieveImg = None
                if request.FILES:
                    achieveImg = request.FILES.get(achId+'achieveImg')
                if not title or not achieveImg:
                    continue
                newAch = models.Achievement(teacher=teacher,title=title)
                _img_content = ContentFile(achieveImg.read())
                newAch.img.save("achievement"+str(teacher.id)+'_'+str(_img_content.size), _img_content)
                newAch.save()
        except Exception as ex:
            logger.error(ex)
            return JsonResponse({'ok': False, 'msg': BaseStaffActionView.defaultErrMeg, 'code': -1})
        return JsonResponse({'ok': True, 'msg': '', 'code': 0})

    def postSaveCert(self, request, teacher, type_code, type_str, cert=None):
        if not cert:
            cert, created = models.Certificate.objects.get_or_create(teacher=teacher, type=type_code,
                                                                     defaults={'name':"",'verified':False})
        certOk = request.POST.get('cert'+type_str+'Ok')
        if certOk and certOk=='True':
            cert.verified = True
        else:
            cert.verified = False
        certImg = None
        if request.FILES:
            certImg = request.FILES.get('cert'+type_str+'Img')
        if certImg:
            _img_content = ContentFile(certImg.read())
            cert.img.save(type_str+str(teacher.id)+'_'+str(_img_content.size), _img_content)
        else:
            if request.POST.get('toDeleteCert'+type_str):
                cert.img.delete()
        if not cert.img:
            cert.verified = False
        cert.save()


class TeacherBankcardView(BaseStaffView):
    template_name = 'staff/teacher/teacher_bankcard_list.html'

    def get_context_data(self, **kwargs):
        # 把查询参数数据放到kwargs['query_data'], 以便template回显
        kwargs['query_data'] = self.request.GET.dict()
        #
        name = self.request.GET.get('name')
        phone = self.request.GET.get('phone')
        page = self.request.GET.get('page')
        query_set = models.BankCard.objects.select_related('account__user__teacher', 'account__user__profile').filter()
        if name:<commit_msg>BE-5: fix query_data to remove debug trace log<commit_after>import logging
import datetime

# django modules
from django.core.files.base import ContentFile
from django.shortcuts import render, redirect, get_object_or_404
from django.http import HttpResponse, JsonResponse
from django.views.decorators.http import require_POST
from django.views.generic import View, TemplateView, ListView
from django.utils.decorators import method_decorator
from django.contrib import auth
from django.db.models import Q
from django.utils import timezone
from rest_framework.renderers import JSONRenderer

import json

# local modules
from app import models
from app.utils import smsUtil
from app.utils.types import parseInt
from app.utils.db import paginate
from .decorators import mala_staff_required, is_manager


logger = logging.getLogger('app')

# Create your views here.

@mala_staff_required
def index(request):
    return render(request, 'staff/index.html')

def login(request, context={}):
    if is_manager(request.user):
        return redirect('staff:index')
    return render(request, 'staff/login.html', context)

def logout(request):
    auth.logout(request)
    return redirect('staff:login')

@require_POST
def login_auth(request):
    username = request.POST.get('username')
    password = request.POST.get('password')
    goto_page = request.POST.get('next')
    logger.debug('try to login, username: '+username+', password: '+password+', goto_page: '+str(goto_page))
    # TODO: 错误信息包含‘错误码’，错误描述可能会变
    if not username or not password:
        return login(request, {'errors': '请输入用户名和密码'})
    #登录前需要先验证
    newUser=auth.authenticate(username=username,password=password)
    if newUser is not None:
        if not is_manager(newUser):
            return login(request, {'errors': '你不是管理员呀'})
        auth.login(request, newUser)
        if goto_page:
            return redirect(goto_page)
        else:
            return redirect('staff:index')
    return login(request, {'errors': '用户名或密码错误'})



class BaseStaffView(TemplateView):
    """
    Base view for staff management page views.
    """

    @method_decorator(mala_staff_required)
    def dispatch(self, request, *args, **kwargs):
        return super(BaseStaffView, self).dispatch(request, *args, **kwargs)


class BaseStaffActionView(View):
    """
    Base view for staff management action views.
    """

    defaultErrMeg = "操作失败,请稍后重试或联系管理员"

    # @method_decorator(csrf_exempt) # 不加csrf,不允许跨域访问
    @method_decorator(mala_staff_required)
    def dispatch(self, request, *args, **kwargs):
        return super(BaseStaffActionView, self).dispatch(request, *args, **kwargs)


#因为使用了listView而无法直接继承BaseStaffView
@method_decorator(mala_staff_required, name='dispatch')
class CouponsListView(ListView):
    model = models.Coupon
    template_name = 'staff/coupon/coupons_list.html'
    context_object_name = 'coupons_list'
    paginate_by = 10

    def get_context_data(self, **kwargs):
        context = super(CouponsListView, self).get_context_data(**kwargs)
        kwargs['statusList'] = [
            {'text':"状态",'value':""},
            {'text':"已使用",'value':"used"},
            {'text':"未使用",'value':"unused"},
            {'text':"已过期",'value':"expired"},
                                ]
        kwargs['typesList'] = [
            {'text':"类型",'value':""},
            {'text':"注册",'value':"reg"},
            {'text':"抽奖",'value':"lotto"},
                                ]
        kwargs['name'] = self.request.GET.get('name',None)
        kwargs['phone'] = self.request.GET.get('phone',None)
        kwargs['dateFrom'] = self.request.GET.get('dateFrom',None)
        kwargs['dateTo'] = self.request.GET.get('dateTo',None)
        kwargs['type'] = self.request.GET.get('type',None)
        kwargs['status'] = self.request.GET.get('status',None)
        return super(CouponsListView, self).get_context_data(**kwargs)

    def get_queryset(self):
        coupons_list = self.model.objects.all()
        #TODO:用字典循环取值
        # for keyword in ['name','phone','dateFrom','dateTo','type','status']:
        #     cmd = "%s = self.request.GET.get('%s',None)" % (keyword,keyword)
        #     exec(cmd)
        #     print(name)
        name = self.request.GET.get('name',None)
        phone = self.request.GET.get('phone',None)
        dateFrom = self.request.GET.get('dateFrom',None)
        dateTo = self.request.GET.get('dateTo',None)
        type = self.request.GET.get('type',None)
        status = self.request.GET.get('status',None)

        if name:
            coupons_list = coupons_list.filter(parent__user__username__icontains=name)
        if phone:
            coupons_list = coupons_list.filter(parent__user__profile__phone__contains=phone)
        if dateFrom and dateTo:
            coupons_list = coupons_list.filter(created_at__range=(dateFrom, dateTo))
        if type == 'reg':
            pass
        if type == 'reg':
            pass
        if status == 'used':
            coupons_list = coupons_list.filter(used = True)
        if status == 'unused':
            now = timezone.now()
            coupons_list = coupons_list.filter(used = False).exclude(expired_at__lt = now)
        if status == 'expired':
            now = timezone.now()
            coupons_list = coupons_list.filter(used = False).filter(expired_at__lt = now)
        return coupons_list


class TeacherView(BaseStaffView):
    template_name = 'staff/teacher/teachers.html'

    def get_context_data(self, **kwargs):
        # 把查询参数数据放到kwargs['query_data'], 以便template回显
        kwargs['query_data'] = self.request.GET.dict()
        #
        name = self.request.GET.get('name')
        phone = self.request.GET.get('phone')
        status = self.request.GET.get('status')
        reg_date_from = self.request.GET.get('reg_date_from')
        reg_date_to = self.request.GET.get('reg_date_to')
        region = self.request.GET.get('region')
        page = self.request.GET.get('page')
        query_set = models.Teacher.objects.filter()
        if name:
            query_set = query_set.filter(name__icontains = name)
        if phone:
            query_set = query_set.filter(user__profile__phone__contains = phone)
        if status and status.isdigit():
            query_set = query_set.filter(status = status)
        if reg_date_from:
            try:
                date_from = datetime.datetime.strptime(reg_date_from, '%Y-%m-%d')
                query_set = query_set.filter(user__date_joined__gte = date_from)
            except:
                pass
        if reg_date_to:
            try:
                date_to = datetime.datetime.strptime(reg_date_to, '%Y-%m-%d')
                date_to += datetime.timedelta(days=1)
                query_set = query_set.filter(user__date_joined__lte = date_to)
            except:
                pass
        if region and region.isdigit():
            query_set = query_set.filter(region_id = region)
        query_set = query_set.order_by('-user__date_joined')
        # paginate
        query_set, pager = paginate(query_set, page)
        kwargs['teachers'] = query_set
        kwargs['pager'] = pager
        # 一些固定数据
        kwargs['status_choices'] = models.Teacher.STATUS_CHOICES
        kwargs['region_list'] = models.Region.objects.filter(Q(opened=True)|Q(name='其他'))
        return super(TeacherView, self).get_context_data(**kwargs)


class TeacherUnpublishedView(BaseStaffView):
    """
    待上架老师列表view
    """
    template_name = 'staff/teacher/teachers_unpublished.html'
    list_type = 'unpublished'

    def get_context_data(self, **kwargs):
        kwargs['list_type'] = self.list_type
        # 把查询参数数据放到kwargs['query_data'], 以便template回显
        kwargs['query_data'] = self.request.GET.dict()
        #
        name = self.request.GET.get('name') and self.request.GET.get('name').strip() or ''
        phone = self.request.GET.get('phone') and self.request.GET.get('phone').strip() or ''
        # province = self.request.GET.get('province')
        # city = self.request.GET.get('city')
        # district = self.request.GET.get('district')
        # region = district and district or city and city or province
        region = self.request.GET.get('region')
        grade = self.request.GET.get('grade') and self.request.GET.get('grade').strip() or ''
        subject = self.request.GET.get('subject') and self.request.GET.get('subject').strip() or ''
        level = self.request.GET.get('level') and self.request.GET.get('level').strip() or ''
        page = self.request.GET.get('page') and self.request.GET.get('page').strip() or ''
        for_published = self.list_type == 'published'
        query_set = models.Teacher.objects.filter(status=models.Teacher.INTERVIEW_OK, published=for_published)
        if name:
            query_set = query_set.filter(name__icontains = name)
        if phone:
            query_set = query_set.filter(user__profile__phone__contains = phone)
        if region:
            query_set = query_set.filter(region_id=region)
        if grade:
            query_set = query_set.filter(Q(abilities__grade_id=grade) | Q(abilities__grade__superset_id=grade))
        if subject:
            query_set = query_set.filter(abilities__subject_id=subject)
        if level:
            query_set = query_set.filter(level_id=level)
        query_set = query_set.order_by('id')
        # paginate
        query_set, pager = paginate(query_set, page)
        kwargs['teachers'] = query_set
        kwargs['pager'] = pager
        # 一些固定数据
        # kwargs['provinces'] = models.Region.objects.filter(superset_id__isnull=True)
        kwargs['region_list'] = models.Region.objects.filter(Q(opened=True)|Q(name='其他'))
        kwargs['grades'] = models.Grade.objects.filter(superset_id__isnull=True)
        kwargs['subjects'] = models.Subject.objects.all
        kwargs['levels'] = models.Level.objects.all
        return super(TeacherUnpublishedView, self).get_context_data(**kwargs)


class TeacherPublishedView(TeacherUnpublishedView):
    """
    已上架老师列表view
    """
    list_type = 'published'
    def get_context_data(self, **kwargs):
        return super(TeacherPublishedView, self).get_context_data(**kwargs)


class TeacherUnpublishedEditView(BaseStaffView):
    """
    待上架老师编辑页面view
    """
    template_name = 'staff/teacher/teachers_unpublished_edit.html'

    def get_context_data(self, **kwargs):
        teacherId = kwargs['tid']
        teacher = get_object_or_404(models.Teacher, id=teacherId)
        kwargs['teacher'] = teacher
        # 老师科目年级
        curSubject = teacher.subject()
        if curSubject:
            kwargs['grade_ids_range'] = models.Ability.objects.filter(subject=curSubject).values_list('grade_id', flat=True)
        kwargs['teacher_grade_ids'] = [grade.id for grade in teacher.grades()]
        # 证书数据
        certification_all = models.Certificate.objects.filter(teacher=teacher)
        cert_others = []
        for cert in certification_all:
            if cert.type == models.Certificate.ID_HELD:
                kwargs['cert_id_held'] = cert
            elif cert.type == models.Certificate.ID_FRONT:
                kwargs['cert_id_front'] = cert
            elif cert.type == models.Certificate.ACADEMIC:
                kwargs['cert_academic'] = cert
            elif cert.type == models.Certificate.TEACHING:
                kwargs['cert_teaching'] = cert
            elif cert.type == models.Certificate.ENGLISH:
                kwargs['cert_english'] = cert
            else:
                cert_others.append(cert)
        kwargs['cert_others'] = cert_others
        # 地区数据
        region_dict = teacher.region and teacher.region.make_dict() or None
        kwargs['region_dict'] = region_dict
        kwargs['provinces'] = models.Region.objects.filter(superset_id__isnull=True)
        if region_dict and region_dict.get('city'):
            kwargs['cities'] = models.Region.objects.filter(superset_id=region_dict.get('city').superset_id)
        if region_dict and region_dict.get('district'):
            kwargs['districts'] = models.Region.objects.filter(superset_id=region_dict.get('district').superset_id)
        # 一些固定数据
        kwargs['gender_choices'] = models.Profile.GENDER_CHOICES
        kwargs['subjects'] = models.Subject.objects.all
        kwargs['levels'] = models.Level.objects.all
        grades_all = models.Grade.objects.all()
        _heap = {}
        grades_tree = []
        for grade in grades_all:
            if not grade.superset_id:
                _temp = {'id':grade.id, 'name':grade.name, 'children':[]}
                _heap[grade.id] = _temp
                grades_tree.append(_temp)
            else:
                _temp = _heap[grade.superset_id]
                _temp['children'].append({'id':grade.id, 'name':grade.name})
        kwargs['grades_tree'] = grades_tree
        kwargs['tags_all'] = models.Tag.objects.all
        return super(TeacherUnpublishedEditView, self).get_context_data(**kwargs)

    def post(self, request, tid):
        teacher = get_object_or_404(models.Teacher, id=tid)
        try:
            # 获取参数, 并检验
            newSubjectId = parseInt(request.POST.get('subject'), False)
            if not newSubjectId:
                return JsonResponse({'ok': False, 'msg': '请选择科目', 'code': 1})
            newGradeIds = request.POST.getlist('grade')
            if not newGradeIds:
                return JsonResponse({'ok': False, 'msg': '请选择年级', 'code': -1})
            newTagIds  = request.POST.getlist('tag')
            if not newTagIds or len(newTagIds)>3:
                return JsonResponse({'ok': False, 'msg': '风格标记 (最少选一个，最多选3个)', 'code': -1})
            certIdHeld, created = models.Certificate.objects.get_or_create(teacher=teacher, type=models.Certificate.ID_HELD,
                                                                  defaults={'name':"",'verified':False})
            profile = teacher.user.profile
            # 基本信息
            teacher.name = request.POST.get('name')
            certIdHeld.name = request.POST.get('id_num')
            profile.phone = request.POST.get('phone')
            profile.gender = request.POST.get('gender')
            province = request.POST.get('province')
            city = request.POST.get('city')
            district = request.POST.get('district')
            region = district and district or city and city or province
            region = parseInt(region, None)
            if not region:
                teacher.region = None
            else:
                teacher.region_id = region
            teacher.teaching_age = parseInt(request.POST.get('teaching_age'), 0)
            teacher.level_id = parseInt(request.POST.get('level'), 1)
            teacher.experience = parseInt(request.POST.get('experience'), 0)
            teacher.profession = parseInt(request.POST.get('profession'), 0)
            teacher.interaction = parseInt(request.POST.get('interaction'), 0)
            certIdHeld.save()
            # 科目年级 & 风格标签
            teacher.abilities.clear()
            ability_set = models.Ability.objects.filter(subject_id=newSubjectId, grade_id__in=newGradeIds)
            for ability in ability_set:
                teacher.abilities.add(ability)
            teacher.tags.clear()
            tag_set = models.Tag.objects.filter(id__in=newTagIds)
            for tag in tag_set:
                teacher.tags.add(tag)
            teacher.save()
            # 头像 & 照片
            avatarImg = None
            if request.FILES:
                avatarImg = request.FILES.get('avatarImg')
            if avatarImg:
                _img_content = ContentFile(avatarImg.read())
                profile.avatar.save("avatar"+str(teacher.id)+'_'+str(_img_content.size), _img_content)
            else:
                if request.POST.get('toDeleteAvatar'):
                    profile.avatar.delete()
            profile.save()
            stayPhotoIds = request.POST.getlist('photoId')
            stayPhotoIds = [i for i in stayPhotoIds if i]
            newPhotoImgs = request.FILES.getlist('photoImg')
            models.Photo.objects.filter(teacher_id=teacher.id).exclude(id__in=stayPhotoIds).delete()
            for photoImg in newPhotoImgs:
                photo = models.Photo(teacher=teacher, public=True)
                _img_content = ContentFile(photoImg.read())
                photo.img.save("photo"+str(teacher.id)+'_'+str(_img_content.size), _img_content)
                photo.save()
            # 提分榜
            allHsIds = request.POST.getlist('highscoreId')
            stayHsIds = [s for s in allHsIds if s and (not s.startswith('new'))]
            newHsIds = [s for s in allHsIds if s.startswith('new')]
            models.Highscore.objects.filter(teacher_id=teacher.id).exclude(id__in=stayHsIds).delete()
            for hsId in newHsIds:
                name = request.POST.get(hsId+'name')
                scores = request.POST.get(hsId+'scores')
                school_from = request.POST.get(hsId+'from')
                school_to = request.POST.get(hsId+'to')
                highscore = models.Highscore(teacher=teacher, name=name, increased_scores=scores,
                                             school_name=school_from, admitted_to=school_to)
                highscore.save()
            ### 认证
            # 身份认证
            certIdHeldOk = request.POST.get('certIdHeldOk')
            if certIdHeldOk and certIdHeldOk=='True':
                certIdHeld.verified = True
            else:
                certIdHeld.verified = False
            certIdHeldImg = None
            if request.FILES:
                certIdHeldImg = request.FILES.get('certIdHeldImg')
            if certIdHeldImg:
                _img_content = ContentFile(certIdHeldImg.read())
                certIdHeld.img.save("idHeld"+str(teacher.id)+'_'+str(_img_content.size), _img_content)
            else:
                if request.POST.get('toDeleteCertIdHeld'):
                    certIdHeld.img.delete()
            if not certIdHeld.img:
                certIdHeld.verified = False
            certIdFront, created = models.Certificate.objects.get_or_create(teacher=teacher, type=models.Certificate.ID_FRONT,
                                                              defaults={'name':"",'verified':False})
            certIdFrontImg = None
            if request.FILES:
                certIdFrontImg = request.FILES.get('certIdFrontImg')
            if certIdFrontImg:
                _img_content = ContentFile(certIdFrontImg.read())
                certIdFront.img.save("IdFront"+str(teacher.id)+'_'+str(_img_content.size), _img_content)
            else:
                if request.POST.get('toDeleteCertIdFront'):
                    certIdFront.img.delete()
            if not certIdFront.img:
                certIdHeld.verified = False
            certIdFront.save()
            certIdHeld.save()
            # 学历, 教师资格证,英语水平
            self.postSaveCert(request, teacher, models.Certificate.ACADEMIC, 'Academic')
            self.postSaveCert(request, teacher, models.Certificate.TEACHING, 'Teaching')
            self.postSaveCert(request, teacher, models.Certificate.ENGLISH, 'English')
            # 其他认证
            allCertOtherIds = request.POST.getlist('certOtherId')
            stayCertOtherIds = [s for s in allCertOtherIds if s and (not s.startswith('new'))]
            newCertOtherIds = [s for s in allCertOtherIds if s.startswith('new')]
            models.Certificate.objects.filter(teacher=teacher, type=models.Certificate.OTHER)\
                .exclude(id__in=stayCertOtherIds).delete()
            for certId in stayCertOtherIds:
                name = request.POST.get(certId+'certName')
                certOk = request.POST.get(certId+'certOk')
                certImg = None
                if request.FILES:
                    certImg = request.FILES.get(certId+'certImg')
                cert = models.Certificate.objects.get(id=certId)
                cert.name = name
                if certOk and certOk=='True':
                    cert.verified = True
                else:
                    cert.verified = False
                if certImg:
                    _img_content = ContentFile(certImg.read())
                    cert.img.save("certOther"+str(teacher.id)+'_'+str(_img_content.size), _img_content)
                cert.save()
            for certId in newCertOtherIds:
                name = request.POST.get(certId+'certName')
                certOk = request.POST.get(certId+'certOk')
                certImg = None
                if request.FILES:
                    certImg = request.FILES.get(certId+'certImg')
                if not certImg:
                    continue
                newCert = models.Certificate(teacher=teacher,name=name,type=models.Certificate.OTHER,verified=False)
                if certOk and certOk=='True':
                    newCert.verified = True
                _img_content = ContentFile(certImg.read())
                newCert.img.save("certOther"+str(teacher.id)+'_'+str(_img_content.size), _img_content)
                newCert.save()
            # TODO: 资质认证修改后, 发邮件或短信通知
            # 介绍语音, 介绍视频
            introAudio = None
            if request.FILES:
                introAudio =  request.FILES.get('introAudio')
            if introAudio:
                _tmp_content = ContentFile(introAudio.read())
                teacher.audio.save('introAudio'+str(teacher.id)+'_'+str(_tmp_content.size), _tmp_content)
            else:
                if request.POST.get('toDeleteAudio'):
                    teacher.audio.delete()
            introVideo = None
            if request.FILES:
                introVideo =  request.FILES.get('introVideo')
            if introVideo:
                _tmp_content = ContentFile(introVideo.read())
                teacher.video.save('introVideo'+str(teacher.id)+'_'+str(_tmp_content.size), _tmp_content)
            else:
                if request.POST.get('toDeleteVideo'):
                    teacher.video.delete()
            teacher.save()
            # 教学成果
            allAchieveIds = request.POST.getlist('achieveId')
            stayAchieveIds = [s for s in allAchieveIds if s and (not s.startswith('new'))]
            newAchieveIds = [s for s in allAchieveIds if s.startswith('new')]
            models.Achievement.objects.filter(teacher=teacher).exclude(id__in=stayAchieveIds).delete()
            for achId in stayAchieveIds:
                title = request.POST.get(achId+'achieveName')
                achieveImg = None
                if request.FILES:
                    achieveImg = request.FILES.get(achId+'achieveImg')
                achievement = models.Achievement.objects.get(id=achId)
                achievement.title = title
                if achieveImg:
                    _img_content = ContentFile(achieveImg.read())
                    achievement.img.save("achievement"+str(teacher.id)+'_'+str(_img_content.size), _img_content)
                achievement.save()
            for achId in newAchieveIds:
                title = request.POST.get(achId+'achieveName')
                achieveImg = None
                if request.FILES:
                    achieveImg = request.FILES.get(achId+'achieveImg')
                if not title or not achieveImg:
                    continue
                newAch = models.Achievement(teacher=teacher,title=title)
                _img_content = ContentFile(achieveImg.read())
                newAch.img.save("achievement"+str(teacher.id)+'_'+str(_img_content.size), _img_content)
                newAch.save()
        except Exception as ex:
            logger.error(ex)
            return JsonResponse({'ok': False, 'msg': BaseStaffActionView.defaultErrMeg, 'code': -1})
        return JsonResponse({'ok': True, 'msg': '', 'code': 0})

    def postSaveCert(self, request, teacher, type_code, type_str, cert=None):
        if not cert:
            cert, created = models.Certificate.objects.get_or_create(teacher=teacher, type=type_code,
                                                                     defaults={'name':"",'verified':False})
        certOk = request.POST.get('cert'+type_str+'Ok')
        if certOk and certOk=='True':
            cert.verified = True
        else:
            cert.verified = False
        certImg = None
        if request.FILES:
            certImg = request.FILES.get('cert'+type_str+'Img')
        if certImg:
            _img_content = ContentFile(certImg.read())
            cert.img.save(type_str+str(teacher.id)+'_'+str(_img_content.size), _img_content)
        else:
            if request.POST.get('toDeleteCert'+type_str):
                cert.img.delete()
        if not cert.img:
            cert.verified = False
        cert.save()


class TeacherBankcardView(BaseStaffView):
    template_name = 'staff/teacher/teacher_bankcard_list.html'

    def get_context_data(self, **kwargs):
        # 把查询参数数据放到kwargs['query_data'], 以便template回显
        query_data = {}
        query_data['name'] = self.request.GET.get('name', '')
        query_data['phone'] = self.request.GET.get('phone', '')
        kwargs['query_data'] = query_data
        #
        name = self.request.GET.get('name')
        phone = self.request.GET.get('phone')
        page = self.request.GET.get('page')
        query_set = models.BankCard.objects.select_related('account__user__teacher', 'account__user__profile').filter()
        if name:
{'fraction_non_alphanumeric': 0.11802710368736212, 'fraction_numerical': 0.0009651749133312323, 'mean_word_length': 2.2634183968631483, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 18, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '474199', 'n_tokens_mistral': 15319, 'n_tokens_neox': 15174, 'n_words': 2523}