Esempio n. 1
0
    def _code_fork(request, code, user):
        '''复制已有公开代码'''

        # 权限检测
        if not (code.author == user or code.public):
            return sorry(request, 403, text='没有复制权限')

        # 验证用户代码数未超标
        if user.code_set.filter(
                ai_type=code.ai_type).count() >= settings.MAX_CODE_PER_GAME:
            return sorry(request, 403, text='已超过最大可保留代码数')

        # 生成新代码
        new_code = Code(ai_type=code.ai_type, author=user)
        new_code.edit_datetime = timezone.now()
        new_code.public = code.public
        new_code.name = ('副本-' + code.name)[:20]

        # 保存副本代码
        new_content = ContentFile(code.content.read())
        new_code.content.save('test', new_content)

        new_code.save()
        messages.info(request, '创建副本"%s"成功' % new_code.name)
        return redirect('/home/')
Esempio n. 2
0
def forgotpasswd(request, code=None):
    if code == None:  # 验证页面
        form = forms.ForgotPasswdForm()

        # 判断发送邮件逻辑
        if request.method == 'POST':
            form = forms.ForgotPasswdForm(request.POST)

            # 检查用户名与学号匹配情况
            if form.is_valid():
                name = request.POST.get('username')
                code = request.POST.get('stu_code')
                try:
                    user = User.objects.get(username=name, stu_code=code)
                except:
                    form.add_error('username', '用户名与学号不匹配')
                    form.add_error('stu_code', '用户名与学号不匹配')
                else:
                    # 小组用户无邮箱
                    if user.is_team:
                        return sorry(request,
                                     text=[
                                         '小组用户不可通过邮箱重置密码',
                                         '若忘记密码请联系课程团队',
                                     ])

            # 发送邮件
            if form.is_valid():
                send_valid_email(user, request, 'forgotpw')
                return redirect('/login/')
            else:
                messages.warning(request, '请检查非法输入')
        return render(request, 'forgotpasswd.html', locals())
    else:
        try:
            checker = UserResetPwMail.objects.get(check_hash=code)
            if timezone.now() > checker.send_time + timezone.timedelta(
                    settings.EMAIL_VALID_LAST_DAYS):
                raise ValueError

            form = forms.ResetPasswdForm()
            if request.method == 'POST':
                form = forms.ResetPasswdForm(request.POST)
                if request.POST.get('new_passwd') != request.POST.get(
                        'new_pw2'):
                    form.add_error('new_pw2', '两次密码输入不同')
                if form.is_valid():
                    checker.user.set_passwd(form.cleaned_data['new_pw2'])
                    set_user(request, checker.user)
                    messages.info(request, '密码已重设')
                    checker.delete()
                    return redirect('/home/')
                messages.warning(request, '请检查非法输入')
            return render(request, 'changepasswd.html', locals())
        except:
            return sorry(request, text='无效的链接')
Esempio n. 3
0
def course_results(request, AI_type, folder):
    try:
        AI_type = int(AI_type)
        assert AI_type in settings.AI_TYPES
    except:
        return sorry(request, text='无效的游戏类型')
    title = settings.AI_TYPES[AI_type]
    request.session['curr_game'] = AI_type  # 设置当前页面游戏
    loader = Factory(AI_type)

    file_folder = '%s/results/%03d' % (settings.MEDIA_ROOT, AI_type)
    if not os.path.isdir(file_folder):
        return sorry(request, text='比赛记录未开放')
    if folder:
        folder = folder.replace('\\', '/').rstrip('/')
        file_folder = os.path.join(file_folder, folder)
    print(file_folder)
    if not (os.path.isdir(file_folder)):
        if os.path.isfile(file_folder):
            return course_view(request, AI_type, file_folder)
        return sorry(request, text='目录不存在')
    pool = os.listdir(file_folder)
    folders, files, errors = [], [], []
    for f in pool:
        f1 = os.path.join(file_folder, f)
        if os.path.isfile(f1):  # 读取记录
            try:
                rec_unit = {
                    'name': f,  # 记录名称
                    'record': loader.load_record_path(f1),  # 记录对象
                    'time': time.ctime(os.path.getmtime(f1)),  # 修改时间
                }
                files.append(rec_unit)
            except Exception as e:
                errors.append(f)
        else:
            folders.append(f)

    # 加载tags
    for record in files:
        record['tags'] = loader.analyze_tags(record['record'])

    # 根据GET参数决定排序方式
    sort_method = request.GET.get(
        'sort',
        request.session.get('course_results_sort', 'name'),
    )
    request.session['course_results_sort'] = sort_method  # 缓存参数于session中
    sort_keys = {'name': '名称', 'time': '时间'}
    for key in sort_keys:
        if sort_method == key:
            files.sort(key=lambda x: x[key])
            break

    return render(request, 'results/filetree.html', locals())
