def img_get_func(request):
    if request.session.get("img_path", None) is not None:
        # 有缓存
        return request.session['img_path'], False

    # 设置当头像无法加载时的位置
    default_img_name = 'pipi_square_iRGk72U.jpg'
    img_path = global_info.this_url + "/media/avatar/" + default_img_name

    # 尝试加载头像
    try:
        if global_info.account_auth:
            Sid = request.session['Sid']
            urls = global_info.img_url + "/getStuImg?stuId=" + Sid
            img_get = long_request.post(url=urls, verify=False, timeout=3)

            if img_get.status_code == 200:  # 接收到了学生信息
                img_path = eval(
                    img_get.content.decode('unicode-escape'))['path']
                img_path = global_info.login_url + img_path
                # 存入缓存
                request.session['img_path'] = img_path
                return img_path, True

    except:
        utils.operation_writer(
            global_info.system_log, f"从YPPF获取头像失败,原因需要查看代码", "web_func.img_get_func", "Problem")
        return img_path, False
        # 接受失败,返回旧地址
    utils.operation_writer(
            global_info.system_log, f"从YPPF获取头像失败,未登录或未返回", "web_func.img_get_func", "Problem")
    return img_path, False
Ejemplo n.º 2
0
 def refresh_scheduler(self, request, queryset):
     '''
     假设的情况是后台修改了开始和结束时间后,需要重置定时任务
     因此,旧的定时任务可能处于任何完成状态
     '''
     if not request.user.is_superuser:
         return self.message_user(request=request,
                                  message='操作失败,没有权限,请联系老师!',
                                  level=messages.WARNING)
     if not queryset:
         return self.message_user(request=request,
                                  message='请至少选择一个需要更新的预约!',
                                  level=messages.WARNING)
     for appoint in queryset:
         try:
             aid = appoint.Aid
             start = appoint.Astart
             finish = appoint.Afinish
             if start > finish:
                 return self.message_user(
                     request=request,
                     message=f'操作失败,预约{aid}开始和结束时间冲突!请勿篡改数据!',
                     level=messages.WARNING)
             scheduler_func.cancel_scheduler(aid)  # 注销原有定时任务 无异常
             scheduler_func.set_scheduler(appoint)  # 开始时进入进行中 结束后判定
             if datetime.now() < start:  # 如果未开始,修改开始提醒
                 scheduler_func.set_start_wechat(appoint, notify_new=False)
         except Exception as e:
             operation_writer(global_info.system_log,
                              "出现更新定时任务失败的问题: " + str(e), "admin.longterm",
                              "Error")
             return self.message_user(request=request,
                                      message=str(e),
                                      level=messages.WARNING)
     return self.message_user(request, '定时任务更新成功!')
Ejemplo n.º 3
0
    def violate(self, request, queryset):  # 确认违约
        if not request.user.is_superuser:
            return self.message_user(request=request,
                                     message='操作失败,没有权限,请联系老师!',
                                     level=messages.WARNING)
        try:
            for appoint in queryset:
                assert not (appoint.Astatus == Appoint.Status.VIOLATED
                            and appoint.Areason == Appoint.Reason.R_ELSE)
                ori_status = appoint.get_status()
                # if appoint.Astatus == Appoint.Status.WAITING:
                # 已违规时不扣除信用分,仅提示用户
                if appoint.Astatus != Appoint.Status.VIOLATED:
                    appoint.Astatus = Appoint.Status.VIOLATED
                    appoint.major_student.Scredit -= 1  # 只扣除发起人
                    appoint.major_student.save()
                appoint.Areason = Appoint.Reason.R_ELSE
                # for stu in appoint.students.all():
                #    stu.Scredit -= 1
                #    stu.save()
                appoint.save()

                # send wechat message
                scheduler.add_job(
                    send_wechat_message,
                    args=[
                        [appoint.major_student.Sid],  # stuid_list
                        appoint.Astart,  # start_time
                        appoint.Room,  # room
                        "violate_admin",  # message_type
                        appoint.major_student.Sname,  # major_student
                        appoint.Ausage,  # usage
                        appoint.Aannouncement,
                        appoint.Ayp_num + appoint.Anon_yp_num,
                        f'原状态:{ori_status}',  # reason
                        #appoint.major_student.Scredit,
                    ],
                    id=f'{appoint.Aid}_violate_admin_wechat',
                    next_run_time=datetime.now() +
                    timedelta(seconds=5))  # 5s足够了
                operation_writer(
                    global_info.system_log,
                    str(appoint.Aid) + "号预约被管理员设为违约" + "发起人:" +
                    str(appoint.major_student), "admin.violate", "OK")
        except:
            return self.message_user(request=request,
                                     message='操作失败!只允许对未审核的条目操作!',
                                     level=messages.WARNING)

        return self.message_user(request, "设为违约成功!")
def clear_appointments():
    if global_info.delete_appoint_weekly:   # 是否清除一周之前的预约
        appoints_to_delete = Appoint.objects.filter(
            Afinish__lte=datetime.now()-timedelta(days=7))
        try:
            # with transaction.atomic(): //不采取原子操作
            write_before_delete(appoints_to_delete)  # 删除之前写在记录内
            appoints_to_delete.delete()
        except Exception as e:
            utils.operation_writer(global_info.system_log, "定时删除任务出现错误: "+str(e),
                             "func[clear_appointments]", "Problem")

        # 写入日志
        utils.operation_writer(global_info.system_log, "定时删除任务成功", "func[clear_appointments]")
Ejemplo n.º 5
0
def set_scheduler(appoint):
    '''不负责发送微信,不处理已经结束的预约,不处理始末逆序的预约,可以任何时间点调用,应该不报错'''
    # --- written by pht: 统一设置预约定时任务 --- #
    start = appoint.Astart
    finish = appoint.Afinish
    current_time = datetime.now() + timedelta(seconds=5)
    if finish < start:  # 开始晚于结束,预约不合规
        utils.operation_writer(
            global_info.system_log,
            f'预约{appoint.Aid}时间为{start}<->{finish},未能设置定时任务',
            'scheduler_func.set_scheduler', 'Error')
        return False  # 直接返回,预约不需要设置
    if finish < current_time:  # 预约已经结束
        utils.operation_writer(global_info.system_log,
                               f'预约{appoint.Aid}在设置定时任务时已经结束',
                               'scheduler_func.set_scheduler', 'Error')
        return False  # 直接返回,预约不需要设置
    has_started = start < current_time
    if has_started:  # 临时预约或特殊情况下设置任务时预约可能已经开始
        start = current_time  # 改为立刻执行
    # --- written end (2021.8.31) --- #

    # written by dyh: 在Astart将状态变为PROCESSING
    if not (has_started and appoint.Astatus == Appoint.Status.PROCESSING):
        scheduler.add_job(web_func.startAppoint,
                          args=[appoint.Aid],
                          id=f'{appoint.Aid}_start',
                          replace_existing=True,
                          next_run_time=start)

    # write by cdf start2  # 添加定时任务:finish
    scheduler.add_job(web_func.finishAppoint,
                      args=[appoint.Aid],
                      id=f'{appoint.Aid}_finish',
                      replace_existing=True,
                      next_run_time=finish)
    return True
def startAppoint(Aid):  # 开始预约时的定时程序
    try:
        appoint = Appoint.objects.get(Aid=Aid)
    except:
        utils.operation_writer(
            global_info.system_log, f"预约{str(Aid)}意外消失", "web_func.startAppoint", "Error")

    if appoint.Astatus == Appoint.Status.APPOINTED:     # 顺利开始
        appoint.Astatus = Appoint.Status.PROCESSING
        appoint.save()
        utils.operation_writer(
            global_info.system_log, f"预约{str(Aid)}成功开始: 状态变为进行中", "web_func.startAppoint")
    
    elif appoint.Astatus == Appoint.Status.PROCESSING:  # 已经开始
        utils.operation_writer(
            global_info.system_log, f"预约{str(Aid)}在检查时已经开始", "web_func.startAppoint")

    elif appoint.Astatus != Appoint.Status.CANCELED:    # 状态异常,本该不存在这个任务
        utils.operation_writer(
            global_info.system_log, f"预约{str(Aid)}的状态异常: {appoint.get_status()}", "web_func.startAppoint", "Error")
