From 8329f0d4207e57ebbaf10f2f10a96f930c912045 Mon Sep 17 00:00:00 2001 From: Himit_ZH <372347736@qq.com> Date: Fri, 25 Jun 2021 11:14:24 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=B0=E5=AF=8C=E5=89=8D=E7=AB=AF=E6=93=8D?= =?UTF-8?q?=E4=BD=9C=EF=BC=8C=E5=A2=9E=E5=8A=A0POJ=E7=9A=84vjudge=E5=88=A4?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + docs/docs/develop/db.md | 2 + hoj-springboot/DataBackup/pom.xml | 6 + .../top/hcode/hoj/config/StartupRunner.java | 26 +++ .../admin/AdminContestController.java | 6 +- .../admin/AdminProblemController.java | 7 +- .../hoj/controller/oj/CommentController.java | 44 +++- .../crawler/problem/POJProblemStrategy.java | 58 +++++ .../java/top/hcode/hoj/pojo/dto/ReplyDto.java | 19 ++ .../java/top/hcode/hoj/pojo/vo/ConfigVo.java | 6 + .../hoj/service/impl/ProblemServiceImpl.java | 8 +- .../java/top/hcode/hoj/utils/ConfigUtils.java | 6 +- .../java/top/hcode/hoj/utils/Constants.java | 3 +- .../hoj/remoteJudge/RemoteJudgeGetResult.java | 5 +- .../hoj/remoteJudge/RemoteJudgeToSubmit.java | 7 +- .../task/Impl/CodeForcesJudge.java | 10 +- .../hoj/remoteJudge/task/Impl/HduJudge.java | 69 +++--- .../hoj/remoteJudge/task/Impl/POJJudge.java | 178 +++++++++++++++ .../remoteJudge/task/RemoteJudgeFactory.java | 3 + .../remoteJudge/task/RemoteJudgeStrategy.java | 2 +- .../java/top/hcode/hoj/util/Constants.java | 2 + .../hoj/JudgeServerApplicationTests.java | 2 + .../top/hcode/hoj/pojo/entity/Discussion.java | 5 +- .../top/hcode/hoj/pojo/entity/Problem.java | 5 +- hoj-vue/src/common/constants.js | 3 +- hoj-vue/src/components/oj/comment/comment.vue | 6 +- .../src/components/oj/common/CodeMirror.vue | 16 +- hoj-vue/src/i18n/admin/en-US.js | 1 + hoj-vue/src/i18n/admin/zh-CN.js | 1 + hoj-vue/src/i18n/oj/en-US.js | 4 + hoj-vue/src/i18n/oj/zh-CN.js | 6 +- .../src/views/admin/problem/ProblemList.vue | 8 +- .../views/oj/discussion/discussionList.vue | 35 ++- hoj-vue/src/views/oj/problem/Problem.vue | 206 +++++++++++++++++- sqlAndsetting/hoj.sql | 4 +- sqlAndsetting/nacos.sql | 2 +- 36 files changed, 686 insertions(+), 86 deletions(-) create mode 100644 hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/crawler/problem/POJProblemStrategy.java create mode 100644 hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/pojo/dto/ReplyDto.java create mode 100644 hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/remoteJudge/task/Impl/POJJudge.java diff --git a/README.md b/README.md index 59c57829..dd8abdf2 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,7 @@ docker ps # 查看当前运行的容器状态 | 2021-06-08 | 添加后台i18n,路由懒加载 | Himit_ZH | | 2021-06-12 | 完善比赛赛制,具体请看在线文档 | Himit_ZH | | 2021-06-14 | 完善后台管理员权限控制,恢复CF的vjudge判题 | Himit_ZH | +| 2021-06-25 | 丰富前端操作,增加POJ的vjudge判题 | Himit_ZH | diff --git a/docs/docs/develop/db.md b/docs/docs/develop/db.md index f9626101..2099e4f6 100644 --- a/docs/docs/develop/db.md +++ b/docs/docs/develop/db.md @@ -142,6 +142,7 @@ problem表 | open_case_result | boolean | | 是否默认开启该题目的测试样例结果查看 | | caseVersion | String | | 题目测试数据的版本号 | | is_upload_case | boolean | | 是否是上传zip评测数据的 | +| modified_user | String | | 最新修改题目的用户 | | gmt_create | datetime | | 创建时间 | | gmt_modified | datetime | | 修改时间 | @@ -529,6 +530,7 @@ discussion表 | view_num | int | | 浏览数量 | | like_num | int | | 点赞数量 | | top_priority | boolean | | 优先级,是否置顶 | +| comment_num | int | | 评论数量 | | status | int | | 是否封禁或逻辑删除该讨论 | | gmt_create | datetime | | 创建时间 | | gmt_modified | datetime | | 修改时间 | diff --git a/hoj-springboot/DataBackup/pom.xml b/hoj-springboot/DataBackup/pom.xml index dc2c6891..cfdac59b 100644 --- a/hoj-springboot/DataBackup/pom.xml +++ b/hoj-springboot/DataBackup/pom.xml @@ -126,6 +126,12 @@ 5.3.3 + + com.vdurmont + emoji-java + 4.0.0 + + org.springframework.boot diff --git a/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/config/StartupRunner.java b/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/config/StartupRunner.java index d98f1f39..8624c68b 100644 --- a/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/config/StartupRunner.java +++ b/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/config/StartupRunner.java @@ -105,6 +105,12 @@ public class StartupRunner implements CommandLineRunner { @Value("${CF_ACCOUNT_PASSWORD_LIST:}") private List cfPasswordList; + @Value("${POJ_ACCOUNT_USERNAME_LIST:}") + private List pojUsernameList; + + @Value("${POJ_ACCOUNT_PASSWORD_LIST:}") + private List pojPasswordList; + @Value("${spring.profiles.active}") private String profile; @@ -151,6 +157,10 @@ public class StartupRunner implements CommandLineRunner { configVo.setCfUsernameList(cfUsernameList); configVo.setCfPasswordList(cfPasswordList); + + configVo.setPojUsernameList(pojUsernameList); + configVo.setPojPasswordList(pojPasswordList); + configService.sendNewConfigToNacos(); if (openRemoteJudge.equals("true")) { @@ -203,6 +213,22 @@ public class StartupRunner implements CommandLineRunner { log.error("Codeforces账号添加失败------------>{}", "请检查配置文件,然后重新启动!"); } } + + List pojRemoteAccountList = new LinkedList<>(); + for (int i = 0; i < pojUsernameList.size(); i++) { + pojRemoteAccountList.add(new RemoteJudgeAccount() + .setUsername(pojUsernameList.get(i)) + .setPassword(pojPasswordList.get(i)) + .setStatus(true) + .setVersion(0L) + .setOj("POJ")); + } + if (pojRemoteAccountList.size()>0) { + boolean addPOJOk = remoteJudgeAccountService.saveOrUpdateBatch(pojRemoteAccountList); + if (!addPOJOk) { + log.error("POJ账号添加失败------------>{}", "请检查配置文件,然后重新启动!"); + } + } } } \ No newline at end of file diff --git a/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/controller/admin/AdminContestController.java b/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/controller/admin/AdminContestController.java index bbe8bff5..dd9602c8 100644 --- a/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/controller/admin/AdminContestController.java +++ b/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/controller/admin/AdminContestController.java @@ -326,7 +326,11 @@ public class AdminContestController { if (problem != null && problem.getId().longValue() != problemDto.getProblem().getId()) { return CommonResult.errorResponse("当前的Problem ID 已被使用,请重新更换新的!", CommonResult.STATUS_FAIL); } - + // 获取当前登录的用户 + HttpSession session = request.getSession(); + UserRolesVo userRolesVo = (UserRolesVo) session.getAttribute("userInfo"); + // 记录修改题目的用户 + problemDto.getProblem().setModifiedUser(userRolesVo.getUsername()); boolean result = problemService.adminUpdateProblem(problemDto); if (result) { // 更新成功 return CommonResult.successResponse(null, "修改成功!"); diff --git a/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/controller/admin/AdminProblemController.java b/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/controller/admin/AdminProblemController.java index 94c91565..e30ef095 100644 --- a/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/controller/admin/AdminProblemController.java +++ b/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/controller/admin/AdminProblemController.java @@ -144,7 +144,7 @@ public class AdminProblemController { @RequiresAuthentication @RequiresRoles(value = {"root", "admin", "problem_admin"}, logical = Logical.OR) @Transactional - public CommonResult updateProblem(@RequestBody ProblemDto problemDto) { + public CommonResult updateProblem(@RequestBody ProblemDto problemDto, HttpServletRequest request) { QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("problem_id", problemDto.getProblem().getProblemId().toUpperCase()); @@ -154,6 +154,11 @@ public class AdminProblemController { if (problem != null && problem.getId().longValue() != problemDto.getProblem().getId()) { return CommonResult.errorResponse("当前的Problem ID 已被使用,请重新更换新的!", CommonResult.STATUS_FAIL); } + // 获取当前登录的用户 + HttpSession session = request.getSession(); + UserRolesVo userRolesVo = (UserRolesVo) session.getAttribute("userInfo"); + // 记录修改题目的用户 + problemDto.getProblem().setModifiedUser(userRolesVo.getUsername()); boolean result = problemService.adminUpdateProblem(problemDto); if (result) { // 更新成功 diff --git a/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/controller/oj/CommentController.java b/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/controller/oj/CommentController.java index dd79b5ae..1d4a18fa 100644 --- a/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/controller/oj/CommentController.java +++ b/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/controller/oj/CommentController.java @@ -12,13 +12,16 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; import top.hcode.hoj.common.result.CommonResult; +import top.hcode.hoj.pojo.dto.ReplyDto; import top.hcode.hoj.pojo.entity.Comment; import top.hcode.hoj.pojo.entity.CommentLike; +import top.hcode.hoj.pojo.entity.Discussion; import top.hcode.hoj.pojo.entity.Reply; import top.hcode.hoj.pojo.vo.CommentsVo; import top.hcode.hoj.pojo.vo.UserRolesVo; import top.hcode.hoj.service.impl.CommentLikeServiceImpl; import top.hcode.hoj.service.impl.CommentServiceImpl; +import top.hcode.hoj.service.impl.DiscussionServiceImpl; import top.hcode.hoj.service.impl.ReplyServiceImpl; import javax.servlet.http.HttpServletRequest; @@ -45,6 +48,9 @@ public class CommentController { @Autowired private ReplyServiceImpl replyService; + @Autowired + private DiscussionServiceImpl discussionService; + @GetMapping("/comments") public CommonResult getComments(@RequestParam(value = "cid", required = false) Long cid, @@ -126,6 +132,13 @@ public class CommentController { commentsVo.setLikeNum(0); commentsVo.setGmtCreate(comment.getGmtCreate()); commentsVo.setReplyList(new LinkedList<>()); + // 如果是讨论区的回复,发布成功需要添加统计该讨论的回复数 + if (comment.getDid() != null) { + UpdateWrapper discussionUpdateWrapper = new UpdateWrapper<>(); + discussionUpdateWrapper.eq("id", comment.getDid()) + .setSql("comment_num=comment_num+1"); + discussionService.update(discussionUpdateWrapper); + } return CommonResult.successResponse(commentsVo, "评论成功"); } else { return CommonResult.errorResponse("评论失败,请重新尝试!"); @@ -151,6 +164,13 @@ public class CommentController { replyService.remove(new UpdateWrapper().eq("comment_id", comment.getId())); if (isDeleteComment) { + // 如果是讨论区的回复,删除成功需要减少统计该讨论的回复数 + if (comment.getDid() != null) { + UpdateWrapper discussionUpdateWrapper = new UpdateWrapper<>(); + discussionUpdateWrapper.eq("id", comment.getDid()) + .setSql("comment_num=comment_num-1"); + discussionService.update(discussionUpdateWrapper); + } return CommonResult.successResponse(null, "删除成功"); } else { return CommonResult.errorResponse("删除失败,请重新尝试"); @@ -222,11 +242,11 @@ public class CommentController { @PostMapping("/reply") @RequiresPermissions("reply_add") @RequiresAuthentication - public CommonResult addReply(@RequestBody Reply reply, HttpServletRequest request) { + public CommonResult addReply(@RequestBody ReplyDto replyDto, HttpServletRequest request) { // 获取当前登录的用户 HttpSession session = request.getSession(); UserRolesVo userRolesVo = (UserRolesVo) session.getAttribute("userInfo"); - + Reply reply = replyDto.getReply(); reply.setFromAvatar(userRolesVo.getAvatar()) .setFromName(userRolesVo.getUsername()) .setFromUid(userRolesVo.getUid()); @@ -244,6 +264,13 @@ public class CommentController { boolean isOk = replyService.saveOrUpdate(reply); if (isOk) { + // 如果是讨论区的回复,发布成功需要增加统计该讨论的回复数 + if (replyDto.getDid() != null) { + UpdateWrapper discussionUpdateWrapper = new UpdateWrapper<>(); + discussionUpdateWrapper.eq("id", replyDto.getDid()) + .setSql("comment_num=comment_num+1"); + discussionService.update(discussionUpdateWrapper); + } return CommonResult.successResponse(reply, "评论成功"); } else { return CommonResult.errorResponse("评论失败,请重新尝试!"); @@ -252,19 +279,24 @@ public class CommentController { @DeleteMapping("/reply") @RequiresAuthentication - public CommonResult deleteReply(@RequestBody Reply reply, HttpServletRequest request) { + public CommonResult deleteReply(@RequestBody ReplyDto replyDto, HttpServletRequest request) { // 获取当前登录的用户 HttpSession session = request.getSession(); UserRolesVo userRolesVo = (UserRolesVo) session.getAttribute("userInfo"); - + Reply reply = replyDto.getReply(); // 如果不是评论本人 或者不是管理员 无权限删除该评论 if (reply.getFromUid().equals(userRolesVo.getUid()) || SecurityUtils.getSubject().hasRole("root") || SecurityUtils.getSubject().hasRole("admin") || SecurityUtils.getSubject().hasRole("problem_admin")) { - // 删除该数据 boolean isOk = replyService.removeById(reply.getId()); - if (isOk) { + // 如果是讨论区的回复,删除成功需要减少统计该讨论的回复数 + if (replyDto.getDid() != null) { + UpdateWrapper discussionUpdateWrapper = new UpdateWrapper<>(); + discussionUpdateWrapper.eq("id", replyDto.getDid()) + .setSql("comment_num=comment_num-1"); + discussionService.update(discussionUpdateWrapper); + } return CommonResult.successResponse(null, "删除成功"); } else { return CommonResult.errorResponse("删除失败,请重新尝试"); diff --git a/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/crawler/problem/POJProblemStrategy.java b/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/crawler/problem/POJProblemStrategy.java new file mode 100644 index 00000000..0d8419b2 --- /dev/null +++ b/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/crawler/problem/POJProblemStrategy.java @@ -0,0 +1,58 @@ +package top.hcode.hoj.crawler.problem; + +import cn.hutool.core.util.ReUtil; +import org.jsoup.Connection; +import org.jsoup.nodes.Document; +import org.springframework.util.Assert; +import top.hcode.hoj.pojo.entity.Problem; +import top.hcode.hoj.utils.JsoupUtils; + +/** + * @Author: Himit_ZH + * @Date: 2021/6/24 23:27 + * @Description: + */ +public class POJProblemStrategy extends ProblemStrategy { + + public static final String JUDGE_NAME = "POJ"; + public static final String HOST = "http://poj.org"; + public static final String PROBLEM_URL = "/problem?id=%s"; + + @Override + public RemoteProblemInfo getProblemInfo(String problemId, String author) throws Exception { + + // 验证题号是否符合规范 + Assert.isTrue(problemId.matches("[1-9]\\d*"), "POJ题号格式错误!"); + Problem info = new Problem(); + String url = HOST + String.format(PROBLEM_URL, problemId); + Connection connection = JsoupUtils.getConnectionFromUrl(url, null, null); + Document document = JsoupUtils.getDocument(connection, null); + String html = document.html(); + html = html.replaceAll("
", "\n"); + info.setProblemId(JUDGE_NAME + "-" + problemId); + info.setTitle(ReUtil.get("\\d{3,} -- ([\\s\\S]*?)", html, 1).trim()); + info.setTimeLimit(Integer.parseInt(ReUtil.get("Time Limit: (\\d{3,})MS", html, 1))); + info.setMemoryLimit(Integer.parseInt(ReUtil.get("Memory Limit: (\\d{2,})K", html, 1)) / 1024); + info.setDescription(ReUtil.get("