Esempio n. 4
0
def game_info(request, AI_type):
    """列出所有可用的比赛,显示其规则,引用至站内对战入口与github项目"""
    # 验证游戏ID存在
    try:
        AI_type = int(AI_type)
        assert AI_type in settings.AI_TYPES
    except:
        return sorry(request, text='无效的游戏类型')
    title = settings.AI_TYPES[AI_type]
    request.session['curr_game'] = AI_type  # 设置当前页面游戏

    try:
        return render(request, 'game_info/%s.html' % AI_type, locals())
    except:
        return sorry(request, text='WORK IN PROGRESS')
Esempio n. 5
0
    def upload(request):
        ai_type = request.GET.get('id', '')
        user = get_user(request)

        if request.method == 'POST':
            form = forms.CodeUploadForm(request.POST, request.FILES)
            if form.is_valid():
                # 验证用户代码数未超标
                code_count = user.code_set.filter(
                    ai_type=form.cleaned_data['ai_type']).count()
                code_max = 1 if user.is_team else settings.MAX_CODE_PER_GAME
                if code_count >= code_max:
                    return sorry(request,
                                 403,
                                 text=[
                                     '已超过最大可上传代码数',
                                     '请删除不必要的代码',
                                     '或在已有代码上进行修改',
                                 ])

                code = form.instance
                code.author = user
                code.edit_datetime = timezone.now()
                form.save()
                messages.info(request, '上传文件"%s"成功' % code.name)
                return redirect('/home/')
            else:
                messages.warning(request, '请检查非法输入')
                return render(request, 'upload.html', locals())
        form = forms.CodeUploadForm()
        return render(request, 'upload.html', locals())
Esempio n. 6
0
    def view_record(request, match_name, record_id):
        try:
            match = PairMatch.objects.get(name=match_name)
        except:
            return sorry(request, text='无效的比赛地址')
        match_dir = os.path.join(settings.PAIRMATCH_DIR, match_name)
        loader = Factory(match.ai_type)
        try:
            record_id = int(record_id)
            record_content = loader.stringfy_record(match_dir, record_id)
        except:
            return sorry(request, text='无效的记录编号')

        not_last_record = (record_id + 1 != match.finished_rounds)

        return render(request, 'renderer/%s.html' % match.ai_type, locals())
Esempio n. 7
0
    def ladder(request, AI_type):
        '''天梯'''

        # 读取参数
        try:
            AI_type = int(AI_type)
            assert AI_type in settings.AI_TYPES
        except:
            return sorry(request, text='无效的比赛编号')
        title = settings.AI_TYPES[AI_type]
        request.session['curr_game'] = AI_type  # 设置当前页面游戏

        # 代码排序
        all_codes = Code.objects.filter(
            ai_type=AI_type,
            author__is_team=False,
        )

        # 用户均分统计
        user_info = all_codes.values('author').annotate(
            score=Max('score'), count=Count('id')).values(
                'author', 'score',
                'count').order_by('-score')[:settings.MAX_LADDER_USER]
        for grp in user_info:
            grp['user'] = User.objects.get(id=grp['author'])

        return render(request, 'ladder.html', locals())