def addAppoint(contents):  # 添加预约, main function

    # 首先检查房间是否存在
    try:
        room = Room.objects.get(Rid=contents['Rid'])
        assert room.Rstatus == Room.Status.PERMITTED, 'room service suspended!'
    except Exception as e:
        return JsonResponse(
            {
                'statusInfo': {
                    'message': '房间不存在或当前房间暂停预约服务,请更换房间!',
                    'detail': str(e)
                }
            },
            status=400)
    # 再检查学号对不对
    students_id = contents['students']  # 存下学号列表
    students = Student.objects.filter(
        Sid__in=students_id).distinct()  # 获取学生objects
    try:
        assert len(students) == len(
            students_id), "students repeat or don't exists"
    except Exception as e:
        return JsonResponse(
            {
                'statusInfo': {
                    'message': '预约人信息有误,请检查后重新发起预约!',
                    'detail': str(e)
                }
            },
            status=400)

    # 检查人员信息
    try:
        #assert len(students) >= room.Rmin, f'at least {room.Rmin} students'
        real_min = room.Rmin if datetime.now().date(
        ) != contents['Astart'].date() else min(global_info.today_min, room.Rmin)
        assert len(students) + contents[
            'non_yp_num'] >= real_min, f'at least {room.Rmin} students'
    except Exception as e:
        return JsonResponse(
            {'statusInfo': {
                'message': '使用总人数需达到房间最小人数!',
                'detail': str(e)
            }},
            status=400)
    # 检查外院人数是否过多
    try:
        # assert len(
        #    students) >= contents['non_yp_num'], f"too much non-yp students!"
        assert 2 * len(
            students) >= real_min, f"too little yp students!"
    except Exception as e:
        return JsonResponse(
            {'statusInfo': {
                # 'message': '外院人数不得超过总人数的一半!',
                'message': '院内使用人数需要达到房间最小人数的一半!',
                'detail': str(e)
            }},
            status=400)

    # 检查如果是俄文楼,是否只有一个人使用
    if "R" in room.Rid:  # 如果是俄文楼系列
        try:
            assert len(
                students) + contents['non_yp_num'] == 1, f"too many people using russian room!"
        except Exception as e:
            return JsonResponse(
                {'statusInfo': {
                    'message': '俄文楼元创空间仅支持单人预约!',
                    'detail': str(e)
                }},
                status=400)

    # 检查预约时间是否正确
    try:
        #Astart = datetime.strptime(contents['Astart'], '%Y-%m-%d %H:%M:%S')
        #Afinish = datetime.strptime(contents['Afinish'], '%Y-%m-%d %H:%M:%S')
        Astart = contents['Astart']
        Afinish = contents['Afinish']
        assert Astart <= Afinish, 'Appoint time error'
        assert Astart > datetime.now(), 'Appoint time error'
    except Exception as e:
        return JsonResponse(
            {
                'statusInfo': {
                    'message': '非法预约时间段,请不要擅自修改url!',
                    'detail': str(e)
                }
            },
            status=400)
    # 预约是否超过3小时
    try:
        assert Afinish <= Astart + timedelta(hours=3)
    except:
        return JsonResponse({'statusInfo': {
            'message': '预约时常不能超过3小时!',
        }},
            status=400)
    # 学号对了,人对了,房间是真实存在的,那就开始预约了


    # 接下来开始搜索数据库,上锁
    try:
        with transaction.atomic():
            # 等待确认的和结束的肯定是当下时刻已经弄完的,所以不用管
            print("得到搜索列表")
            appoints = room.appoint_list.select_for_update().exclude(
                Astatus=Appoint.Status.CANCELED).filter(
                    Room_id=contents['Rid'])
            for appoint in appoints:
                start = appoint.Astart
                finish = appoint.Afinish

                # 第一种可能,开始在开始之前,只要结束的比开始晚就不行
                # 第二种可能,开始在开始之后,只要在结束之前就都不行
                if (start <= Astart < finish) or (Astart <= start < Afinish):
                    # 有预约冲突的嫌疑,但要检查一下是不是重复预约了
                    if start == Astart and finish == Afinish and appoint.Ausage == contents['Ausage'] \
                            and appoint.Aannouncement == contents['announcement'] and appoint.Ayp_num == len(students) \
                            and appoint.Anon_yp_num == contents['non_yp_num'] and contents['Sid'] == appoint.major_student_id:
                        # Room不用检查,肯定是同一个房间
                        utils.operation_writer(
                            major_student.Sid, "重复发起同时段预约,预约号"+str(appoint.Aid), "func[addAppoint]", "OK")
                        return JsonResponse({'data': appoint.toJson()}, status=200)
                    else:
                        # 预约冲突
                        return JsonResponse(
                            {
                                'statusInfo': {
                                    'message': '预约时间与已有预约冲突,请重选时间段!',
                                    'detail': appoint.toJson()
                                }
                            },
                            status=400)
            # 获取预约发起者,确认预约状态
            try:
                major_student = Student.objects.get(Sid=contents['Sid'])
            except:
                return JsonResponse(
                    {
                        'statusInfo': {
                            'message': '发起人信息与登录信息不符,请不要在同一浏览器同时登录不同账号!',
                        }
                    },
                    status=400)

            # 确认信用分符合要求
            try:
                assert major_student.Scredit > 0
            except:
                return JsonResponse(
                    {'statusInfo': {
                        'message': '信用分不足,本月无法发起预约!',
                    }},
                    status=400)

            # 合法,可以返回了
            appoint = Appoint(Room=room,
                              Astart=Astart,
                              Afinish=Afinish,
                              Ausage=contents['Ausage'],
                              Aannouncement=contents['announcement'],
                              major_student=major_student,
                              Anon_yp_num=contents['non_yp_num'],
                              Ayp_num=len(students))
            appoint.save()
            for student in students:
                appoint.students.add(student)
            appoint.save()

            # write by cdf start2  # 添加定时任务:finish
            scheduler.add_job(web_func.finishFunction,
                              args=[appoint.Aid],
                              id=f'{appoint.Aid}_finish',
                              next_run_time=Afinish)  # - timedelta(minutes=45))
            # write by cdf end2
            if datetime.now() <= appoint.Astart - timedelta(minutes=15):  # 距离预约开始还有15分钟以上,提醒有新预约&定时任务
                print('距离预约开始还有15分钟以上,提醒有新预约&定时任务', contents['new_require'])
                if contents['new_require'] == 1:  # 只有在非长线预约中才添加这个job
                    scheduler.add_job(utils.send_wechat_message,
                                      args=[students_id,
                                            appoint.Astart,
                                            appoint.Room,
                                            "new",
                                            appoint.major_student.Sname,
                                            appoint.Ausage,
                                            appoint.Aannouncement,
                                            appoint.Anon_yp_num+appoint.Ayp_num,
                                            '',
                                            # appoint.major_student.Scredit,
                                            ],
                                      id=f'{appoint.Aid}_new_wechat',
                                      next_run_time=datetime.now() + timedelta(seconds=5))
                scheduler.add_job(utils.send_wechat_message,
                                  args=[students_id,
                                        appoint.Astart,
                                        appoint.Room,
                                        "start",
                                        appoint.major_student.Sname,
                                        appoint.Ausage,
                                        appoint.Aannouncement,
                                        appoint.Ayp_num+appoint.Anon_yp_num,
                                        '',
                                        # appoint.major_student.Scredit,
                                        ],
                                  id=f'{appoint.Aid}_start_wechat',
                                  next_run_time=appoint.Astart - timedelta(minutes=15))
            else:  # 距离预约开始还有不到15分钟,提醒有新预约并且马上开始
                # send_status, err_message = utils.send_wechat_message(students_id, appoint.Astart, appoint.Room,"new&start")
                scheduler.add_job(utils.send_wechat_message,
                                  args=[students_id,
                                        appoint.Astart,
                                        appoint.Room,
                                        "new&start",
                                        appoint.major_student.Sname,
                                        appoint.Ausage,
                                        appoint.Aannouncement,
                                        appoint.Anon_yp_num+appoint.Ayp_num,
                                        '',
                                        # appoint.major_student.Scredit,
                                        ],
                                  id=f'{appoint.Aid}_new_wechat',
                                  next_run_time=datetime.now() + timedelta(seconds=5))

            utils.operation_writer(major_student.Sid, "发起预约,预约号" +
                             str(appoint.Aid), "func[addAppoint]", "OK")

    except Exception as e:
        utils.operation_writer(global_info.system_log, "学生" + str(major_student) +
                         "出现添加预约失败的问题:"+str(e), "func[addAppoint]", "Error")
        return JsonResponse({'statusInfo': {
            'message': '添加预约失败!请与管理员联系!',
        }},
            status=400)

    return JsonResponse({'data': appoint.toJson()}, status=200)