Description

([\\s\\S]*?)

", html, 1) + .replaceAll("src=\"../../", "src=\"" + HOST + "/")); + + info.setInput(ReUtil.get("

Input

([\\s\\S]*?)

", html, 1)); + info.setOutput(ReUtil.get("

Output

([\\s\\S]*?)

", html, 1)); + StringBuilder sb = new StringBuilder(""); + sb.append(ReUtil.get("

Sample Input

([\\s\\S]*?)

", html, 1)); + sb.append(""); + sb.append(ReUtil.get("

Sample Output

([\\s\\S]*?)

", html, 1)) + .append(""); + info.setExamples(sb.toString()); + info.setHint(ReUtil.get("

Hint

([\\s\\S]*?)

", html, 1)); + info.setIsRemote(true); + info.setSource(String.format("%s", problemId, JUDGE_NAME + "-" + problemId)); + info.setType(0) + .setAuth(1) + .setAuthor(author) + .setOpenCaseResult(false) + .setIsRemoveEndBlank(false) + .setDifficulty(1); // 默认为简单 + return new RemoteProblemInfo().setProblem(info).setTagList(null); + } +} \ No newline at end of file diff --git a/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/pojo/dto/ReplyDto.java b/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/pojo/dto/ReplyDto.java new file mode 100644 index 00000000..72cb6f35 --- /dev/null +++ b/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/pojo/dto/ReplyDto.java @@ -0,0 +1,19 @@ +package top.hcode.hoj.pojo.dto; + +import lombok.Data; +import lombok.experimental.Accessors; +import top.hcode.hoj.pojo.entity.Reply; + +/** + * @Author: Himit_ZH + * @Date: 2021/6/24 17:00 + * @Description: + */ +@Data +@Accessors(chain = true) +public class ReplyDto { + + private Reply reply; + + private Long did; +} \ No newline at end of file diff --git a/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/pojo/vo/ConfigVo.java b/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/pojo/vo/ConfigVo.java index 7622a55b..096d41e3 100644 --- a/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/pojo/vo/ConfigVo.java +++ b/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/pojo/vo/ConfigVo.java @@ -119,4 +119,10 @@ public class ConfigVo { @Value("${hoj.cf.account.password:}") private List cfPasswordList; + @Value("${hoj.poj.account.username:}") + private List pojUsernameList; + + @Value("${hoj.poj.account.password:}") + private List pojPasswordList; + } diff --git a/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/service/impl/ProblemServiceImpl.java b/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/service/impl/ProblemServiceImpl.java index eac180d2..e3ac3680 100644 --- a/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/service/impl/ProblemServiceImpl.java +++ b/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/service/impl/ProblemServiceImpl.java @@ -19,10 +19,7 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.util.DigestUtils; import org.springframework.util.StringUtils; import org.yaml.snakeyaml.Yaml; -import top.hcode.hoj.crawler.problem.CFProblemStrategy; -import top.hcode.hoj.crawler.problem.HDUProblemStrategy; -import top.hcode.hoj.crawler.problem.ProblemContext; -import top.hcode.hoj.crawler.problem.ProblemStrategy; +import top.hcode.hoj.crawler.problem.*; import top.hcode.hoj.pojo.dto.ProblemDto; import top.hcode.hoj.pojo.entity.*; import top.hcode.hoj.pojo.vo.ImportProblemVo; @@ -544,6 +541,9 @@ public class ProblemServiceImpl extends ServiceImpl impl case "CF": problemStrategy = new CFProblemStrategy(); break; + case "POJ": + problemStrategy = new POJProblemStrategy(); + break; default: throw new Exception("未知的OJ的名字,暂时不支持!"); } diff --git a/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/utils/ConfigUtils.java b/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/utils/ConfigUtils.java index 59f645fb..aed3f198 100644 --- a/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/utils/ConfigUtils.java +++ b/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/utils/ConfigUtils.java @@ -72,7 +72,11 @@ public class ConfigUtils { " cf:\n" + " account:\n" + " username: " + listToStr(configVo.getCfUsernameList()) + "\n" + - " password: " + listToStr(configVo.getCfPasswordList()); + " password: " + listToStr(configVo.getCfPasswordList()) + "\n" + + " poj:\n" + + " account:\n" + + " username: " + listToStr(configVo.getPojUsernameList()) + "\n" + + " password: " + listToStr(configVo.getPojPasswordList()); } private String listToStr(List list) { diff --git a/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/utils/Constants.java b/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/utils/Constants.java index 04c676d6..bab3c011 100644 --- a/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/utils/Constants.java +++ b/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/utils/Constants.java @@ -58,7 +58,8 @@ public class Constants { public enum RemoteOJ { HDU("HDU"), - CODEFORCES("CF"); + CODEFORCES("CF"), + POJ("POJ"); private final String name; diff --git a/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/remoteJudge/RemoteJudgeGetResult.java b/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/remoteJudge/RemoteJudgeGetResult.java index 23b5eeca..b85b2657 100644 --- a/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/remoteJudge/RemoteJudgeGetResult.java +++ b/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/remoteJudge/RemoteJudgeGetResult.java @@ -32,8 +32,7 @@ public class RemoteJudgeGetResult { @Transactional public void sendTask(String remoteJudge, String username, Long submitId, String uid, - Long cid, Long pid, Long resultSubmitId, String token, - HashMap cookies) { + Long cid, Long pid, Long resultSubmitId, String cookies) { RemoteJudgeStrategy remoteJudgeStrategy = RemoteJudgeFactory.selectJudge(remoteJudge); @@ -47,7 +46,7 @@ public class RemoteJudgeGetResult { public void run() { count.getAndIncrement(); try { - Map result = remoteJudgeStrategy.result(resultSubmitId, username, token, cookies); + Map result = remoteJudgeStrategy.result(resultSubmitId, username, cookies); 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()) { diff --git a/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/remoteJudge/RemoteJudgeToSubmit.java b/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/remoteJudge/RemoteJudgeToSubmit.java index b5b40164..59e65ece 100644 --- a/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/remoteJudge/RemoteJudgeToSubmit.java +++ b/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/remoteJudge/RemoteJudgeToSubmit.java @@ -87,17 +87,16 @@ public class RemoteJudgeToSubmit { return; } - // 提交成功顺便更新状态为-->STATUS_JUDGING 判题中... + // 提交成功顺便更新状态为-->STATUS_PENDING 等待中... judgeService.updateById(new Judge() .setSubmitId(submitId) - .setStatus(Constants.Judge.STATUS_JUDGING.getStatus()) + .setStatus(Constants.Judge.STATUS_PENDING.getStatus()) .setJudger(name) ); // 调用获取远程判题结果 remoteJudgeGetResult.sendTask(remoteJudge, username, submitId, uid, cid, pid, - (Long) submitResult.get("runId"), (String) submitResult.get("token"), - (HashMap) submitResult.get("cookies")); + (Long) submitResult.get("runId"), (String) submitResult.get("cookies")); } } diff --git a/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/remoteJudge/task/Impl/CodeForcesJudge.java b/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/remoteJudge/task/Impl/CodeForcesJudge.java index 0d1c6293..a7ee4ce4 100644 --- a/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/remoteJudge/task/Impl/CodeForcesJudge.java +++ b/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/remoteJudge/task/Impl/CodeForcesJudge.java @@ -14,7 +14,6 @@ import com.gargoylesoftware.htmlunit.SilentCssErrorHandler; import com.gargoylesoftware.htmlunit.WebClient; import com.gargoylesoftware.htmlunit.html.*; import lombok.extern.slf4j.Slf4j; -import org.jsoup.Connection; import top.hcode.hoj.remoteJudge.task.RemoteJudgeStrategy; import top.hcode.hoj.util.Constants; @@ -73,16 +72,15 @@ public class CodeForcesJudge implements RemoteJudgeStrategy { // 获取提交的题目id - Long maxRunId = getMaxRunId(null, username, problemId); + Long maxRunId = getMaxRunId(username, problemId); return MapUtil.builder(new HashMap()) .put("runId", maxRunId) - .put("token", "") - .put("cookies", new HashMap()) + .put("cookies", null) .map(); } - private Long getMaxRunId(Connection connection, String username, String problemId) throws InterruptedException { + private Long getMaxRunId(String username, String problemId) throws InterruptedException { int retryNum = 0; String url = String.format(SUBMISSION_RESULT_URL, username); HttpRequest httpRequest = HttpUtil.createGet(HOST + url); @@ -118,7 +116,7 @@ public class CodeForcesJudge implements RemoteJudgeStrategy { } @Override - public Map result(Long submitId, String username, String token, HashMap cookies) throws Exception { + public Map result(Long submitId, String username, String cookies) { String url = HOST + String.format(SUBMISSION_RESULT_URL, username); diff --git a/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/remoteJudge/task/Impl/HduJudge.java b/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/remoteJudge/task/Impl/HduJudge.java index 74619a3a..b9172c37 100644 --- a/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/remoteJudge/task/Impl/HduJudge.java +++ b/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/remoteJudge/task/Impl/HduJudge.java @@ -2,15 +2,13 @@ package top.hcode.hoj.remoteJudge.task.Impl; import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.ReUtil; -import cn.hutool.http.HtmlUtil; +import cn.hutool.http.*; import lombok.extern.slf4j.Slf4j; -import org.jsoup.Connection; + import org.jsoup.helper.Validate; -import org.jsoup.nodes.Document; -import top.hcode.hoj.pojo.entity.Problem; + import top.hcode.hoj.remoteJudge.task.RemoteJudgeStrategy; import top.hcode.hoj.util.Constants; -import top.hcode.hoj.util.JsoupUtils; import java.util.HashMap; import java.util.Map; @@ -31,6 +29,7 @@ public class HduJudge implements RemoteJudgeStrategy { .put("Host", "acm.hdu.edu.cn") .put("origin", "http://acm.hdu.edu.cn") .put("referer", "http://acm.hdu.edu.cn") + .put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36") .map(); /** @@ -45,39 +44,46 @@ public class HduJudge implements RemoteJudgeStrategy { return null; } Map loginUtils = getLoginUtils(username, password); - Map loginCookie = (Map) loginUtils.get("cookie"); - Connection connection = JsoupUtils.getConnectionFromUrl(HOST + SUBMIT_URL, headers, loginCookie); - Connection.Response response = JsoupUtils.postResponse(connection, MapUtil - .builder(new HashMap()) + String cookies = (String) loginUtils.get("cookie"); + + HttpRequest request = HttpUtil.createPost(HOST + SUBMIT_URL) + .addHeaders(headers) + .cookie(cookies); + + HttpResponse response = request.form(MapUtil + .builder(new HashMap()) .put("check", "0") .put("language", getLanguage(language)) .put("problemid", problemId) .put("usercode", userCode) - .map()); - if (response.statusCode() != 200) { + .map()) + .execute(); + if (response.getStatus() != 200) { log.error("进行题目提交时发生错误:提交题目失败," + HduJudge.class.getName() + ",题号:" + problemId); return null; } - + // 下面的请求都是GET + request.setMethod(Method.GET); // 获取提交的题目id - Long maxRunId = getMaxRunId(connection, username, problemId); + Long maxRunId = getMaxRunId(request, username, problemId); if (maxRunId == -1L) { // 等待2s再次查询,如果还是失败,则表明提交失败了 TimeUnit.SECONDS.sleep(2); - maxRunId = getMaxRunId(connection, username, problemId); + maxRunId = getMaxRunId(request, username, problemId); } return MapUtil.builder(new HashMap()) - .put("token", null) - .put("cookies", loginCookie) + .put("cookies", cookies) .put("runId", maxRunId) .map(); } @Override - public Map result(Long submitId, String username, String token, HashMap cookies) throws Exception { + public Map result(Long submitId, String username, String cookies) throws Exception { String url = HOST + String.format(QUERY_URL, submitId); - Connection connection = JsoupUtils.getConnectionFromUrl(url, headers, null); - Connection.Response response = JsoupUtils.getResponse(connection, null); + HttpRequest request = HttpUtil.createGet(url) + .cookie(cookies) + .addHeaders(headers); + HttpResponse response = request.execute(); // 1提交时间 2结果 3执行时间 4执行空间 5代码长度 // 一般情况下 代码长度和提交时间不需要,想要也行,自行添加 Pattern pattern = Pattern.compile(">" + submitId + "([\\s\\S]*?)([\\s\\S]*?)[\\s\\S]*?(\\d*?)MS(\\d*?)K(\\d*?)B"); @@ -100,9 +106,9 @@ public class HduJudge implements RemoteJudgeStrategy { result.put("memory", Integer.parseInt(executionMemory)); // 如果CE了,则还需要获得错误信息 if (statusType == Constants.Judge.STATUS_COMPILE_ERROR) { - connection.url(HOST + String.format(ERROR_URL, submitId)); - response = JsoupUtils.getResponse(connection, null); - String compilationErrorInfo = ReUtil.get("

([\\s\\S]*?)
", response.body(), 1); + request.setUrl(HOST + String.format(ERROR_URL, submitId)); + String CEHtml = request.execute().body(); + String compilationErrorInfo = ReUtil.get("
([\\s\\S]*?)
", CEHtml, 1); result.put("CEInfo", HtmlUtil.unescape(compilationErrorInfo)); } return result; @@ -110,14 +116,16 @@ public class HduJudge implements RemoteJudgeStrategy { @Override - public Map getLoginUtils(String username, String password) throws Exception { - Connection connection = JsoupUtils.getConnectionFromUrl(HOST + LOGIN_URL, headers, null); - Connection.Response response = JsoupUtils.postResponse(connection, MapUtil - .builder(new HashMap()) + public Map getLoginUtils(String username, String password){ + + HttpRequest request = HttpUtil.createPost(HOST + LOGIN_URL).addHeaders(headers); + HttpResponse response = request.form(MapUtil + .builder(new HashMap()) .put("username", username) .put("login", "Sign In") - .put("userpass", password).map()); - return MapUtil.builder(new HashMap()).put("cookie", response.cookies()).map(); + .put("userpass", password).map()) + .execute(); + return MapUtil.builder(new HashMap()).put("cookie", response.getCookieStr()).map(); } @Override @@ -144,10 +152,9 @@ public class HduJudge implements RemoteJudgeStrategy { } - public Long getMaxRunId(Connection connection, String userName, String problemId) throws Exception { + public Long getMaxRunId(HttpRequest request, String userName, String problemId){ String url = String.format(STATUS_URL, userName, problemId); - connection.url(HOST + url); - Connection.Response response = JsoupUtils.getResponse(connection, null); + HttpResponse response = request.setUrl(url).execute(); Matcher matcher = Pattern.compile("(\\d+)").matcher(response.body()); return matcher.find() ? Long.parseLong(matcher.group(1)) : -1L; } diff --git a/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/remoteJudge/task/Impl/POJJudge.java b/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/remoteJudge/task/Impl/POJJudge.java new file mode 100644 index 00000000..ba3b7eb9 --- /dev/null +++ b/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/remoteJudge/task/Impl/POJJudge.java @@ -0,0 +1,178 @@ +package top.hcode.hoj.remoteJudge.task.Impl; + +import cn.hutool.core.codec.Base64; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ReUtil; +import cn.hutool.http.*; +import lombok.extern.slf4j.Slf4j; +import top.hcode.hoj.remoteJudge.task.RemoteJudgeStrategy; +import top.hcode.hoj.util.Constants; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @Author: Himit_ZH + * @Date: 2021/6/24 21:19 + * @Description: + */ +@Slf4j(topic = "hoj") +public class POJJudge implements RemoteJudgeStrategy { + public static final String HOST = "http://poj.org"; + public static final String LOGIN_URL = "/login"; + public static final String SUBMIT_URL = "/submit"; + public static final String STATUS_URL = "/status?user_id=%s&problem_id=%s"; + public static final String QUERY_URL = "/showsource?solution_id=%s"; + public static final String ERROR_URL = "/showcompileinfo?solution_id=%s"; + public static Map headers = MapUtil + .builder(new HashMap()) + .put("Host", "poj.org") + .put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36") + .map(); + + /** + * @param problemId 提交的题目id + * @param language + * @param userCode 用户代码 + * @return + */ + @Override + public Map submit(String username, String password, String problemId, String language, String userCode) throws Exception { + if (problemId == null || userCode == null) { + return null; + } + Map loginUtils = getLoginUtils(username, password); + String cookies = (String) loginUtils.get("cookie"); + + HttpRequest request = HttpUtil.createPost(HOST + SUBMIT_URL) + .addHeaders(headers) + .cookie(cookies); + + HttpResponse response = request.form(MapUtil.builder(new HashMap()) + .put("language", getLanguage(language)) + .put("submit", "Submit") + .put("problem_id", problemId) + .put("source", Base64.encode(userCode)) + .put("encoded", 1).map()) + .execute(); + if (response.getStatus() != 302) { + log.error("进行题目提交时发生错误:提交题目失败," + POJJudge.class.getName() + ",题号:" + problemId); + return null; + } + // 下面的请求都是GET + request.setMethod(Method.GET); + // 获取提交的题目id + Long maxRunId = getMaxRunId(request, username, problemId); + + if (maxRunId == -1L) { // 等待2s再次查询,如果还是失败,则表明提交失败了 + TimeUnit.SECONDS.sleep(2); + maxRunId = getMaxRunId(request, username, problemId); + } + return MapUtil.builder(new HashMap()) + .put("cookies", cookies) + .put("runId", maxRunId) + .map(); + } + + @Override + public Map result(Long submitId, String username, String cookies) { + String url = HOST + String.format(QUERY_URL, submitId); + HttpRequest request = HttpUtil.createGet(url) + .cookie(cookies) + .addHeaders(headers); + HttpResponse response = request.execute(); + + String statusStr = ReUtil.get("Result:(.+?)", response.body(), 1) + .replaceAll("<.*?>", "") + .trim(); + + Constants.Judge statusType = statusTypeMap.getOrDefault(statusStr, null); + + if (statusType == null) { + return MapUtil.builder(new HashMap()) + .put("status", Constants.Judge.STATUS_PENDING).build(); + } + // 返回的结果map + Map result = MapUtil.builder(new HashMap()) + .put("status", statusType.getStatus()).build(); + // 如果CE了,需要获得错误信息 + if (statusType == Constants.Judge.STATUS_COMPILE_ERROR) { + request.setUrl(HOST + String.format(ERROR_URL, submitId)); + String CEHtml = request.execute().body(); + String compilationErrorInfo = ReUtil.get("
([\\s\\S]*?)
", CEHtml, 1); + result.put("CEInfo", HtmlUtil.unescape(compilationErrorInfo)); + } else { + // 如果不是CE,获取其他信息 + String executionTime = ReUtil.get("Memory: ([-\\d]+)", response.body(), 1); + result.put("time", Integer.parseInt(executionTime)); + String executionMemory = ReUtil.get("Time: ([-\\d]+)", response.body(), 1); + result.put("memory", Integer.parseInt(executionMemory)); + } + return result; + } + + + @Override + public Map getLoginUtils(String username, String password) { + + HttpRequest request = HttpUtil.createPost(HOST + LOGIN_URL); + HttpResponse response = request.form(MapUtil.builder(new HashMap()) + .put("user_id1", username) + .put("B1", "login") + .put("url", ".") + .put("password1", password).map()).execute(); + + return MapUtil.builder(new HashMap()).put("cookie", response.getCookieStr()).map(); + } + + @Override + public String getLanguage(String language) { + switch (language) { + case "G++": + return "0"; + case "GCC": + return "1"; + case "Java": + return "2"; + case "Pascal": + return "3"; + case "C++": + return "4"; + case "C": + return "5"; + case "Fortran": + return "6"; + default: + // TODO 抛出没有这个语言的异常 + return null; + } + } + + + public Long getMaxRunId(HttpRequest request, String userName, String problemId) { + String url = String.format(STATUS_URL, userName, problemId); + request.setUrl(HOST + url); + String html = request.execute().body(); + Matcher matcher = Pattern.compile("(\\d+)").matcher(html); + return matcher.find() ? Long.parseLong(matcher.group(1)) : -1L; + } + + + // TODO 添加结果对应的状态 + private static final Map statusTypeMap = new HashMap() { + { + put("Compiling", Constants.Judge.STATUS_COMPILING); + put("Accepted", Constants.Judge.STATUS_ACCEPTED); + put("Presentation Error", Constants.Judge.STATUS_PRESENTATION_ERROR); + put("Time Limit Exceeded", Constants.Judge.STATUS_TIME_LIMIT_EXCEEDED); + put("Memory Limit Exceeded", Constants.Judge.STATUS_MEMORY_LIMIT_EXCEEDED); + put("Wrong Answer", Constants.Judge.STATUS_WRONG_ANSWER); + put("Runtime Error", Constants.Judge.STATUS_RUNTIME_ERROR); + put("Output Limit Exceeded", Constants.Judge.STATUS_RUNTIME_ERROR); + put("Compile Error", Constants.Judge.STATUS_COMPILE_ERROR); + } + }; +} \ No newline at end of file diff --git a/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/remoteJudge/task/RemoteJudgeFactory.java b/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/remoteJudge/task/RemoteJudgeFactory.java index cddbb03a..68631dc9 100644 --- a/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/remoteJudge/task/RemoteJudgeFactory.java +++ b/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/remoteJudge/task/RemoteJudgeFactory.java @@ -2,6 +2,7 @@ package top.hcode.hoj.remoteJudge.task; import top.hcode.hoj.remoteJudge.task.Impl.CodeForcesJudge; import top.hcode.hoj.remoteJudge.task.Impl.HduJudge; +import top.hcode.hoj.remoteJudge.task.Impl.POJJudge; import top.hcode.hoj.util.Constants; @@ -14,6 +15,8 @@ public class RemoteJudgeFactory { return new HduJudge(); case CF_JUDGE: return new CodeForcesJudge(); + case POJ_JUDGE: + return new POJJudge(); default: return null; } diff --git a/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/remoteJudge/task/RemoteJudgeStrategy.java b/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/remoteJudge/task/RemoteJudgeStrategy.java index a9f68e0e..925b2689 100644 --- a/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/remoteJudge/task/RemoteJudgeStrategy.java +++ b/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/remoteJudge/task/RemoteJudgeStrategy.java @@ -22,7 +22,7 @@ public interface RemoteJudgeStrategy { * @param username 题库的提交者的账号 * @return 返回结果 */ - Map result(Long submitId, String username, String token, HashMap cookies) throws Exception; + Map result(Long submitId, String username, String cookies) throws Exception; Map getLoginUtils(String username, String password) throws Exception; diff --git a/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/util/Constants.java b/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/util/Constants.java index dcfdebcd..4c0c8199 100644 --- a/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/util/Constants.java +++ b/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/util/Constants.java @@ -67,6 +67,8 @@ public class Constants { CF_JUDGE("CF"), + POJ_JUDGE("POJ"), + HDU_REMOTE_JUDGE_ACCOUNT("Hdu Remote Judge Account"), CF_REMOTE_JUDGE_ACCOUNT("Codeforces Remote Judge Account"); diff --git a/hoj-springboot/JudgeServer/src/test/java/top/hcode/hoj/JudgeServerApplicationTests.java b/hoj-springboot/JudgeServer/src/test/java/top/hcode/hoj/JudgeServerApplicationTests.java index b24de175..29020673 100644 --- a/hoj-springboot/JudgeServer/src/test/java/top/hcode/hoj/JudgeServerApplicationTests.java +++ b/hoj-springboot/JudgeServer/src/test/java/top/hcode/hoj/JudgeServerApplicationTests.java @@ -88,4 +88,6 @@ public class JudgeServerApplicationTests { "}"); System.out.println(result); } + + } diff --git a/hoj-springboot/api/src/main/java/top/hcode/hoj/pojo/entity/Discussion.java b/hoj-springboot/api/src/main/java/top/hcode/hoj/pojo/entity/Discussion.java index 16757cb7..6c16a44b 100644 --- a/hoj-springboot/api/src/main/java/top/hcode/hoj/pojo/entity/Discussion.java +++ b/hoj-springboot/api/src/main/java/top/hcode/hoj/pojo/entity/Discussion.java @@ -56,7 +56,10 @@ public class Discussion { private Integer viewNum; @ApiModelProperty(value = "点赞数量") - private String likeNum; + private Integer likeNum; + + @ApiModelProperty(value = "评论数量,包括其评论及其回复数") + private Integer commentNum; @ApiModelProperty(value = "优先级,是否置顶") private Boolean topPriority; diff --git a/hoj-springboot/api/src/main/java/top/hcode/hoj/pojo/entity/Problem.java b/hoj-springboot/api/src/main/java/top/hcode/hoj/pojo/entity/Problem.java index f6980eee..11d1ae5f 100644 --- a/hoj-springboot/api/src/main/java/top/hcode/hoj/pojo/entity/Problem.java +++ b/hoj-springboot/api/src/main/java/top/hcode/hoj/pojo/entity/Problem.java @@ -45,7 +45,7 @@ public class Problem implements Serializable { @ApiModelProperty(value = "单位ms") private Integer timeLimit; - @ApiModelProperty(value = "单位kb") + @ApiModelProperty(value = "单位mb") private Integer memoryLimit; @ApiModelProperty(value = "单位mb") @@ -104,6 +104,9 @@ public class Problem implements Serializable { @ApiModelProperty(value = "题目测试数据的版本号") private String caseVersion; + @ApiModelProperty(value = "修改题目的管理员用户名") + private String modifiedUser; + @TableField(fill = FieldFill.INSERT) private Date gmtCreate; diff --git a/hoj-vue/src/common/constants.js b/hoj-vue/src/common/constants.js index aa47f2b3..9b72e315 100644 --- a/hoj-vue/src/common/constants.js +++ b/hoj-vue/src/common/constants.js @@ -151,7 +151,8 @@ export const PROBLEM_LEVEL_RESERVE={ export const REMOTE_OJ = [ {name:'HDU',key:"HDU"}, - {name:"Codeforces",key:"CF"} + {name:"Codeforces",key:"CF"}, + {name:"POJ",key:"POJ"}, ] export const CONTEST_STATUS = { diff --git a/hoj-vue/src/components/oj/comment/comment.vue b/hoj-vue/src/components/oj/comment/comment.vue index 57f96502..2e6c9a72 100644 --- a/hoj-vue/src/components/oj/comment/comment.vue +++ b/hoj-vue/src/components/oj/comment/comment.vue @@ -622,7 +622,10 @@ export default { return; } this.replyObj.content = this.replyInputComment; - let replyData = Object.assign({}, this.replyObj); + let replyData = { + reply: this.replyObj, + did: this.did, + }; api.addReply(replyData).then((res) => { for (let i = 0; i < this.comments.length; i++) { if (this.comments[i].id == this.replyObj.commentId) { @@ -715,6 +718,7 @@ export default { .then(() => { let replyDeleteData = { id: reply.id, + did: this.did, fromUid: reply.fromUid, }; api.deleteReply(replyDeleteData).then((res) => { diff --git a/hoj-vue/src/components/oj/common/CodeMirror.vue b/hoj-vue/src/components/oj/common/CodeMirror.vue index 2b82bfd6..e92f0500 100644 --- a/hoj-vue/src/components/oj/common/CodeMirror.vue +++ b/hoj-vue/src/components/oj/common/CodeMirror.vue @@ -1,14 +1,14 @@ + +