Esempio n. 8
0
 def inner(request, *a, **kw):
     user = get_user(request)
     if user.is_team:
         return sorry(request, 403, text=[
             '当前页面不可访问',
             '小组用户所有比赛由系统自动发起',
         ])
     return func(request, *a, **kw)
Esempio n. 9
0
    def view_pairmatch(request, match_name):
        # 读取比赛对象
        try:
            match = PairMatch.objects.get(name=match_name)
        except:
            return sorry(request, text='无效的比赛地址')
        match_dir = os.path.join(settings.PAIRMATCH_DIR, match_name)

        # 检测权限
        user = get_user(request)
        my_match = (match.code1.author == user) or user.is_admin

        # 处理操作请求
        if my_match:
            op = request.GET.get('op')
            if match.status == 1 and op == 'stop':
                match_monitor.kill_match('match', match.name)
                messages.info(request, '比赛已中止')
            elif match.status != 1 and op == 'del':
                if not settings.CAN_DELETE_MATCH_RESULT:
                    return sorry(request, text='删除比赛记录功能已关闭')
                upper = match.code1.id
                match.delete()
                messages.info(request, '比赛记录已删除')
                return redirect('/code/%d' % upper)

        # 读取比赛记录
        loader = Factory(match.ai_type)
        records = loader.load_records(match)
        result_summary = loader.summary_records(records)
        result_stat = result_summary['stat']

        # 读取tag
        record_tags = []
        for record in records:
            try:
                record_tags.append(loader.analyze_tags(record))
            except:
                record_tags.append([])
        record_pairs = zip(records, record_tags)

        return render(request, 'view_match.html', locals())
Esempio n. 10
0
def course_view(request, AI_type, file):
    try:
        AI_type = int(AI_type)
        assert AI_type in settings.AI_TYPES
    except:
        return sorry(request, text='无效的游戏类型')
    title = settings.AI_TYPES[AI_type]

    loader = Factory(AI_type)
    record = loader.load_record_path(file)
    record_content = loader.stringfy_record_obj(record)
    return render(request, 'renderer/%s.html' % AI_type, locals())
Esempio n. 11
0
    def ranked_match(request, AI_type):
        '''积分匹配赛'''

        # 读取参数
        try:
            AI_type = int(AI_type)
            assert AI_type in settings.AI_TYPES
        except:
            return sorry(request, text='无效的比赛编号')
        title = settings.AI_TYPES[AI_type]
        request.session['curr_game'] = AI_type  # 设置当前页面游戏

        # 获取可选AI列表
        codes = Code.objects.filter(
            ai_type=AI_type,
            author__is_team=False,  # 排除小组代码
        )
        my_codes = codes.filter(author=request.session['userid'])  # 我方所有

        # 读取筛选条件
        my_code = request.GET.get('code1', '')

        if request.method == 'POST':
            form = forms.PairMatchFormFactory.get(AI_type, request.POST)
            my_code = request.POST.get('code1')
            if not (my_code and my_codes.filter(id=my_code)):
                form.errors['code1'] = '非法输入: %s' % my_code

            # 选取目标代码
            if form.is_valid():
                my_code_obj = my_codes.filter(id=my_code)[0]
                target_codes = codes.exclude(author=request.session['userid'])
                target_codes = sorted(
                    target_codes,
                    key=lambda code: abs(code.score - my_code_obj.score
                                         ))[:settings.RANKING_RANDOM_RANGE]
                if not target_codes:
                    form.errors['code1'] = '暂无可用的匹配代码'

            _limit_rounds(request, form, my_code)  # 限制发起局数

            if form.is_valid():  # run match
                target = random.choice(target_codes).id
                match_name = match_monitor.start_match(AI_type, my_code,
                                                       target, form, True)
                messages.info(request, '创建匹配赛成功')
                return redirect('/match/' + match_name)
            else:  # invalid input
                messages.warning(request, '请检查非法输入')
                return render(request, 'ranked_match.html', locals())
        form = forms.PairMatchFormFactory.get(AI_type)
        return render(request, 'ranked_match.html', locals())