Ejemplo n.º 8
0
def door_check(request):  # 先以Sid Rid作为参数,看之后怎么改

    get_post = request.get_full_path().split("?")[1].split("&")
    get_post = {i.split("=")[0]: i.split("=")[1] for i in get_post}

    # 获取房间基本信息,如果是自习室就开门
    try:

        Sid, Rid = get_post['Sid'], get_post['Rid']

        assert Sid is not None
        assert Rid is not None
        Rid = doortoroom(Rid)
        all_room = Room.objects.all()
        all_rid = [room.Rid for room in all_room]
        if Rid[:4] in all_rid:  # 表示增加了一个未知的A\B号
            Rid = Rid[:4]
        if Rid in all_rid:  # 如果在房间列表里,考虑类型
            if Room.objects.get(
                    Rid=Rid).Rstatus == Room.Status.SUSPENDED:  # 自习室
                return JsonResponse({
                    "code": 0,
                    "openDoor": "true"
                },
                                    status=200)
            # 否则是预约房,进入后续逻辑
        else:  # 不在房间列表
            raise SystemError

        student = Student.objects.get(Sid=Sid)
    except Exception as e:
        return JsonResponse({
            "code": 1,
            "openDoor": "false",
        }, status=400)

    # 检查预约者和房间是否匹配
    contents = {'Sid': str(Sid), 'kind': 'today'}
    stu_appoint = student.appoint_list.not_canceled()

    # 获取预约者今天的全部预约
    stu_appoint = [
        appoint for appoint in stu_appoint
        if appoint.Room_id == Rid and appoint.Astart.date() == datetime.now(
        ).date() and datetime.now() >= appoint.Astart - timedelta(minutes=15)
        and datetime.now() <= appoint.Afinish + timedelta(minutes=15)
    ]

    # 是这个房间and是今天的预约and在可开门时间范围内
    if len(stu_appoint) == 0:
        # 没有预约,或不在开门时间范围内
        return JsonResponse({
            "code": 1,
            "openDoor": "false",
        }, status=400)

    else:  # 到这里的一定是可以开门的
        '''
        # check the camera
        journal = open("journal.txt","a")
        journal.write(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
        # journal.write('\t'+room.Rid+'\t')
        journal.write("开门\n")
        journal.close()
        '''
        try:
            with transaction.atomic():
                for now_appoint in stu_appoint:
                    if (now_appoint.Astatus == Appoint.Status.APPOINTED
                            and datetime.now() <=
                            now_appoint.Astart + timedelta(minutes=15)):
                        now_appoint.Astatus = Appoint.Status.PROCESSING
                        now_appoint.save()
        except Exception as e:
            operation_writer(
                global_info.system_log, "可以开门却不开门的致命错误,房间号为" + str(Rid) +
                ",学生为" + str(Sid) + ",错误为:" + str(e), "func[doorcheck]",
                "Error")
            return JsonResponse(  # 未知错误
                {
                    "code": 1,
                    "openDoor": "false",
                }, status=400)
    return JsonResponse({"code": 0, "openDoor": "true"}, status=200)
Ejemplo n.º 9
0
def cameracheck(request):  # 摄像头post的后端函数

    # 获取摄像头信号,得到rid,最小人数
    try:
        ip = request.META.get("REMOTE_ADDR")
        temp_stu_num = int(
            eval(request.body.decode('unicode-escape'))['body']['people_num'])
        rid = iptoroom(ip.split(".")[3])  # !!!!!
        # rid = 'B221'  # just for debug
        room = Room.objects.get(Rid=rid)  # 获取摄像头信号
        num_need = room.Rmin  # 最小房间人数
    except:
        return JsonResponse({'statusInfo': {
            'message': '缺少摄像头信息!',
        }},
                            status=400)
    now_time = datetime.now()

    # 更新现在的人数、最近更新时间
    try:
        with transaction.atomic():
            room.Rpresent = temp_stu_num
            room.Rlatest_time = now_time
            room.save()

    except Exception as e:
        operation_writer(global_info.system_log,
                         "房间" + str(rid) + "更新摄像头人数失败1: " + str(e),
                         "func[cameracheck]", "Error")

        return JsonResponse({'statusInfo': {
            'message': '更新摄像头人数失败!',
        }},
                            status=400)

    # 检查时间问题,可能修改预约状态;
    appointments = Appoint.objects.not_canceled().filter(
        Q(Astart__lte=now_time) & Q(Afinish__gte=now_time)
        & Q(Room_id=rid))  # 只选取状态在1,2之间的预约

    if len(appointments):  # 如果有,只能有一个预约
        content = appointments[0]
        if content.Atime.date() == content.Astart.date():
            # 如果预约时间在使用时间的24h之内 则人数下限为2
            num_need = min(global_info.today_min, num_need)
        try:
            if room.Rid in {"B109A", "B207"}:  # 康德报告厅&小舞台 不考虑违约
                content.Astatus = Appoint.Status.CONFIRMED
                content.save()
            else:  # 其他房间

                # added by wxy
                # 检查人数:采样、判断、更新
                # 人数在finishappoint中检查
                rand = random.uniform(0, 1)
                camera_lock.acquire()
                with transaction.atomic():
                    if rand > 1 - global_info.check_rate:
                        content.Acamera_check_num += 1
                        if temp_stu_num >= num_need:
                            content.Acamera_ok_num += 1
                        content.save()
                camera_lock.release()
                # add end
        except Exception as e:
            operation_writer(global_info.system_log,
                             "预约" + str(content.Aid) + "更新摄像头人数失败2: " + str(e),
                             "func[cameracheck]", "Error")

            return JsonResponse({'statusInfo': {
                'message': '更新预约状态失败!',
            }},
                                status=400)
        try:
            if now_time > content.Astart + timedelta(
                    minutes=15) and content.Astatus == Appoint.Status.APPOINTED:
                # added by wxy: 违约原因:迟到
                status, tempmessage = appoint_violate(content,
                                                      Appoint.Reason.R_LATE)
                if not status:
                    operation_writer(
                        global_info.system_log, "预约" + str(content.Aid) +
                        "因迟到而违约,返回值出现异常: " + tempmessage, "func[cameracheck]",
                        "Error")
        except Exception as e:
            operation_writer(
                global_info.system_log,
                "预约" + str(content.Aid) + "在迟到违约过程中: " + tempmessage,
                "func[cameracheck]", "Error")

        return JsonResponse({}, status=200)  # 返回空就好
    else:  # 否则的话 相当于没有预约 正常返回
        return JsonResponse({}, status=200)  # 返回空就好
