调整vjudge 修改部分前端

This commit is contained in:
Himit_ZH 2021-06-17 21:16:50 +08:00
parent 30f6022403
commit cab8fc233f
19 changed files with 146 additions and 60 deletions

View File

@ -8,8 +8,8 @@
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<module name="api" />
<module name="JudgeServer" />
<module name="DataBackup" />
<module name="JudgeServer" />
</profile>
</annotationProcessing>
</component>

View File

@ -400,10 +400,13 @@ public class AdminContestController {
Long cid = Long.valueOf(cidStr);
QueryWrapper<ContestProblem> contestProblemQueryWrapper = new QueryWrapper<>();
contestProblemQueryWrapper.eq("pid", pid).eq("cid", cid);
contestProblemQueryWrapper.eq("cid", cid)
.and(QueryWrapper -> QueryWrapper.eq("pid", pid)
.or()
.eq("display_id",displayId));
ContestProblem contestProblem = contestProblemService.getOne(contestProblemQueryWrapper, false);
if (contestProblem != null) {
return CommonResult.errorResponse("添加失败,该题目已经加入到此次比赛当中了,请勿重复操作!", CommonResult.STATUS_FAIL);
return CommonResult.errorResponse("添加失败,该题目已添加或者题目的比赛展示ID已存在", CommonResult.STATUS_FAIL);
}
// 比赛中题目显示默认为原标题
@ -456,12 +459,17 @@ public class AdminContestController {
}
QueryWrapper<ContestProblem> contestProblemQueryWrapper = new QueryWrapper<>();
contestProblemQueryWrapper.eq("pid", problem.getId()).eq("cid", cid);
Problem finalProblem = problem;
contestProblemQueryWrapper.eq("cid", cid)
.and(QueryWrapper -> queryWrapper.eq("pid", finalProblem.getId())
.or()
.eq("display_id",displayId));
ContestProblem contestProblem = contestProblemService.getOne(contestProblemQueryWrapper, false);
if (contestProblem != null) {
return CommonResult.errorResponse("添加失败,该题目已经加入到此次比赛当中了,请勿重复操作!", CommonResult.STATUS_FAIL);
return CommonResult.errorResponse("添加失败,该题目已添加或者题目的比赛展示ID已存在", CommonResult.STATUS_FAIL);
}
// 比赛中题目显示默认为原标题
String displayName = problem.getTitle();

View File

@ -86,7 +86,12 @@ public class AdminJudgeController {
// 设置默认值
judge.setStatus(Constants.Judge.STATUS_PENDING.getStatus()); // 开始进入判题队列
judge.setVersion(judge.getVersion() + 1);
judge.setJudger(null).setTime(null).setMemory(null).setErrorMessage(null);
judge.setJudger(null)
.setTime(null)
.setMemory(null)
.setErrorMessage(null)
.setJudger(null)
.setScore(null);
boolean result = judgeService.updateById(judge);
if (result) {
// 调用判题服务
@ -123,7 +128,12 @@ public class AdminJudgeController {
for (Judge judge : rejudgeList) {
judge.setStatus(Constants.Judge.STATUS_PENDING.getStatus()); // 开始进入判题队列
judge.setVersion(judge.getVersion() + 1);
judge.setJudger(null).setTime(null).setMemory(null).setErrorMessage(null);
judge.setJudger(null)
.setTime(null)
.setMemory(null)
.setErrorMessage(null)
.setJudger(null)
.setScore(null);
submitIdList.add(judge.getSubmitId());
}
boolean resetJudgeResult = judgeService.updateBatchById(rejudgeList);

View File

@ -300,7 +300,6 @@ public class JudgeController {
boolean root = SecurityUtils.getSubject().hasRole("root"); // 是否为超级管理员
HashMap<String, Object> result = new HashMap<>();
// 如果是比赛需要判断是否为封榜,比赛管理员和超级管理员可以有权限查看(ACM题目除外)
if (judge.getCid() != 0 && !root) {
Contest contest = contestService.getById(judge.getCid());
if (!userRolesVo.getUid().equals(contest.getUid()) && contest.getSealRank()
@ -315,16 +314,33 @@ public class JudgeController {
// 超级管理员与管理员有权限查看代码
// 如果不是本人或者并未分享代码则不可查看
// 当此次提交代码不共享
boolean admin = SecurityUtils.getSubject().hasRole("admin")
|| SecurityUtils.getSubject().hasRole("problem_admin");// 是否为管理员
if (!judge.getShare() && !root && !admin) {
if (userRolesVo != null) { // 当前是登陆状态
// 需要判断是否为当前登陆用户自己的提交代码
if (!judge.getUid().equals(userRolesVo.getUid())) {
// 比赛提交只有比赛创建者和root账号可看代码
if (judge.getCid() != 0){
Contest contest = contestService.getById(judge.getCid());
if (!root&&!userRolesVo.getUid().equals(contest.getUid())) {
// 如果是比赛,那么还需要判断是否为封榜,比赛管理员和超级管理员可以有权限查看(ACM题目除外)
if(contest.getSealRank()
&& contest.getType().intValue() == Constants.Contest.TYPE_OI.getCode()
&& contest.getStatus().intValue() == Constants.Contest.STATUS_RUNNING.getCode()
&& contest.getSealRankTime().before(new Date())) {
result.put("submission", new Judge().setStatus(Constants.Judge.STATUS_SUBMITTED_UNKNOWN_RESULT.getStatus()));
return CommonResult.successResponse(result, "获取提交数据成功!");
}
judge.setCode(null);
}
}else {
boolean admin = SecurityUtils.getSubject().hasRole("admin")
|| SecurityUtils.getSubject().hasRole("problem_admin");// 是否为管理员
if (!judge.getShare() && !root && !admin) {
if (userRolesVo != null) { // 当前是登陆状态
// 需要判断是否为当前登陆用户自己的提交代码
if (!judge.getUid().equals(userRolesVo.getUid())) {
judge.setCode(null);
}
} else { // 不是登陆状态就直接无权限查看代码
judge.setCode(null);
}
} else { // 不是登陆状态就直接无权限查看代码
judge.setCode(null);
}
}

View File

@ -85,7 +85,7 @@ public class Dispatcher {
}
}
if (count.get() == 90) { // 90次失败则判为提交失败
if (count.get() == 300) { // 300次失败则判为提交失败
if (isRemote) { // 远程判题需要将账号归为可用
UpdateWrapper<RemoteJudgeAccount> remoteJudgeAccountUpdateWrapper = new UpdateWrapper<>();
remoteJudgeAccountUpdateWrapper

View File

@ -24,6 +24,7 @@ import top.hcode.hoj.utils.JsoupUtils;
import top.hcode.hoj.utils.RedisUtils;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
@ -196,6 +197,12 @@ public class ScheduleServiceImpl implements ScheduleService {
// 格式化api
String ratingAPI = String.format(codeforcesUserInfoAPI, cfUsername);
try {
// 防止cf的频率限制
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 连接api获取json格式对象
JSONObject resultObject = JsoupUtils.getJsonFromConnection(JsoupUtils.getConnectionFromUrl(ratingAPI, null, null));
// 获取状态码

View File

@ -51,11 +51,15 @@ public class RemoteJudgeGetResult {
Integer status = (Integer) result.getOrDefault("status", Constants.Judge.STATUS_SYSTEM_ERROR.getStatus());
if (status.intValue() != Constants.Judge.STATUS_PENDING.getStatus() &&
status.intValue() != Constants.Judge.STATUS_JUDGING.getStatus()) {
Judge judge = judgeService.getById(submitId);
Integer time = (Integer) result.getOrDefault("time", null);
Integer memory = (Integer) result.getOrDefault("memory", null);
String CEInfo = (String) result.getOrDefault("CEInfo", null);
judge.setStatus(status)
Judge judge = new Judge();
judge.setSubmitId(submitId)
.setStatus(status)
.setTime(time)
.setMemory(memory);
@ -66,7 +70,7 @@ public class RemoteJudgeGetResult {
}
// 如果是比赛题目需要特别适配OI比赛的得分 除AC给100 其它结果给0分
if (judge.getCid() != 0) {
if (cid != 0) {
int score = 0;
if (judge.getStatus().intValue() == Constants.Judge.STATUS_ACCEPTED.getStatus()) {

View File

@ -2,6 +2,8 @@ package top.hcode.hoj.remoteJudge.task.Impl;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
@ -21,13 +23,14 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.TimeUnit;
@Slf4j(topic = "hoj")
public class CodeForcesJudge implements RemoteJudgeStrategy {
public static final String HOST = "https://codeforces.com/";
public static final String LOGIN_URL = "enter";
public static final String SUBMIT_URL = "problemset/submit";
public static final String SUBMISSION_RESULT_URL = "api/user.status?handle=%s&from=1&count=5";
public static final String SUBMISSION_RESULT_URL = "api/user.status?handle=%s&from=1&count=30";
public static final String CE_INFO_URL = "data/submitSource";
private static final Map<String, Constants.Judge> statusMap = new HashMap<String, Constants.Judge>() {{
@ -64,16 +67,14 @@ public class CodeForcesJudge implements RemoteJudgeStrategy {
return null;
}
WebClient webClient = (WebClient) loginUtils.getOrDefault("webClient", null);
boolean isSubmitted = submitCode(webClient, problemId, getLanguage(language), userCode);
if (!isSubmitted) {
log.error("进行题目提交时发生错误:提交题目失败," + CodeForcesJudge.class.getName() + ",题号:" + problemId);
return null;
try (WebClient webClient = (WebClient) loginUtils.getOrDefault("webClient", null)) {
submitCode(webClient, problemId, getLanguage(language), userCode);
}
// 获取提交的题目id
Long maxRunId = getMaxRunId(null, username, problemId);
return MapUtil.builder(new HashMap<String, Object>())
.put("runId", maxRunId)
.put("token", "")
@ -81,15 +82,24 @@ public class CodeForcesJudge implements RemoteJudgeStrategy {
.map();
}
private Long getMaxRunId(Connection connection, String username, String problemId) {
private Long getMaxRunId(Connection connection, String username, String problemId) throws InterruptedException {
int retryNum = 0;
String url = String.format(SUBMISSION_RESULT_URL, username);
String resJson = HttpUtil.createGet(HOST + url).timeout(30000).execute().body();
HttpRequest httpRequest = HttpUtil.createGet(HOST + url);
httpRequest.header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.101 Safari/537.36 Edg/91.0.864.48");
httpRequest.disableCache();
HttpResponse httpResponse = httpRequest.execute();
// 防止cf的nginx限制访问频率重试10次
while (httpResponse.getStatus() != 200 && retryNum != 10) {
TimeUnit.SECONDS.sleep(3);
httpResponse = httpRequest.execute();
retryNum++;
}
String contestNum = problemId.replaceAll("\\D.*", "");
String problemNum = problemId.replaceAll("^\\d*", "");
try {
Map<String, Object> json = JSONUtil.parseObj(resJson);
Map<String, Object> json = JSONUtil.parseObj(httpResponse.body());
List<Map<String, Object>> results = (List<Map<String, Object>>) json.get("result");
for (Map<String, Object> result : results) {
Long runId = Long.valueOf(result.get("id").toString());
@ -147,7 +157,7 @@ public class CodeForcesJudge implements RemoteJudgeStrategy {
.form(MapUtil
.builder(new HashMap<String, Object>())
.put("csrf_token", csrfToken)
.put("submissionId", "119327069").map())
.put("submissionId", submitId.toString()).map())
.timeout(30000)
.execute()
.body();
@ -207,7 +217,7 @@ public class CodeForcesJudge implements RemoteJudgeStrategy {
}
}
public boolean submitCode(WebClient webClient, String problemID, String languageID, String code) throws IOException {
public void submitCode(WebClient webClient, String problemID, String languageID, String code) throws IOException {
// 模拟浏览器打开一个目标网址
HtmlPage page = webClient.getPage(HOST + SUBMIT_URL);
@ -225,15 +235,7 @@ public class CodeForcesJudge implements RemoteJudgeStrategy {
source.setText(code + getRandomBlankString());
HtmlSubmitInput button = (HtmlSubmitInput) page.getByXPath("//input[@class='submit']").get(0);
HtmlPage retPage = button.click();
if (retPage.getUrl().toString().equals("https://codeforces.com/problemset/status?my=on")) {
webClient.close();
return true;
} else {
webClient.close();
return false;
}
button.click();
}
@Override

View File

@ -14,6 +14,7 @@ import top.hcode.hoj.util.JsoupUtils;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -28,9 +29,10 @@ public class HduJudge implements RemoteJudgeStrategy {
public static Map<String, String> headers = MapUtil
.builder(new HashMap<String, String>())
.put("Host", "acm.hdu.edu.cn")
.put("origin","http://acm.hdu.edu.cn")
.put("referer","http://acm.hdu.edu.cn")
.put("origin", "http://acm.hdu.edu.cn")
.put("referer", "http://acm.hdu.edu.cn")
.map();
/**
* @param problemId 提交的题目id
* @param language
@ -59,6 +61,11 @@ public class HduJudge implements RemoteJudgeStrategy {
// 获取提交的题目id
Long maxRunId = getMaxRunId(connection, username, problemId);
if (maxRunId == -1L) { // 等待2s再次查询如果还是失败则表明提交失败了
TimeUnit.SECONDS.sleep(2);
maxRunId = getMaxRunId(connection, username, problemId);
}
return MapUtil.builder(new HashMap<String, Object>())
.put("token", null)
.put("cookies", loginCookie)

View File

@ -41,7 +41,7 @@ public class ContestRecordServiceImpl extends ServiceImpl<ContestRecordMapper, C
@Override
@Async
@Transactional(rollbackFor = Exception.class, isolation = Isolation.READ_COMMITTED)
@Transactional
public void UpdateContestRecord(String uid, Integer score, Integer status, Long submitId, Long cid) {
UpdateWrapper<ContestRecord> updateWrapper = new UpdateWrapper<>();
// 如果是AC
@ -66,7 +66,7 @@ public class ContestRecordServiceImpl extends ServiceImpl<ContestRecordMapper, C
updateWrapper.eq("submit_id", submitId) // submit_id一定只有一个
.eq("uid", uid);
boolean result = contestRecordMapper.update(null, updateWrapper) == 1;
boolean result = contestRecordMapper.update(null, updateWrapper) > 0;
if (!result) {
tryAgainUpdate(updateWrapper);
}

View File

@ -97,6 +97,7 @@ public class JudgeServiceImpl extends ServiceImpl<JudgeMapper, Judge> implements
}
} else { //如果是比赛提交
contestRecordService.UpdateContestRecord(uid, score, status, submitId, cid);
}
}

View File

@ -233,9 +233,10 @@ public class Constants {
/*
{0} --> tmpfs_dir
{1} --> exeName
{1} --> exeName (user or spj)
{2} --> The test case standard input file name of question
{3} --> The test case standard output file name of question
{3} --> The user's program output file name of question
{4} --> The test case standard output file name of question
*/
public enum RunConfig {
C("C", "{0}/{1}", "main", defaultEnv),
@ -256,9 +257,9 @@ public class Constants {
CS("C#", "/usr/bin/mono {0}/{1}", "main", defaultEnv),
SPJ_C("SPJ-C", "{0}/{1} {2} {3}", "spj", defaultEnv),
SPJ_C("SPJ-C", "{0}/{1} {2} {3} {4}", "spj", defaultEnv),
SPJ_CPP("SPJ-C++", "{0}/{1} {2} {3}", "spj", defaultEnv);
SPJ_CPP("SPJ-C++", "{0}/{1} {2} {3} {4}", "spj", defaultEnv);
private String language;
private String command;

View File

@ -50,13 +50,13 @@
:h="100"
:accuracy="3"
@success="handleLogin"
:slider-text="$t('m.Login_Verify')"
:slider-text="$t('m.Slide_Verify')"
ref="slideBlock"
v-if="!verify.loginSuccess"
>
</slide-verify>
<el-alert
:title="$t('m.Login_Verify_Success')"
:title="$t('m.Slide_Verify_Success')"
type="success"
:description="verify.loginMsg"
v-show="verify.loginSuccess"

View File

@ -259,7 +259,7 @@ export default {
otherOJName: 'HDU',
otherOJProblemId: '',
REMOTE_OJ: {},
displayId: 'A',
displayId: '',
};
},
mounted() {

View File

@ -131,7 +131,7 @@
></avatar>
<a
@click="goUserHome(row.username, row.uid)"
style="color: rgb(87, 163, 243)"
style="color:#2d8cf0;"
>{{ row.username }}</a
>
</template>

View File

@ -18,17 +18,26 @@
auto-resize
style="font-weight: 500;"
>
<vxe-table-column type="seq" width="50"></vxe-table-column>
<vxe-table-column type="seq" min-width="50"></vxe-table-column>
<vxe-table-column
field="username"
:title="$t('m.User')"
min-width="150"
show-overflow
align="left"
>
<template v-slot="{ row }">
<avatar
:username="row.username"
:inline="true"
:size="25"
color="#FFF"
:src="row.avatar"
class="user-avatar"
></avatar>
<a
@click="getInfoByUsername(row.uid, row.username)"
style="color:rgb(87, 163, 243);"
style="color:#2d8cf0;"
>{{ row.username }}</a
>
</template>
@ -109,11 +118,13 @@ import api from '@/common/api';
import utils from '@/common/utils';
import { RULE_TYPE } from '@/common/constants';
import { mapGetters } from 'vuex';
import Avatar from 'vue-avatar';
const Pagination = () => import('@/components/oj/common/Pagination');
export default {
name: 'acm-rank',
components: {
Pagination,
Avatar,
},
data() {
return {
@ -303,4 +314,8 @@ export default {
margin: 0;
padding: 0;
}
.user-avatar {
margin-right: 5px !important;
vertical-align: middle;
}
</style>

View File

@ -24,11 +24,20 @@
:title="$t('m.User')"
min-width="150"
show-overflow
align="left"
>
<template v-slot="{ row }">
<avatar
:username="row.username"
:inline="true"
:size="25"
color="#FFF"
:src="row.avatar"
class="user-avatar"
></avatar>
<a
@click="getInfoByUsername(row.uid, row.username)"
style="color:rgb(87, 163, 243);"
style="color:#2d8cf0;"
>{{ row.username }}</a
>
</template>
@ -107,11 +116,13 @@ import api from '@/common/api';
import utils from '@/common/utils';
import { RULE_TYPE } from '@/common/constants';
import { mapGetters } from 'vuex';
import Avatar from 'vue-avatar';
const Pagination = () => import('@/components/oj/common/Pagination');
export default {
name: 'acm-rank',
components: {
Pagination,
Avatar,
},
data() {
return {
@ -280,4 +291,8 @@ export default {
padding: 0 !important;
}
}
.user-avatar {
margin-right: 5px !important;
vertical-align: middle;
}
</style>

View File

@ -504,7 +504,7 @@ export default {
const checkStatus = () => {
let submitIds = this.needCheckSubmitIds;
let func = this.contestID
? 'getContestSubmissionList'
? 'checkContestSubmissonsStatus'
: 'checkSubmissonsStatus';
api[func](Object.keys(submitIds), this.contestID).then(
(res) => {
@ -538,7 +538,7 @@ export default {
// 180s2s*90
if (
Object.keys(this.needCheckSubmitIds).length == 0 ||
this.checkStatusNum == 90
this.checkStatusNum == 300
) {
clearTimeout(this.refreshStatus);
this.autoCheckOpen = false;