Esempio n. 12
0
    def ladder_teams(request, AI_type):
        """ 小组账号限定天梯 """

        # 读取参数
        try:
            AI_type = int(AI_type)
            assert AI_type in settings.AI_TYPES
        except:
            return sorry(request, text='无效的比赛编号')
        title = settings.AI_TYPES[AI_type]
        request.session['curr_game'] = AI_type  # 设置当前页面游戏

        return render(request, 'ladder_teams.html', locals())
Esempio n. 13
0
    def view_code(request, code_id, code_op=None):
        '''查看代码对象、分发下级命令'''

        # 获取代码对象
        try:
            code = Code.objects.get(id=int(code_id))
        except:
            return sorry(request, text='无效的代码编号')

        # 检测权限
        user = get_user(request)
        my_code = (code.author == user) or user.is_admin

        # 代码主页
        if code_op == None:
            return render(request, 'view_code.html', locals())

        # 代码编辑页
        elif code_op == 'edit':
            return _code_editor(request, code, user, True)

        # 代码删除页
        elif code_op == 'del':
            return _code_del(request, code, user)

        # 查看公开代码
        elif code_op == 'view':
            return _code_editor(request, code, user, False)

        # 复制公开代码
        elif code_op == 'fork':
            if not settings.CAN_FORK_PUBLIC_CODE:
                return sorry(request, text='拷贝公开代码功能已关闭')
            return _code_fork(request, code, user)

        return sorry(request, text=['亲亲', '"%s"这样的命令' % code_op, '是不存在的呢'])
Esempio n. 14
0
def view_user(request, userid):
    '''其它用户主页,快速访问对战页面'''

    # 验证用户
    try:
        user = User.objects.get(id=userid)
    except:
        try:
            user = User.objects.get(username=userid)
        except:
            return sorry('该用户不存在')

    # 本用户主页
    if user.id == request.session.get('userid'):
        return redirect('/home/')

    return home(request, user)
Esempio n. 15
0
    def _code_del(request, code, user):
        '''验证密码删除代码'''

        # 权限检测
        if code.author != user or user.is_team:
            return sorry(request, 403, text='没有删除权限')

        # 检测密码验证
        if request.method == 'POST':
            pw = request.POST.get('check_pw', '')

            # 删除代码
            if user.match_passwd(pw):
                code.delete()
                messages.info(request, '代码已删除')
                return redirect('/home/')

            # 密码错误
            else:
                messages.warning(request, '密码错误')

        return render(request, 'delete_code.html', locals())
Esempio n. 16
0
def user_settings(request):
    '''
    个人设置
    '''
    user = get_user(request)
    form = forms.SettingsForm(request.POST or user.__dict__)

    # 小组用户不可修改
    if user.is_team:
        return sorry(request, 403, text='小组用户不可改名')

    # GET请求
    if request.method == 'GET':
        return render(request, 'settings.html', locals())

    form = forms.SettingsForm(request.POST)
    if form.is_valid():
        user.nickname = form.cleaned_data['nickname']
        user.real_name = form.cleaned_data['real_name']
        user.save()
        return redirect('/home/')
    else:
        messages.warning(request, '请检查非法输入')
        return render(request, 'changepasswd.html', locals())