Ejemplo n.º 10
0
def addAppoint(contents):  # 添加预约, main function

    # 检查是否为临时预约 add by lhw (2021.7.13)
    if 'Atemp_flag' not in contents.keys():
        contents['Atemp_flag'] = False
    # 首先检查房间是否存在
    try:
        room = Room.objects.get(Rid=contents['Rid'])
        assert room.Rstatus == Room.Status.PERMITTED, 'room service suspended!'
    except Exception as e:
        return JsonResponse(
            {
                'statusInfo': {
                    'message': '房间不存在或当前房间暂停预约服务,请更换房间!',
                    'detail': str(e)
                }
            },
            status=400)
    # 再检查学号对不对
    students_id = contents['students']  # 存下学号列表
    students = Student.objects.filter(
        Sid__in=students_id).distinct()  # 获取学生objects
    try:
        assert len(students) == len(
            students_id), "students repeat or don't exists"
    except Exception as e:
        return JsonResponse(
            {
                'statusInfo': {
                    'message': '预约人信息有误,请检查后重新发起预约!',
                    'detail': str(e)
                }
            },
            status=400)

    # 检查人员信息
    try:
        #assert len(students) >= room.Rmin, f'at least {room.Rmin} students'

        # ---- modify by lhw: 加入考虑临时预约的情况 ---- #
        current_time = datetime.now()  # 获取当前时间,只获取一次,防止多次获取得到不同时间
        if current_time.date() != contents['Astart'].date():  # 若不为当天
            real_min = room.Rmin
        elif contents['Atemp_flag'] == False:  # 当天预约,放宽限制
            real_min = min(room.Rmin, global_info.today_min)
        else:  # 临时预约,放宽限制
            real_min = min(room.Rmin, global_info.temporary_min)
        # ----- modify end : 2021.7.10 ----- #

        assert len(students) + contents[
            'non_yp_num'] >= real_min, f'at least {room.Rmin} students'
    except Exception as e:
        return JsonResponse(
            {'statusInfo': {
                'message': '使用总人数需达到房间最小人数!',
                'detail': str(e)
            }},
            status=400)
    # 检查外院人数是否过多
    try:
        # assert len(
        #    students) >= contents['non_yp_num'], f"too much non-yp students!"
        assert 2 * len(students) >= real_min, f"too little yp students!"
    except Exception as e:
        return JsonResponse(
            {
                'statusInfo': {
                    # 'message': '外院人数不得超过总人数的一半!',
                    'message': '院内使用人数需要达到房间最小人数的一半!',
                    'detail': str(e)
                }
            },
            status=400)

    # 检查如果是俄文楼,是否只有一个人使用
    if "R" in room.Rid:  # 如果是俄文楼系列
        try:
            assert len(students) + contents[
                'non_yp_num'] == 1, f"too many people using russian room!"
        except Exception as e:
            return JsonResponse(
                {
                    'statusInfo': {
                        'message': '俄文楼元创空间仅支持单人预约!',
                        'detail': str(e)
                    }
                },
                status=400)

    # 检查预约时间是否正确
    try:
        #Astart = datetime.strptime(contents['Astart'], '%Y-%m-%d %H:%M:%S')
        #Afinish = datetime.strptime(contents['Afinish'], '%Y-%m-%d %H:%M:%S')
        Astart = contents['Astart']
        Afinish = contents['Afinish']
        assert Astart <= Afinish, 'Appoint time error'

        # --- modify by lhw: Astart 可能比datetime.now小 --- #

        #assert Astart > datetime.now(), 'Appoint time error'
        assert Afinish > datetime.now(), 'Appoint time error'

        # --- modify end: 2021.7.10 --- #

    except Exception as e:
        return JsonResponse(
            {
                'statusInfo': {
                    'message': '非法预约时间段,请不要擅自修改url!',
                    'detail': str(e)
                }
            },
            status=400)
    # 预约是否超过3小时
    try:
        assert Afinish <= Astart + timedelta(hours=3)
    except:
        return JsonResponse({'statusInfo': {
            'message': '预约时常不能超过3小时!',
        }},
                            status=400)
    # 学号对了,人对了,房间是真实存在的,那就开始预约了

    # 接下来开始搜索数据库,上锁
    major_student = None  # 避免下面未声明出错
    try:
        with transaction.atomic():

            # 获取预约发起者,确认预约状态
            try:
                major_student = Student.objects.get(Sid=contents['Sid'])
            except:
                return JsonResponse(
                    {
                        'statusInfo': {
                            'message': '发起人信息与登录信息不符,请不要在同一浏览器同时登录不同账号!',
                        }
                    },
                    status=400)

            # 等待确认的和结束的肯定是当下时刻已经弄完的,所以不用管
            print("得到搜索列表")
            appoints = room.appoint_list.select_for_update().exclude(
                Astatus=Appoint.Status.CANCELED).filter(
                    Room_id=contents['Rid'])
            for appoint in appoints:
                start = appoint.Astart
                finish = appoint.Afinish

                # 第一种可能,开始在开始之前,只要结束的比开始晚就不行
                # 第二种可能,开始在开始之后,只要在结束之前就都不行
                if (start <= Astart < finish) or (Astart <= start < Afinish):
                    # 有预约冲突的嫌疑,但要检查一下是不是重复预约了
                    if start == Astart and finish == Afinish and appoint.Ausage == contents['Ausage'] \
                            and appoint.Aannouncement == contents['announcement'] and appoint.Ayp_num == len(students) \
                            and appoint.Anon_yp_num == contents['non_yp_num'] and contents['Sid'] == appoint.major_student_id:
                        # Room不用检查,肯定是同一个房间
                        utils.operation_writer(
                            major_student.Sid,
                            "重复发起同时段预约,预约号" + str(appoint.Aid),
                            "scheduler_func.addAppoint", "OK")
                        return JsonResponse({'data': appoint.toJson()},
                                            status=200)
                    else:
                        # 预约冲突
                        return JsonResponse(
                            {
                                'statusInfo': {
                                    'message': '预约时间与已有预约冲突,请重选时间段!',
                                    'detail': appoint.toJson()
                                }
                            },
                            status=400)

            # 确认信用分符合要求
            try:
                assert major_student.Scredit > 0
            except:
                return JsonResponse(
                    {'statusInfo': {
                        'message': '信用分不足,本月无法发起预约!',
                    }},
                    status=400)

            # 合法,可以返回了
            appoint = Appoint(Room=room,
                              Astart=Astart,
                              Afinish=Afinish,
                              Ausage=contents['Ausage'],
                              Aannouncement=contents['announcement'],
                              major_student=major_student,
                              Anon_yp_num=contents['non_yp_num'],
                              Ayp_num=len(students),
                              Atemp_flag=contents['Atemp_flag'])
            appoint.save()
            for student in students:
                appoint.students.add(student)
            appoint.save()

            # modify by pht: 整合定时任务为函数
            set_scheduler(appoint)
            set_start_wechat(appoint,
                             students_id=students_id,
                             notify_new=bool(contents.get('new_require',
                                                          True)))

            utils.operation_writer(major_student.Sid,
                                   "发起预约,预约号" + str(appoint.Aid),
                                   "scheduler_func.addAppoint", "OK")

    except Exception as e:
        utils.operation_writer(
            global_info.system_log,
            "学生" + str(major_student) + "出现添加预约失败的问题:" + str(e),
            "scheduler_func.addAppoint", "Error")
        return JsonResponse({'statusInfo': {
            'message': '添加预约失败!请与管理员联系!',
        }},
                            status=400)

    return JsonResponse({'data': appoint.toJson()}, status=200)
Ejemplo n.º 11
0
def set_start_wechat(appoint, students_id=None, notify_new=True):
    '''将预约成功和开始前的提醒定时发送给微信'''
    if students_id is None:
        students_id = list(appoint.students.all().values_list('Sid',
                                                              flat=True))
    # write by cdf end2
    # modify by pht: 如果已经开始,非临时预约记录log
    if datetime.now() >= appoint.Astart:
        # add by lhw : 临时预约 #
        if appoint.Atemp_flag == True:
            scheduler.add_job(
                utils.send_wechat_message,
                args=[
                    students_id,
                    appoint.Astart,
                    appoint.Room,
                    "temp_appointment",
                    appoint.major_student.Sname,
                    appoint.Ausage,
                    appoint.Aannouncement,
                    appoint.Anon_yp_num + appoint.Ayp_num,
                    '',
                    # appoint.major_student.Scredit,
                ],
                id=f'{appoint.Aid}_start_wechat',
                replace_existing=True,
                next_run_time=datetime.now() + timedelta(seconds=5))
        else:
            utils.operation_writer(
                global_info.system_log,
                "预约" + str(appoint.Aid) + "尝试发送给微信时已经开始,且并非临时预约",
                'scheduler_func.set_start_wechat', "Problem")
            return False
    elif datetime.now() <= appoint.Astart - timedelta(
            minutes=15):  # 距离预约开始还有15分钟以上,提醒有新预约&定时任务
        # print('距离预约开始还有15分钟以上,提醒有新预约&定时任务', notify_new)
        if notify_new:  # 只有在非长线预约中才添加这个job
            scheduler.add_job(
                utils.send_wechat_message,
                args=[
                    students_id,
                    appoint.Astart,
                    appoint.Room,
                    "new",
                    appoint.major_student.Sname,
                    appoint.Ausage,
                    appoint.Aannouncement,
                    appoint.Anon_yp_num + appoint.Ayp_num,
                    '',
                    # appoint.major_student.Scredit,
                ],
                id=f'{appoint.Aid}_new_wechat',
                replace_existing=True,
                next_run_time=datetime.now() + timedelta(seconds=5))
        scheduler.add_job(
            utils.send_wechat_message,
            args=[
                students_id,
                appoint.Astart,
                appoint.Room,
                "start",
                appoint.major_student.Sname,
                appoint.Ausage,
                appoint.Aannouncement,
                appoint.Ayp_num + appoint.Anon_yp_num,
                '',
                # appoint.major_student.Scredit,
            ],
            id=f'{appoint.Aid}_start_wechat',
            replace_existing=True,
            next_run_time=appoint.Astart - timedelta(minutes=15))
    else:  # 距离预约开始还有不到15分钟,提醒有新预约并且马上开始
        # send_status, err_message = utils.send_wechat_message(students_id, appoint.Astart, appoint.Room,"new&start")
        scheduler.add_job(
            utils.send_wechat_message,
            args=[
                students_id,
                appoint.Astart,
                appoint.Room,
                "new&start",
                appoint.major_student.Sname,
                appoint.Ausage,
                appoint.Aannouncement,
                appoint.Anon_yp_num + appoint.Ayp_num,
                '',
                # appoint.major_student.Scredit,
            ],
            id=f'{appoint.Aid}_start_wechat',
            replace_existing=True,
            next_run_time=datetime.now() + timedelta(seconds=5))
    return True
Ejemplo n.º 12
0
def index(request):  # 主页
    search_code = 0
    warn_code = 0
    message_code = 0
    login_url = global_info.login_url
    # 处理学院公告
    if (College_Announcement.objects.all()):
        try:
            message_item = College_Announcement.objects.get(
                show=College_Announcement.Show_Status.Yes)
            show_message = message_item.announcement
            message_code = 1
            # 必定只有一个才能继续
        except:
            message_code = 0
            # print("无法顺利呈现公告,原因可能是没有将状态设置为YES或者超过一条状态被设置为YES")

    # 用户校验
    if global_info.account_auth:
        # print("check", identity_check(request))
        if not identity_check(request):
            try:
                if request.method == "GET":
                    stu_id_ming = request.GET['Sid']
                    stu_id_code = request.GET['Secret']
                    timeStamp = request.GET['timeStamp']
                    request.session['Sid'] = stu_id_ming
                    request.session['Secret'] = stu_id_code
                    request.session['timeStamp'] = timeStamp
                    assert identity_check(request) is True

                else:  # POST 说明是display的修改,但是没登陆,自动错误
                    raise SystemError
            except:
                return redirect(direct_to_login(request))

                # 至此获得了登录的授权 但是这个人可能不存在 加判断
            try:
                request.session['Sname'] = Student.objects.get(
                    Sid=request.session['Sid']).Sname
                # modify by pht: 自动更新姓名
                if request.session['Sname'] == '未命名' and request.GET.get(
                        'name'):
                    # 获取姓名和首字母
                    given_name = request.GET['name']
                    pinyin_list = pypinyin.pinyin(given_name,
                                                  style=pypinyin.NORMAL)
                    szm = ''.join([w[0][0] for w in pinyin_list])

                    # 更新数据库和session
                    with transaction.atomic():
                        Student.objects.select_for_update().filter(
                            Sid=request.session['Sid']).update(
                                Sname=given_name, pinyin=szm)
                    request.session['Sname'] = given_name
            except:
                # 没有这个人 自动添加并提示
                if global_info.allow_newstu_appoint:
                    with transaction.atomic():
                        success = 1
                        try:
                            given_name = request.GET['name']
                        except:
                            operation_writer(
                                global_info.system_log,
                                f"创建未命名用户:学号为{request.session['Sid']}",
                                "views.index", "Problem")
                            given_name = "未命名"
                            success = 0
                        # 设置首字母
                        pinyin_list = pypinyin.pinyin(given_name,
                                                      style=pypinyin.NORMAL)
                        szm = ''.join([w[0][0] for w in pinyin_list])

                        student = Student(Sid=request.session['Sid'],
                                          Sname=given_name,
                                          Scredit=3,
                                          superuser=0,
                                          pinyin=szm)

                        student.save()
                        request.session['Sname'] = given_name
                        warn_code = 1
                        if success == 1:
                            warn_message = "数据库不存在学生信息,已为您自动创建!"
                        else:
                            warn_message = "数据库不存在学生信息,已为您自动创建,请联系管理员修改您的姓名!"
                else:  # 学生不存在
                    request.session['Sid'] = "0000000000"
                    request.session['Secret'] = ""  # 清空信息
                    # request.session['Sname'] = Student.objects.get(
                    # Sid=request.session['Sid']).Sname
                    warn_code = 1
                    warn_message = "数据库不存在学生信息,请联系管理员添加!在此之前,您只能查看实时人数."

    else:
        request.session['Sid'] = global_info.debug_stuid
        request.session['Sname'] = Student.objects.get(
            Sid=request.session['Sid']).Sname

    #--------- 前端变量 ---------#

    room_list = Room.objects.all()
    now, tomorrow = datetime.now(), datetime.today() + timedelta(days=1)
    occupied_rooms = Appoint.objects.not_canceled().filter(
        Astart__lte=now + timedelta(minutes=15),
        Afinish__gte=now).values('Room')  # 接下来有预约的房间
    future_appointments = Appoint.objects.not_canceled().filter(
        Astart__gte=now + timedelta(minutes=15), Astart__lt=tomorrow)  # 接下来的预约
    room_appointments = {room.Rid: None for room in room_list}
    for appointment in future_appointments:  # 每个房间的预约
        room_appointments[appointment.Room.Rid] = min(
            room_appointments[appointment.Room.Rid] or timedelta(1),
            appointment.Astart - now)

    def format(delta):  # 格式化timedelta,隐去0h
        if delta is None:
            return None
        hour, rem = divmod(delta.seconds, 3600)
        return f"{rem // 60}min" if hour == 0 else f"{hour}h{rem // 60}min"

    #--------- 1,2 地下室状态部分 ---------#

    double_list = ['航模', '绘画', '书法']
    function_room_list = room_list.exclude(Rid__icontains="R").filter(
        Rstatus=Room.Status.PERMITTED).filter(
            ~Q(Rtitle__icontains="研讨") | Q(Rtitle__icontains="绘画")
            | Q(Rtitle__icontains="航模")
            | Q(Rtitle__icontains="书法")).order_by('Rid')

    #--------- 地下室状态:left tab ---------#
    suspended_room_list = room_list.filter(
        Rstatus=Room.Status.SUSPENDED).order_by('-Rtitle')  # 开放房间
    statistics_info = [(room, (room.Rpresent * 10) // (room.Rmax or 1))
                       for room in suspended_room_list]  # 开放房间人数统计

    #--------- 地下室状态:right tab ---------#
    talk_room_list = room_list.filter(  # 研讨室(展示临时预约)
        Rtitle__icontains="研讨").filter(Rstatus=Room.Status.PERMITTED).order_by(
            'Rmin', 'Rid')
    room_info = [
        (
            room,
            {
                'Room': room.Rid
            } in occupied_rooms,
            format(  # 研讨室占用情况
                room_appointments[room.Rid])) for room in talk_room_list
    ]

    #--------- 3 俄文楼部分 ---------#

    russian_room_list = room_list.filter(
        Rstatus=Room.Status.PERMITTED).filter(  # 俄文楼
            Rid__icontains="R").order_by('Rid')
    russ_len = len(russian_room_list)
    if request.method == "POST":

        # YHT: added for Russian search
        request_time = request.POST.get("request_time", None)
        russ_request_time = request.POST.get("russ_request_time", None)
        check_type = ""
        if request_time is None and russ_request_time is not None:
            check_type = "russ"
            request_time = russ_request_time
        elif request_time is not None and russ_request_time is None:
            check_type = "talk"
        else:
            return render(request, 'Appointment/index.html', locals())

        if request_time != None and request_time != "":  # 初始加载或者不选时间直接搜索则直接返回index页面,否则进行如下反查时间
            day, month, year = int(request_time[:2]), int(
                request_time[3:5]), int(request_time[6:10])
            re_time = datetime(year, month, day)  # 获取目前request时间的datetime结构
            if re_time.date() < datetime.now().date():  # 如果搜过去时间
                search_code = 1
                search_message = "请不要搜索已经过去的时间!"
                return render(request, 'Appointment/index.html', locals())
            elif re_time.date() - datetime.now().date() > timedelta(days=6):
                # 查看了7天之后的
                search_code = 1
                search_message = "只能查看最近7天的情况!"
                return render(request, 'Appointment/index.html', locals())
            # 到这里 搜索没问题 进行跳转
            urls = reverse("Appointment:arrange_talk") + "?year=" + str(
                year) + "&month=" + str(month) + "&day=" + str(
                    day) + "&type=" + check_type
            # YHT: added for Russian search
            return redirect(urls)

    return render(request, 'Appointment/index.html', locals())
Ejemplo n.º 13
0
    def confirm(self, request, queryset):  # 确认通过
        if not request.user.is_superuser:
            return self.message_user(request=request,
                                     message='操作失败,没有权限,请联系老师!',
                                     level=messages.WARNING)
        some_invalid = 0
        have_success = 0
        try:
            with transaction.atomic():
                for appoint in queryset:
                    if appoint.Astatus == Appoint.Status.WAITING:
                        appoint.Astatus = Appoint.Status.CONFIRMED
                        appoint.save()
                        have_success = 1
                        # send wechat message
                        scheduler.add_job(
                            send_wechat_message,
                            args=[
                                [appoint.major_student.Sid],  # stuid_list
                                appoint.Astart,  # start_time
                                appoint.Room,  # room
                                "confirm_admin_w2c",  # message_type
                                appoint.major_student.Sname,  # major_student
                                appoint.Ausage,  # usage
                                appoint.Aannouncement,
                                appoint.Ayp_num + appoint.Anon_yp_num,
                                appoint.get_status(),  # reason
                                # appoint.major_student.Scredit,
                            ],
                            id=f'{appoint.Aid}_confirm_admin_wechat',
                            next_run_time=datetime.now() +
                            timedelta(seconds=5))  # 5s足够了
                        operation_writer(
                            global_info.system_log,
                            str(appoint.Aid) + "号预约被管理员从WAITING改为CONFIRMED" +
                            "发起人:" + str(appoint.major_student),
                            "admin.confirm", "OK")
                    elif appoint.Astatus == Appoint.Status.VIOLATED:
                        appoint.Astatus = Appoint.Status.JUDGED
                        # for stu in appoint.students.all():
                        if appoint.major_student.Scredit < 3:
                            appoint.major_student.Scredit += 1
                            appoint.major_student.save()
                        appoint.save()
                        have_success = 1
                        # send wechat message
                        scheduler.add_job(
                            send_wechat_message,
                            args=[
                                [appoint.major_student.Sid],  # stuid_list
                                appoint.Astart,  # start_time
                                appoint.Room,  # room
                                "confirm_admin_v2j",  # message_type
                                appoint.major_student.Sname,  # major_student
                                appoint.Ausage,  # usage
                                appoint.Aannouncement,
                                appoint.Ayp_num + appoint.Anon_yp_num,
                                appoint.get_status(),  # reason
                                #appoint.major_student.Scredit,
                            ],
                            id=f'{appoint.Aid}_confirm_admin_wechat',
                            next_run_time=datetime.now() +
                            timedelta(seconds=5))  # 5s足够了
                        operation_writer(
                            global_info.system_log,
                            str(appoint.Aid) + "号预约被管理员从VIOLATED改为JUDGED" +
                            "发起人:" + str(appoint.major_student),
                            "admin.confirm", "OK")

                    else:  # 不允许更改
                        some_invalid = 1

        except:
            return self.message_user(request=request,
                                     message='操作失败!请与开发者联系!',
                                     level=messages.WARNING)
        if not some_invalid:
            return self.message_user(request, "更改状态成功!")
        else:
            if have_success:
                return self.message_user(
                    request=request,
                    message='部分修改成功!但遭遇状态不为等待、违约的预约,这部分预约不允许更改!',
                    level=messages.WARNING)
            else:
                return self.message_user(request=request,
                                         message='修改失败!不允许修改状态不为等待、违约的预约!',
                                         level=messages.WARNING)
Ejemplo n.º 14
0
def finishAppoint(Aid):  # 结束预约时的定时程序
    '''
    结束预约时的定时程序
    - 接受单个预约id
    - 可以处理任何状态的预约
    - 对于非终止状态,判断人数是否合格,并转化为终止状态

    要注意的是,由于定时任务可能执行多次,第二次的时候可能已经终止
    '''
    try:
        appoint = Appoint.objects.get(Aid=Aid)
    except:
        utils.operation_writer(
            global_info.system_log, f"预约{str(Aid)}意外消失", "web_func.finishAppoint", "Error")
    
    
    # 避免直接使用全局变量! by pht
    adjusted_camera_qualified_check_rate = global_info.camera_qualified_check_rate
    
    # --- add by pht: 终止状态 --- #
    TERMINATE_STATUSES = [
        Appoint.Status.CONFIRMED,
        Appoint.Status.VIOLATED,
        Appoint.Status.CANCELED,
        ]
    # --- add by pht(2021.9.4) --- #

    # 如果处于非终止状态,只需检查人数判断是否合格
    if appoint.Astatus not in TERMINATE_STATUSES:
        # 希望接受的非终止状态只有进行中,但其他状态也同样判定是否合格
        if appoint.Astatus != Appoint.Status.PROCESSING:
            utils.operation_writer(
                appoint.major_student.Sid,
                f"预约{str(Aid)}结束时状态为{appoint.get_status()}:照常检查是否合格",
                "web_func.finishAppoint", "Error")

        # 摄像头出现超时问题,直接通过
        if datetime.now() - appoint.Room.Rlatest_time > timedelta(minutes=15):
            appoint.Astatus = Appoint.Status.CONFIRMED  # waiting
            appoint.save()
            utils.operation_writer(
                appoint.major_student.Sid, f"预约{str(Aid)}的状态变为{Appoint.Status.CONFIRMED}: 顺利完成", "web_func.finishAppoint", "OK")
        else:
            #if appoint.Acamera_check_num == 0:
            #    utils.operation_writer(
            #        global_info.system_log, f"预约{str(Aid)}的摄像头检测次数为零", "web_func.finishAppoint", "Error")
            # 检查人数是否足够

            # added by pht: 需要根据状态调整 出于复用性和简洁性考虑在本函数前添加函数
            # added by pht: 同时出于安全考虑 在本函数中重定义了本地rate 稍有修改 避免出错
            adjusted_camera_qualified_check_rate = get_adjusted_qualified_rate(
                original_qualified_rate=adjusted_camera_qualified_check_rate,
                appoint=appoint
            )
            
            if appoint.Acamera_ok_num < appoint.Acamera_check_num * adjusted_camera_qualified_check_rate - 0.01:  # 人数不足
                # add by lhw : 迟到的预约通知在这里处理。如果迟到不扣分,删掉这个if的内容即可,让下面那个camera check的if判断是否违规。
                if appoint.Areason == Appoint.Reason.R_LATE:
                    status, tempmessage = utils.appoint_violate(
                        appoint, Appoint.Reason.R_LATE)
                    if not status:
                        utils.operation_writer(
                            global_info.system_log, f"预约{str(Aid)}因迟到而违约时出现异常: {tempmessage}", "web_func.finishAppoint", "Error")
                else:
                    status, tempmessage = utils.appoint_violate(
                        appoint, Appoint.Reason.R_TOOLITTLE)
                    if not status:
                        utils.operation_writer(
                            global_info.system_log, f"预约{str(Aid)}因人数不够而违约时出现异常: {tempmessage}", "web_func.finishAppoint", "Error")

            else:   # 通过
                appoint.Astatus = Appoint.Status.CONFIRMED
                appoint.save()
                utils.operation_writer(
                    global_info.system_log, f"预约{str(Aid)}人数合格,已通过", "web_func.finishAppoint", "OK")

    else:
        if appoint.Astatus == Appoint.Status.CONFIRMED:   # 可能已经判定通过,如公共区域和俄文楼
            rid = appoint.Room.Rid
            if rid[:1] != 'R' and rid not in {'B109A', 'B207'}:
                utils.operation_writer(
                    global_info.system_log, f"预约{str(Aid)}提前合格: {rid}房间", "web_func.finishAppoint", "Problem")

        elif appoint.Astatus != Appoint.Status.CANCELED:    # 状态异常,多半是已经判定过了
            utils.operation_writer(
                global_info.system_log, f"预约{str(Aid)}提前终止: {appoint.get_status()}", "web_func.finishAppoint", "Problem")
def finishFunction(Aid):  # 结束预约时的定时程序
    # 变更预约状态
    appoint = Appoint.objects.get(Aid=Aid)
    mins15 = timedelta(minutes=15)
    # 避免直接使用全局变量! by pht
    adjusted_camera_qualified_check_rate = global_info.camera_qualified_check_rate
    try:
        # 如果处于进行中,表示没有迟到,只需检查人数
        if appoint.Astatus == Appoint.Status.PROCESSING:

            # 摄像头出现超时问题,直接通过
            if datetime.now() - appoint.Room.Rlatest_time > mins15:
                appoint.Astatus = Appoint.Status.CONFIRMED  # waiting
                appoint.save()
                utils.operation_writer(
                    appoint.major_student.Sid,
                    "顺利完成预约" + str(appoint.Aid) + ",设为Confirm",
                    "func[finishAppoint]", "OK")
            else:
                if appoint.Acamera_check_num == 0:
                    utils.operation_writer(
                        global_info.system_log,
                        "预约" + str(appoint.Aid) + "摄像头检测次数为0", "finishAppoint",
                        "Problem")
                # 检查人数是否足够

                # added by pht: 需要根据状态调整 出于复用性和简洁性考虑在本函数前添加函数
                # added by pht: 同时出于安全考虑 在本函数中重定义了本地rate 稍有修改 避免出错
                adjusted_camera_qualified_check_rate = get_adjusted_qualified_rate(
                    original_qualified_rate=
                    adjusted_camera_qualified_check_rate,
                    appoint=appoint,
                )

                if appoint.Acamera_ok_num < appoint.Acamera_check_num * adjusted_camera_qualified_check_rate - 0.01:  # 人数不足
                    status, tempmessage = utils.appoint_violate(
                        appoint, Appoint.Reason.R_TOOLITTLE)
                    if not status:
                        utils.operation_writer(
                            global_info.system_log, "预约" + str(appoint.Aid) +
                            "因人数不够而违约时出现异常: " + tempmessage,
                            "func[finishAppoint]", "Error")

                else:  # 通过
                    appoint.Astatus = Appoint.Status.CONFIRMED
                    appoint.save()

        # 表示压根没刷卡
        elif appoint.Astatus == Appoint.Status.APPOINTED:
            # 特殊情况,不违约(地下室小舞台&康德,以及俄文楼)
            if (appoint.Room_id in {"B109A", "B207"}) or ('R'
                                                          in appoint.Room_id):
                appoint.Astatus = Appoint.Status.CONFIRMED
                appoint.save()
                utils.operation_writer(
                    appoint.major_student.Sid,
                    "顺利完成预约" + str(appoint.Aid) + ",设为Confirm",
                    "func[finishAppoint]", "OK")
            else:
                status, tempmessage = utils.appoint_violate(
                    appoint, Appoint.Reason.R_LATE)
                if not status:
                    utils.operation_writer(
                        global_info.system_log, "预约" + str(appoint.Aid) +
                        "因迟到而违约时出现异常: " + tempmessage, "func[finishAppoint]",
                        "Error")

    # 如果上述过程出现不可预知的错误,记录
    except Exception as e:
        utils.operation_writer(
            global_info.system_log, "预约" + str(appoint.Aid) + "在完成时出现异常:" +
            str(e) + ",提交为waiting状态,请处理!", "func[finishAppoint]", "Error")
        appoint.Astatus = Appoint.Status.WAITING  # waiting
        appoint.save()
Ejemplo n.º 16
0
    def longterm_wk(self, request, queryset, week_num):
        if not request.user.is_superuser:
            return self.message_user(request=request,
                                     message='操作失败,没有权限,请联系老师!',
                                     level=messages.WARNING)
        if len(queryset) != 1:
            return self.message_user(request=request,
                                     message='每次仅允许将一条预约长线化!',
                                     level=messages.WARNING)
        for appoint in queryset:
            # print(appoint)
            try:
                with transaction.atomic():
                    stuid_list = [stu.Sid for stu in appoint.students.all()]
                    for i in range(week_num):
                        # 调用函数完成预约
                        feedback = addAppoint({
                            'Rid':
                            appoint.Room.Rid,
                            'students':
                            stuid_list,
                            'non_yp_num':
                            appoint.Anon_yp_num,
                            'Astart':
                            appoint.Astart + (i + 1) * timedelta(days=7),
                            'Afinish':
                            appoint.Afinish + (i + 1) * timedelta(days=7),
                            'Sid':
                            appoint.major_student.Sid,
                            'Ausage':
                            appoint.Ausage,
                            'announcement':
                            appoint.Aannouncement,
                            'new_require':  # 长线预约,不需要每一个都添加信息, 直接统一添加
                            0
                        })
                        if feedback.status_code != 200:  # 成功预约
                            warning = eval(
                                feedback.content.decode(
                                    'unicode-escape'))['statusInfo']['message']
                            print(warning)
                            raise Exception(warning)
                        '''
                        newappoint = Appoint(
                            Room=appoint.Room,
                            Astart=appoint.Astart + (i+1) * timedelta(days=7),
                            Afinish=appoint.Afinish + \
                                (i+1) * timedelta(days=7),
                            Ausage=appoint.Ausage,
                            Aannouncement=appoint.Aannouncement,
                            major_student=appoint.major_student,
                            Anon_yp_num=appoint.Anon_yp_num,
                            Ayp_num=appoint.Ayp_num
                        )
                        newappoint.save()
                        for tempstudent in appoint.students.all():
                            print(tempstudent)
                            newappoint.students.add(tempstudent)
                        newappoint.save()
                        '''
            except Exception as e:
                operation_writer(
                    global_info.system_log, "学生" + str(appoint.major_student) +
                    "出现添加长线化预约失败的问题:" + str(e), "admin.longterm", "Problem")
                return self.message_user(request=request,
                                         message=str(e),
                                         level=messages.WARNING)

            # 到这里, 长线化预约发起成功
            scheduler.add_job(
                send_wechat_message,
                args=[
                    stuid_list,  # stuid_list
                    appoint.Astart,  # start_time
                    appoint.Room,  # room
                    "longterm",  # message_type
                    appoint.major_student.Sname,  # major_student
                    appoint.Ausage,  # usage
                    appoint.Aannouncement,
                    len(stuid_list) + appoint.Anon_yp_num,
                    week_num,  # reason, 这里用作表示持续周数
                    #appoint.major_student.Scredit,
                ],
                id=f'{appoint.Aid}_new_wechat',
                next_run_time=datetime.now() + timedelta(seconds=5))  # 2s足够了
            operation_writer(
                appoint.major_student.Sid,
                "发起" + str(week_num) + "周的长线化预约, 原始预约号" + str(appoint.Aid),
                "admin.longterm", "OK")
        return self.message_user(request, '长线化成功!')
def cancelFunction(request):  # 取消预约
    
    warn_code = 0
    try:
        Aid = request.POST.get('cancel_btn')
        appoints = Appoint.objects.filter(Astatus=Appoint.Status.APPOINTED)
        appoint = appoints.get(Aid=Aid)
    except:
        warn_code = 1
        warning = "预约不存在、已经开始或者已取消!"
        # return render(request, 'Appointment/admin-index.html', locals())
        return redirect(
            reverse("Appointment:admin_index") + "?warn_code=" +
            str(warn_code) + "&warning=" + warning)

    try:
        assert appoint.major_student.Sid == request.session['Sid']
    except:
        warn_code = 1
        warning = "请不要恶意尝试取消不是自己发起的预约!"
        # return render(request, 'Appointment/admin-index.html', locals())
        return redirect(
            reverse("Appointment:admin_index") + "?warn_code=" +
            str(warn_code) + "&warning=" + warning)

    if appoint.Astart < datetime.now() + timedelta(minutes=30):
        warn_code = 1
        warning = "不能取消开始时间在30分钟之内的预约!"
        return redirect(
            reverse("Appointment:admin_index") + "?warn_code=" +
            str(warn_code) + "&warning=" + warning)
    # 先准备发送人
    stu_list = [stu.Sid for stu in appoint.students.all()]
    with transaction.atomic():
        appoint_room_name = appoint.Room.Rtitle
        appoint.cancel()
        try:
            scheduler.remove_job(f'{appoint.Aid}_finish')
        except:
            utils.operation_writer(global_info.system_log, "预约"+str(appoint.Aid) +
                             "取消时发现不存在计时器", 'func[cancelAppoint]', "Problem")
        utils.operation_writer(appoint.major_student.Sid, "取消了预约" +
                         str(appoint.Aid), "func[cancelAppoint]", "OK")
        warn_code = 2
        warning = "成功取消对" + appoint_room_name + "的预约!"
    # send_status, err_message = utils.send_wechat_message([appoint.major_student.Sid],appoint.Astart,appoint.Room,"cancel")
    # todo: to all
        print('will send cancel message')
        scheduler.add_job(utils.send_wechat_message,
                          args=[stu_list,
                                appoint.Astart,
                                appoint.Room,
                                "cancel",
                                appoint.major_student.Sname,
                                appoint.Ausage,
                                appoint.Aannouncement,
                                appoint.Anon_yp_num+appoint.Ayp_num,
                                '',
                                #appoint.major_student.Scredit,
                                ],
                          id=f'{appoint.Aid}_cancel_wechat',
                          next_run_time=datetime.now() + timedelta(seconds=5))
    '''
    if send_status == 1:
        # 记录错误信息
        utils.operation_writer(global_info.system_log, "预约" +
                             str(appoint.Aid) + "取消时向微信发消息失败,原因:"+err_message, "func[addAppoint]", "Problem")
    '''

    # cancel wechat scheduler
    try:
        scheduler.remove_job(f'{appoint.Aid}_start_wechat')
    except:
        utils.operation_writer(global_info.system_log, "预约"+str(appoint.Aid) +
                         "取消时发现不存在wechat计时器,但也可能本来就没有", 'func[cancelAppoint]', "Problem")

    return redirect(
        reverse("Appointment:admin_index") + "?warn_code=" + str(warn_code) +
        "&warning=" + warning)
Ejemplo n.º 18
0
def cameracheck(request):  # 摄像头post的后端函数

    # 获取摄像头信号,得到rid,最小人数
    try:
        ip = request.META.get("REMOTE_ADDR")
        temp_stu_num = int(
            eval(request.body.decode('unicode-escape'))['body']['people_num'])
        rid = iptoroom(ip.split(".")[3])  # !!!!!
        # rid = 'B221'  # just for debug
        room = Room.objects.get(Rid=rid)  # 获取摄像头信号
        num_need = room.Rmin  # 最小房间人数
    except:
        return JsonResponse({'statusInfo': {
            'message': '缺少摄像头信息!',
        }},
                            status=400)
    now_time = datetime.now()

    # 存储上一次的检测时间
    room_previous_check_time = room.Rlatest_time

    # 更新现在的人数、最近更新时间
    try:
        with transaction.atomic():
            room.Rpresent = temp_stu_num
            room.Rlatest_time = now_time
            room.save()

    except Exception as e:
        operation_writer(global_info.system_log,
                         "房间" + str(rid) + "更新摄像头人数失败1: " + str(e),
                         "views.cameracheck", "Error")

        return JsonResponse({'statusInfo': {
            'message': '更新摄像头人数失败!',
        }},
                            status=400)

    # 检查时间问题,可能修改预约状态;
    appointments = Appoint.objects.not_canceled().filter(
        Q(Astart__lte=now_time) & Q(Afinish__gte=now_time)
        & Q(Room_id=rid))  # 只选取状态在1,2之间的预约

    if len(appointments):  # 如果有,只能有一个预约
        content = appointments[0]
        if room.Rid == "B107B":
            # 107b的监控不太靠谱,正下方看不到
            num_need = min(max(global_info.today_min, num_need - 2), num_need)
        elif room.Rid == "B217":
            # 地下室关灯导致判定不清晰,晚上更严重
            if content.Astart.hour >= 20:
                num_need = min(max(global_info.today_min, num_need - 2),
                               num_need)
            else:
                num_need = min(max(global_info.today_min, num_need - 1),
                               num_need)
        if content.Atime.date() == content.Astart.date():
            # 如果预约时间在使用时间的24h之内 则人数下限为2
            num_need = min(global_info.today_min, num_need)
        if content.Atemp_flag == Appoint.Bool_flag.Yes:
            # 如果为临时预约 则人数下限为1 不作为合格标准 只是记录
            num_need = min(global_info.temporary_min, num_need)
        try:
            if room.Rid in {"B109A", "B207"}:  # 康德报告厅&小舞台 不考虑违约
                content.Astatus = Appoint.Status.CONFIRMED
                content.save()
            else:  # 其他房间

                # added by wxy
                # 检查人数:采样、判断、更新
                # 人数在finishappoint中检查
                # modified by pht - 2021/8/15
                # 增加UNSAVED状态
                # 逻辑是尽量宽容,因为一分钟只记录两次,两次随机大概率只有一次成功
                # 所以没必要必须随机成功才能修改错误结果
                rand = random.uniform(0, 1)
                camera_lock.acquire()
                with transaction.atomic():
                    if now_time.minute != room_previous_check_time.minute or\
                            content.Acheck_status == Appoint.Check_status.UNSAVED:
                        # 说明是新的一分钟或者本分钟还没有记录
                        # 如果随机成功,记录新的检查结果
                        if rand < global_info.check_rate:
                            content.Acheck_status = Appoint.Check_status.FAILED
                            content.Acamera_check_num += 1
                            if temp_stu_num >= num_need:  # 如果本次检测合规
                                content.Acamera_ok_num += 1
                                content.Acheck_status = Appoint.Check_status.PASSED
                        # 如果随机失败,锁定上一分钟的结果
                        else:
                            if content.Acheck_status == Appoint.Check_status.FAILED:
                                # 如果本次检测合规,宽容时也算上一次通过(因为一分钟只检测两次)
                                if temp_stu_num >= num_need:
                                    content.Acamera_ok_num += 1
                            # 本分钟暂无记录
                            content.Acheck_status = Appoint.Check_status.UNSAVED
                    else:
                        # 和上一次检测在同一分钟,此时:1.不增加检测次数 2.如果合规则增加ok次数
                        if content.Acheck_status == Appoint.Check_status.FAILED:
                            # 当前不合规;如果这次检测合规,那么认为本分钟合规
                            if temp_stu_num >= num_need:
                                content.Acamera_ok_num += 1
                                content.Acheck_status = Appoint.Check_status.PASSED
                        # else:当前已经合规,不需要额外操作
                    content.save()
                camera_lock.release()
                # add end
        except Exception as e:
            operation_writer(global_info.system_log,
                             "预约" + str(content.Aid) + "更新摄像头人数失败2: " + str(e),
                             "views.cameracheck", "Error")

            return JsonResponse({'statusInfo': {
                'message': '更新预约状态失败!',
            }},
                                status=400)
        try:
            if now_time > content.Astart + timedelta(
                    minutes=15) and content.Astatus == Appoint.Status.APPOINTED:
                status, tempmessage = set_appoint_reason(
                    content, Appoint.Reason.R_LATE)
                # 该函数只是把appoint标记为迟到(填写reason)并修改状态为进行中,不发送微信提醒
                if not status:
                    operation_writer(
                        global_info.system_log, "预约" + str(content.Aid) +
                        "设置为迟到时的返回值异常 " + tempmessage, "views.cameracheck",
                        "Error")
        except Exception as e:
            operation_writer(
                global_info.system_log,
                "预约" + str(content.Aid) + "在迟到状态设置过程中: " + tempmessage,
                "views.cameracheck", "Error")
            # added by wxy: 违约原因:迟到
            # status, tempmessage = appoint_violate(
            #     content, Appoint.Reason.R_LATE)
            # if not status:
            #     operation_writer(global_info.system_log, "预约"+str(content.Aid) +
            #                      "因迟到而违约,返回值出现异常: "+tempmessage, "views.cameracheck", "Error")
        # except Exception as e:
        #     operation_writer(global_info.system_log, "预约"+str(content.Aid) +
        #                      "在迟到违约过程中: "+tempmessage, "views.cameracheck", "Error")

        return JsonResponse({}, status=200)  # 返回空就好
    else:  # 否则的话 相当于没有预约 正常返回
        return JsonResponse({}, status=200)  # 返回空就好