Esempio n. 17
0
    def pairmatch(request, AI_type):
        '''启动一对一比赛'''

        # 读取参数
        try:
            AI_type = int(AI_type)
            assert AI_type in settings.AI_TYPES
        except:
            return sorry(request, text='无效的比赛编号')
        title = settings.AI_TYPES[AI_type]
        request.session['curr_game'] = AI_type  # 设置当前页面游戏

        # 获取可选AI列表
        codes = Code.objects.filter(
            ai_type=AI_type,
            author__is_team=False,  # 排除小组代码
        )
        my_codes = codes.filter(author=request.session['userid'])  # 我方所有
        # 筛选对方代码
        code2_empty = True
        try:
            target_user = request.GET.get('user2')
            if target_user:
                target_codes = codes.filter(author=target_user)
                if target_codes:
                    code2_empty = False
                else:
                    messages.warning(request, '用户没有上传代码')
        except:
            messages.warning(request, '输入用户非法')
        if code2_empty:
            target_codes = codes.all()  # 所有代码

        # 获取自由模式得分参数,转换为百分比
        score_ratio = settings.SCORE_FACTOR_NORANK * 100

        # 读取筛选条件
        my_code = request.GET.get('code1', '')
        target_code = request.GET.get('code2', '')

        if request.method == 'POST':
            form = forms.PairMatchFormFactory.get(AI_type, request.POST)
            my_code = request.POST.get('code1')
            target_code = request.POST.get('code2')
            if not (my_code and my_codes.filter(id=my_code)):
                form.errors['code1'] = '非法输入: %s' % my_code
            if not (target_code and target_codes.filter(id=target_code)):
                form.errors['code2'] = '非法输入: %s' % target_code

            _limit_rounds(request, form, my_code)  # 限制发起局数

            if form.is_valid():  # run match
                match_name = match_monitor.start_match(AI_type, my_code,
                                                       target_code, form)
                messages.info(request, '创建比赛成功')
                return redirect('/match/' + match_name)
            else:  # invalid input
                messages.warning(request, '请检查非法输入')
                return render(request, 'pairmatch.html', locals())
        form = forms.PairMatchFormFactory.get(AI_type)
        return render(request, 'pairmatch.html', locals())
Esempio n. 18
0
    def _code_editor(request, code, user, is_edit):
        '''
        CodeMirror代码编辑器页
        提供编辑自己代码+查看公开代码功能
        '''

        # 检测权限及重定向
        my_code = (code.author == user) or user.is_admin

        if is_edit:
            if not my_code:  # 非本人进入编辑模式
                return redirect('/code/%s/view/' % code.id)
        else:
            if my_code:  # 本人进入查看模式
                return redirect('/code/%s/edit/' % code.id)
            elif not code.public:  # 查看非公开代码
                return sorry(request, 403, text='没有编辑权限')

        # GET请求输出代码至编辑器
        if request.method == 'GET':
            code_content = code.content.read().decode('utf-8', 'ignore')
            return render(request, 'edit_code.html', locals())

        # 非编辑模式拒绝POST
        elif not is_edit:
            return JsonResponse({})

        # POST请求ajax
        res = {}
        to_update = False

        # 更新名称
        new_name = request.POST.get('name')
        if new_name != None:
            new_name = new_name[:20].strip() or '未命名'
            to_update = True
            code.name = new_name
            res['name'] = new_name

        # 更新代码是否公开
        new_public = request.POST.get('public')
        try:
            new_public = int(new_public)
        except:
            pass
        if isinstance(new_public, int):
            to_update = True
            code.public = bool(new_public)

        # 验证更新代码
        new_code = request.POST.get('code')
        if new_code:
            loader = Factory(code.ai_type)
            validated = False

            # 尝试读取代码
            try:
                ast, warnings = loader.load_code(new_code, True, True)
                for line in warnings:
                    messages.warning(request, '注意: ' + line)
                validated = True
                res['code_status'] = 0
            except Exception as e:
                messages.warning(request, '代码有误: ' + str(e))
                res['code_status'] = 1

            # 保存代码
            if validated:
                code.content.open('wb')
                code.content.write(new_code.encode('utf-8', errors='ignore'))
                code.content.close()
                code.edit_datetime = timezone.now()
                code.save()
                to_update = True

        if to_update:
            messages.info(request, '更新代码"%s"成功' % code.name)
            code.save()
        return JsonResponse(res)
Esempio n. 19
0
 def invite_match(request, AI_type):
     # TODO: 支持向其他用户发起指定参数的比赛
     request.session['curr_game'] = AI_type  # 设置当前页面游戏
     return sorry(request, text='WORK IN PROGRESS')