From 0073539cab41def69f8d79811ac5b6fc0e9a368a Mon Sep 17 00:00:00 2001 From: Ashar Fuadi Date: Sat, 24 Jun 2023 13:55:26 +0700 Subject: [PATCH] refactor(server): decouple Dropwizard resources from JAX-RS contract interfaces --- .../jerahmeel/archive/ArchiveResource.java | 56 ++++--- .../jerahmeel/chapter/ChapterResource.java | 51 ++++-- .../chapter/lesson/ChapterLessonResource.java | 73 ++++---- .../problem/ChapterProblemResource.java | 77 +++++---- .../jerahmeel/course/CourseResource.java | 72 ++++---- .../course/chapter/CourseChapterResource.java | 91 +++++----- .../curriculum/CurriculumResource.java | 19 ++- .../jerahmeel/problem/ProblemResource.java | 46 +++-- .../jerahmeel/problem/ProblemTagResource.java | 19 ++- .../problemset/ProblemSetResource.java | 110 +++++++----- .../jerahmeel/stats/UserStatsResource.java | 36 ++-- .../bundle/ItemSubmissionResource.java | 129 +++++++------- .../programming/SubmissionResource.java | 131 +++++++-------- .../judgels/jophiel/user/UserResource.java | 91 ++++++---- .../user/account/UserAccountResource.java | 60 ++++--- .../user/avatar/UserAvatarResource.java | 44 +++-- .../jophiel/user/info/UserInfoResource.java | 54 +++--- .../jophiel/user/me/MyUserResource.java | 45 +++-- .../user/rating/UserRatingResource.java | 46 ++--- .../web/UserRegistrationWebResource.java | 7 +- .../user/search/UserSearchResource.java | 36 ++-- .../jophiel/user/web/UserWebResource.java | 37 ++-- .../editorial/ProblemEditorialResource.java | 2 - .../uriel/contest/ContestResource.java | 141 ++++++++++------ .../ContestAnnouncementResource.java | 76 +++++---- .../ContestClarificationResource.java | 86 +++++----- .../contestant/ContestContestantResource.java | 120 ++++++++----- .../editorial/ContestEditorialResource.java | 51 +++--- .../contest/file/ContestFileResource.java | 47 +++--- .../history/ContestHistoryResource.java | 32 ++-- .../uriel/contest/log/ContestLogResource.java | 64 +++---- .../manager/ContestManagerResource.java | 72 ++++---- .../contest/module/ContestModuleResource.java | 90 ++++++---- .../problem/ContestProblemResource.java | 99 +++++------ .../contest/rating/ContestRatingResource.java | 68 ++++---- .../scoreboard/ContestScoreboardResource.java | 76 ++++----- .../bundle/ContestItemSubmissionResource.java | 134 ++++++++------- .../ContestSubmissionResource.java | 158 +++++++++--------- .../supervisor/ContestSupervisorResource.java | 72 ++++---- .../uriel/contest/web/ContestWebResource.java | 59 ++++--- 40 files changed, 1490 insertions(+), 1287 deletions(-) diff --git a/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/archive/ArchiveResource.java b/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/archive/ArchiveResource.java index a8588bea4..cc2e06eb9 100644 --- a/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/archive/ArchiveResource.java +++ b/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/archive/ArchiveResource.java @@ -1,38 +1,40 @@ package judgels.jerahmeel.archive; +import static javax.ws.rs.core.HttpHeaders.AUTHORIZATION; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static judgels.service.ServiceUtils.checkAllowed; import static judgels.service.ServiceUtils.checkFound; import io.dropwizard.hibernate.UnitOfWork; import java.util.Optional; import javax.inject.Inject; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; import judgels.jerahmeel.api.archive.Archive; import judgels.jerahmeel.api.archive.ArchiveCreateData; -import judgels.jerahmeel.api.archive.ArchiveService; import judgels.jerahmeel.api.archive.ArchiveUpdateData; import judgels.jerahmeel.api.archive.ArchivesResponse; import judgels.jerahmeel.role.RoleChecker; import judgels.service.actor.ActorChecker; import judgels.service.api.actor.AuthHeader; -public class ArchiveResource implements ArchiveService { - private final ActorChecker actorChecker; - private final RoleChecker roleChecker; - private final ArchiveStore archiveStore; - - @Inject - public ArchiveResource( - ActorChecker actorChecker, - RoleChecker roleChecker, - ArchiveStore archiveStore) { - this.actorChecker = actorChecker; - this.roleChecker = roleChecker; - this.archiveStore = archiveStore; - } +@Path("/api/v2/archives") +public class ArchiveResource { + @Inject protected ActorChecker actorChecker; + @Inject protected RoleChecker roleChecker; + @Inject protected ArchiveStore archiveStore; + + @Inject public ArchiveResource() {} - @Override + @GET + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) - public ArchivesResponse getArchives(Optional authHeader) { + public ArchivesResponse getArchives(@HeaderParam(AUTHORIZATION) Optional authHeader) { actorChecker.check(authHeader); return new ArchivesResponse.Builder() @@ -40,18 +42,30 @@ public ArchivesResponse getArchives(Optional authHeader) { .build(); } - @Override + @POST + @Consumes(APPLICATION_JSON) + @Produces(APPLICATION_JSON) @UnitOfWork - public Archive createArchive(AuthHeader authHeader, ArchiveCreateData data) { + public Archive createArchive( + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + ArchiveCreateData data) { + String actorJid = actorChecker.check(authHeader); checkAllowed(roleChecker.isAdmin(actorJid)); return archiveStore.createArchive(data); } - @Override + @POST + @Path("/{archiveJid}") + @Consumes(APPLICATION_JSON) + @Produces(APPLICATION_JSON) @UnitOfWork - public Archive updateArchive(AuthHeader authHeader, String archiveJid, ArchiveUpdateData data) { + public Archive updateArchive( + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("archiveJid") String archiveJid, + ArchiveUpdateData data) { + String actorJid = actorChecker.check(authHeader); checkFound(archiveStore.getArchiveByJid(archiveJid)); checkAllowed(roleChecker.isAdmin(actorJid)); diff --git a/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/chapter/ChapterResource.java b/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/chapter/ChapterResource.java index a175c2be3..26bd17dbc 100644 --- a/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/chapter/ChapterResource.java +++ b/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/chapter/ChapterResource.java @@ -1,35 +1,40 @@ package judgels.jerahmeel.chapter; +import static javax.ws.rs.core.HttpHeaders.AUTHORIZATION; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static judgels.service.ServiceUtils.checkAllowed; import static judgels.service.ServiceUtils.checkFound; import io.dropwizard.hibernate.UnitOfWork; import java.util.List; import javax.inject.Inject; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; import judgels.jerahmeel.api.chapter.Chapter; import judgels.jerahmeel.api.chapter.ChapterCreateData; -import judgels.jerahmeel.api.chapter.ChapterService; import judgels.jerahmeel.api.chapter.ChapterUpdateData; import judgels.jerahmeel.api.chapter.ChaptersResponse; import judgels.jerahmeel.role.RoleChecker; import judgels.service.actor.ActorChecker; import judgels.service.api.actor.AuthHeader; -public class ChapterResource implements ChapterService { - private final ActorChecker actorChecker; - private final RoleChecker roleChecker; - private final ChapterStore chapterStore; +@Path("/api/v2/chapters") +public class ChapterResource { + @Inject protected ActorChecker actorChecker; + @Inject protected RoleChecker roleChecker; + @Inject protected ChapterStore chapterStore; - @Inject - public ChapterResource(ActorChecker actorChecker, RoleChecker roleChecker, ChapterStore chapterStore) { - this.actorChecker = actorChecker; - this.roleChecker = roleChecker; - this.chapterStore = chapterStore; - } + @Inject public ChapterResource() {} - @Override + @GET + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) - public ChaptersResponse getChapters(AuthHeader authHeader) { + public ChaptersResponse getChapters(@HeaderParam(AUTHORIZATION) AuthHeader authHeader) { String actorJid = actorChecker.check(authHeader); checkAllowed(roleChecker.isAdmin(actorJid)); @@ -39,18 +44,30 @@ public ChaptersResponse getChapters(AuthHeader authHeader) { .build(); } - @Override + @POST + @Consumes(APPLICATION_JSON) + @Produces(APPLICATION_JSON) @UnitOfWork - public Chapter createChapter(AuthHeader authHeader, ChapterCreateData data) { + public Chapter createChapter( + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + ChapterCreateData data) { + String actorJid = actorChecker.check(authHeader); checkAllowed(roleChecker.isAdmin(actorJid)); return chapterStore.createChapter(data); } - @Override + @POST + @Path("/{chapterJid}") + @Consumes(APPLICATION_JSON) + @Produces(APPLICATION_JSON) @UnitOfWork - public Chapter updateChapter(AuthHeader authHeader, String chapterJid, ChapterUpdateData data) { + public Chapter updateChapter( + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("chapterJid") String chapterJid, + ChapterUpdateData data) { + String actorJid = actorChecker.check(authHeader); checkFound(chapterStore.getChapterByJid(chapterJid)); checkAllowed(roleChecker.isAdmin(actorJid)); diff --git a/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/chapter/lesson/ChapterLessonResource.java b/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/chapter/lesson/ChapterLessonResource.java index 3e8604faa..0cd860902 100644 --- a/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/chapter/lesson/ChapterLessonResource.java +++ b/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/chapter/lesson/ChapterLessonResource.java @@ -1,6 +1,8 @@ package judgels.jerahmeel.chapter.lesson; import static com.google.common.base.Preconditions.checkArgument; +import static javax.ws.rs.core.HttpHeaders.AUTHORIZATION; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static judgels.service.ServiceUtils.checkAllowed; import static judgels.service.ServiceUtils.checkFound; @@ -11,10 +13,18 @@ import java.util.Set; import java.util.stream.Collectors; import javax.inject.Inject; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; import javax.ws.rs.core.UriInfo; import judgels.jerahmeel.api.chapter.lesson.ChapterLesson; import judgels.jerahmeel.api.chapter.lesson.ChapterLessonData; -import judgels.jerahmeel.api.chapter.lesson.ChapterLessonService; import judgels.jerahmeel.api.chapter.lesson.ChapterLessonStatement; import judgels.jerahmeel.api.chapter.lesson.ChapterLessonsResponse; import judgels.jerahmeel.chapter.ChapterStore; @@ -25,31 +35,24 @@ import judgels.service.actor.ActorChecker; import judgels.service.api.actor.AuthHeader; -public class ChapterLessonResource implements ChapterLessonService { - private final ActorChecker actorChecker; - private final RoleChecker roleChecker; - private final ChapterStore chapterStore; - private final ChapterLessonStore lessonStore; - private final LessonClient lessonClient; - - @Inject - public ChapterLessonResource( - ActorChecker actorChecker, - RoleChecker roleChecker, - ChapterStore chapterStore, - ChapterLessonStore lessonStore, - LessonClient lessonClient) { - - this.actorChecker = actorChecker; - this.roleChecker = roleChecker; - this.chapterStore = chapterStore; - this.lessonStore = lessonStore; - this.lessonClient = lessonClient; - } +@Path("/api/v2/chapters/{chapterJid}/lessons") +public class ChapterLessonResource { + @Inject protected ActorChecker actorChecker; + @Inject protected RoleChecker roleChecker; + @Inject protected ChapterStore chapterStore; + @Inject protected ChapterLessonStore lessonStore; + @Inject protected LessonClient lessonClient; + + @Inject public ChapterLessonResource() {} - @Override + @PUT + @Consumes(APPLICATION_JSON) @UnitOfWork - public void setLessons(AuthHeader authHeader, String chapterJid, List data) { + public void setLessons( + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("chapterJid") String chapterJid, + List data) { + String actorJid = actorChecker.check(authHeader); checkFound(chapterStore.getChapterByJid(chapterJid)); checkAllowed(roleChecker.isAdmin(actorJid)); @@ -73,9 +76,13 @@ public void setLessons(AuthHeader authHeader, String chapterJid, List authHeader, String chapterJid) { + public ChapterLessonsResponse getLessons( + @HeaderParam(AUTHORIZATION) Optional authHeader, + @PathParam("chapterJid") String chapterJid) { + actorChecker.check(authHeader); checkFound(chapterStore.getChapterByJid(chapterJid)); @@ -89,14 +96,16 @@ public ChapterLessonsResponse getLessons(Optional authHeader, String .build(); } - @Override + @GET + @Path("/{lessonAlias}/statement") + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) public ChapterLessonStatement getLessonStatement( - UriInfo uriInfo, - Optional authHeader, - String chapterJid, - String lessonAlias, - Optional language) { + @Context UriInfo uriInfo, + @HeaderParam(AUTHORIZATION) Optional authHeader, + @PathParam("chapterJid") String chapterJid, + @PathParam("lessonAlias") String lessonAlias, + @QueryParam("language") Optional language) { actorChecker.check(authHeader); checkFound(chapterStore.getChapterByJid(chapterJid)); diff --git a/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/chapter/problem/ChapterProblemResource.java b/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/chapter/problem/ChapterProblemResource.java index 5234e0e77..63110fd4e 100644 --- a/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/chapter/problem/ChapterProblemResource.java +++ b/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/chapter/problem/ChapterProblemResource.java @@ -1,6 +1,8 @@ package judgels.jerahmeel.chapter.problem; import static com.google.common.base.Preconditions.checkArgument; +import static javax.ws.rs.core.HttpHeaders.AUTHORIZATION; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static judgels.service.ServiceUtils.checkAllowed; import static judgels.service.ServiceUtils.checkFound; @@ -11,10 +13,18 @@ import java.util.Set; import java.util.stream.Collectors; import javax.inject.Inject; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; import javax.ws.rs.core.UriInfo; import judgels.jerahmeel.api.chapter.problem.ChapterProblem; import judgels.jerahmeel.api.chapter.problem.ChapterProblemData; -import judgels.jerahmeel.api.chapter.problem.ChapterProblemService; import judgels.jerahmeel.api.chapter.problem.ChapterProblemWorksheet; import judgels.jerahmeel.api.chapter.problem.ChapterProblemsResponse; import judgels.jerahmeel.api.problem.ProblemProgress; @@ -27,34 +37,25 @@ import judgels.service.actor.ActorChecker; import judgels.service.api.actor.AuthHeader; -public class ChapterProblemResource implements ChapterProblemService { - private final ActorChecker actorChecker; - private final RoleChecker roleChecker; - private final ChapterStore chapterStore; - private final ChapterProblemStore problemStore; - private final ProblemClient problemClient; - private final StatsStore statsStore; - - @Inject - public ChapterProblemResource( - ActorChecker actorChecker, - RoleChecker roleChecker, - ChapterStore chapterStore, - ChapterProblemStore problemStore, - ProblemClient problemClient, - StatsStore statsStore) { - - this.actorChecker = actorChecker; - this.roleChecker = roleChecker; - this.chapterStore = chapterStore; - this.problemStore = problemStore; - this.problemClient = problemClient; - this.statsStore = statsStore; - } +@Path("/api/v2/chapters/{chapterJid}/problems") +public class ChapterProblemResource { + @Inject protected ActorChecker actorChecker; + @Inject protected RoleChecker roleChecker; + @Inject protected ChapterStore chapterStore; + @Inject protected ChapterProblemStore problemStore; + @Inject protected ProblemClient problemClient; + @Inject protected StatsStore statsStore; + + @Inject public ChapterProblemResource() {} - @Override + @PUT + @Consumes(APPLICATION_JSON) @UnitOfWork - public void setProblems(AuthHeader authHeader, String chapterJid, List data) { + public void setProblems( + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("chapterJid") String chapterJid, + List data) { + String actorJid = actorChecker.check(authHeader); checkFound(chapterStore.getChapterByJid(chapterJid)); checkAllowed(roleChecker.isAdmin(actorJid)); @@ -79,9 +80,13 @@ public void setProblems(AuthHeader authHeader, String chapterJid, List authHeader, String chapterJid) { + public ChapterProblemsResponse getProblems( + @HeaderParam(AUTHORIZATION) Optional authHeader, + @PathParam("chapterJid") String chapterJid) { + String actorJid = actorChecker.check(authHeader); checkFound(chapterStore.getChapterByJid(chapterJid)); @@ -97,14 +102,16 @@ public ChapterProblemsResponse getProblems(Optional authHeader, Stri .build(); } - @Override + @GET + @Path("/{problemAlias}/worksheet") + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) public ChapterProblemWorksheet getProblemWorksheet( - UriInfo uriInfo, - Optional authHeader, - String chapterJid, - String problemAlias, - Optional language) { + @Context UriInfo uriInfo, + @HeaderParam(AUTHORIZATION) Optional authHeader, + @PathParam("chapterJid") String chapterJid, + @PathParam("problemAlias") String problemAlias, + @QueryParam("language") Optional language) { actorChecker.check(authHeader); checkFound(chapterStore.getChapterByJid(chapterJid)); diff --git a/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/course/CourseResource.java b/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/course/CourseResource.java index 2aeeb2c09..c23a87cfb 100644 --- a/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/course/CourseResource.java +++ b/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/course/CourseResource.java @@ -1,5 +1,7 @@ package judgels.jerahmeel.course; +import static javax.ws.rs.core.HttpHeaders.AUTHORIZATION; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static judgels.service.ServiceUtils.checkAllowed; import static judgels.service.ServiceUtils.checkFound; @@ -10,10 +12,16 @@ import java.util.Set; import java.util.stream.Collectors; import javax.inject.Inject; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; import judgels.jerahmeel.api.course.Course; import judgels.jerahmeel.api.course.CourseCreateData; import judgels.jerahmeel.api.course.CourseProgress; -import judgels.jerahmeel.api.course.CourseService; import judgels.jerahmeel.api.course.CourseUpdateData; import judgels.jerahmeel.api.course.CoursesResponse; import judgels.jerahmeel.api.curriculum.Curriculum; @@ -23,31 +31,20 @@ import judgels.service.actor.ActorChecker; import judgels.service.api.actor.AuthHeader; -public class CourseResource implements CourseService { - private final ActorChecker actorChecker; - private final RoleChecker roleChecker; - private final CourseStore courseStore; - private final CurriculumStore curriculumStore; - private final StatsStore statsStore; +@Path("/api/v2/courses") +public class CourseResource { + @Inject protected ActorChecker actorChecker; + @Inject protected RoleChecker roleChecker; + @Inject protected CourseStore courseStore; + @Inject protected CurriculumStore curriculumStore; + @Inject protected StatsStore statsStore; - @Inject - public CourseResource( - ActorChecker actorChecker, - RoleChecker roleChecker, - CourseStore courseStore, - CurriculumStore curriculumStore, - StatsStore statsStore) { + @Inject public CourseResource() {} - this.actorChecker = actorChecker; - this.roleChecker = roleChecker; - this.courseStore = courseStore; - this.curriculumStore = curriculumStore; - this.statsStore = statsStore; - } - - @Override + @GET + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) - public CoursesResponse getCourses(Optional authHeader) { + public CoursesResponse getCourses(@HeaderParam(AUTHORIZATION) Optional authHeader) { String actorJid = actorChecker.check(authHeader); List courses = courseStore.getCourses(); @@ -61,26 +58,43 @@ public CoursesResponse getCourses(Optional authHeader) { .build(); } - @Override + @GET + @Path("/slug/{courseSlug}") + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) - public Course getCourseBySlug(Optional authHeader, String courseSlug) { + public Course getCourseBySlug( + @HeaderParam(AUTHORIZATION) Optional authHeader, + @PathParam("courseSlug") String courseSlug) { + actorChecker.check(authHeader); return checkFound(courseStore.getCourseBySlug(courseSlug)); } - @Override + @POST + @Consumes(APPLICATION_JSON) + @Produces(APPLICATION_JSON) @UnitOfWork - public Course createCourse(AuthHeader authHeader, CourseCreateData data) { + public Course createCourse( + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + CourseCreateData data) { + String actorJid = actorChecker.check(authHeader); checkAllowed(roleChecker.isAdmin(actorJid)); return courseStore.createCourse(data); } - @Override + @POST + @Path("/{courseJid}") + @Consumes(APPLICATION_JSON) + @Produces(APPLICATION_JSON) @UnitOfWork - public Course updateCourse(AuthHeader authHeader, String courseJid, CourseUpdateData data) { + public Course updateCourse( + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("courseJid") String courseJid, + CourseUpdateData data) { + String actorJid = actorChecker.check(authHeader); checkFound(courseStore.getCourseByJid(courseJid)); checkAllowed(roleChecker.isAdmin(actorJid)); diff --git a/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/course/chapter/CourseChapterResource.java b/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/course/chapter/CourseChapterResource.java index c2a273bbc..b8e3295f2 100644 --- a/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/course/chapter/CourseChapterResource.java +++ b/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/course/chapter/CourseChapterResource.java @@ -3,6 +3,8 @@ import static com.google.common.base.Preconditions.checkArgument; import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toSet; +import static javax.ws.rs.core.HttpHeaders.AUTHORIZATION; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static judgels.service.ServiceUtils.checkAllowed; import static judgels.service.ServiceUtils.checkFound; @@ -15,13 +17,20 @@ import java.util.Optional; import java.util.Set; import javax.inject.Inject; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; import judgels.jerahmeel.api.chapter.Chapter; import judgels.jerahmeel.api.chapter.ChapterInfo; import judgels.jerahmeel.api.chapter.ChapterProgress; import judgels.jerahmeel.api.chapter.lesson.ChapterLesson; import judgels.jerahmeel.api.course.chapter.CourseChapter; import judgels.jerahmeel.api.course.chapter.CourseChapterResponse; -import judgels.jerahmeel.api.course.chapter.CourseChapterService; import judgels.jerahmeel.api.course.chapter.CourseChapterUserProgressesData; import judgels.jerahmeel.api.course.chapter.CourseChapterUserProgressesResponse; import judgels.jerahmeel.api.course.chapter.CourseChaptersResponse; @@ -34,40 +43,27 @@ import judgels.service.actor.ActorChecker; import judgels.service.api.actor.AuthHeader; -public class CourseChapterResource implements CourseChapterService { - private final ActorChecker actorChecker; - private final RoleChecker roleChecker; - private final CourseStore courseStore; - private final CourseChapterStore courseChapterStore; - private final ChapterStore chapterStore; - private final ChapterLessonStore chapterLessonStore; - private final StatsStore statsStore; - private final UserClient userClient; - - @Inject - public CourseChapterResource( - ActorChecker actorChecker, - RoleChecker roleChecker, - CourseStore courseStore, - CourseChapterStore courseChapterStore, - ChapterStore chapterStore, - ChapterLessonStore chapterLessonStore, - StatsStore statsStore, - UserClient userClient) { - - this.actorChecker = actorChecker; - this.roleChecker = roleChecker; - this.courseStore = courseStore; - this.courseChapterStore = courseChapterStore; - this.chapterLessonStore = chapterLessonStore; - this.chapterStore = chapterStore; - this.statsStore = statsStore; - this.userClient = userClient; - } - - @Override +@Path("/api/v2/courses/{courseJid}/chapters") +public class CourseChapterResource { + @Inject protected ActorChecker actorChecker; + @Inject protected RoleChecker roleChecker; + @Inject protected CourseStore courseStore; + @Inject protected CourseChapterStore courseChapterStore; + @Inject protected ChapterStore chapterStore; + @Inject protected ChapterLessonStore chapterLessonStore; + @Inject protected StatsStore statsStore; + @Inject protected UserClient userClient; + + @Inject public CourseChapterResource() {} + + @PUT + @Consumes(APPLICATION_JSON) @UnitOfWork - public void setChapters(AuthHeader authHeader, String courseJid, List data) { + public void setChapters( + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("courseJid") String courseJid, + List data) { + String actorJid = actorChecker.check(authHeader); checkFound(courseStore.getCourseByJid(courseJid)); checkAllowed(roleChecker.isAdmin(actorJid)); @@ -81,9 +77,13 @@ public void setChapters(AuthHeader authHeader, String courseJid, List authHeader, String courseJid) { + public CourseChaptersResponse getChapters( + @HeaderParam(AUTHORIZATION) Optional authHeader, + @PathParam("courseJid") String courseJid) { + String actorJid = actorChecker.check(authHeader); checkFound(courseStore.getCourseByJid(courseJid)); @@ -99,9 +99,15 @@ public CourseChaptersResponse getChapters(Optional authHeader, Strin .build(); } - @Override + @GET + @Path("/{chapterAlias}") + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) - public CourseChapterResponse getChapter(Optional authHeader, String courseJid, String chapterAlias) { + public CourseChapterResponse getChapter( + @HeaderParam(AUTHORIZATION) Optional authHeader, + @PathParam("courseJid") String courseJid, + @PathParam("chapterAlias") String chapterAlias) { + checkFound(courseStore.getCourseByJid(courseJid)); CourseChapter courseChapter = checkFound(courseChapterStore.getChapterByAlias(courseJid, chapterAlias)); @@ -116,11 +122,14 @@ public CourseChapterResponse getChapter(Optional authHeader, String .build(); } - @Override + @POST + @Path("/user-progresses") + @Consumes(APPLICATION_JSON) + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) public CourseChapterUserProgressesResponse getChapterUserProgresses( - Optional authHeader, - String courseJid, + @HeaderParam(AUTHORIZATION) Optional authHeader, + @PathParam("courseJid") String courseJid, CourseChapterUserProgressesData data) { checkFound(courseStore.getCourseByJid(courseJid)); diff --git a/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/curriculum/CurriculumResource.java b/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/curriculum/CurriculumResource.java index 2e12df6ba..d26751178 100644 --- a/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/curriculum/CurriculumResource.java +++ b/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/curriculum/CurriculumResource.java @@ -1,19 +1,22 @@ package judgels.jerahmeel.curriculum; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; + import io.dropwizard.hibernate.UnitOfWork; import javax.inject.Inject; -import judgels.jerahmeel.api.curriculum.CurriculumService; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; import judgels.jerahmeel.api.curriculum.CurriculumsResponse; -public class CurriculumResource implements CurriculumService { - private final CurriculumStore curriculumStore; +@Path("/api/v2/curriculums") +public class CurriculumResource { + @Inject protected CurriculumStore curriculumStore; - @Inject - public CurriculumResource(CurriculumStore curriculumStore) { - this.curriculumStore = curriculumStore; - } + @Inject public CurriculumResource() {} - @Override + @GET + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) public CurriculumsResponse getCurriculums() { return new CurriculumsResponse.Builder() diff --git a/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/problem/ProblemResource.java b/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/problem/ProblemResource.java index 8dd5ce838..9c3ef27ab 100644 --- a/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/problem/ProblemResource.java +++ b/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/problem/ProblemResource.java @@ -1,11 +1,18 @@ package judgels.jerahmeel.problem; +import static javax.ws.rs.core.HttpHeaders.AUTHORIZATION; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; + import io.dropwizard.hibernate.UnitOfWork; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import javax.inject.Inject; -import judgels.jerahmeel.api.problem.ProblemService; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; import judgels.jerahmeel.api.problem.ProblemSetProblemInfo; import judgels.jerahmeel.api.problem.ProblemsResponse; import judgels.jerahmeel.difficulty.ProblemDifficultyStore; @@ -15,36 +22,25 @@ import judgels.service.actor.ActorChecker; import judgels.service.api.actor.AuthHeader; -public class ProblemResource implements ProblemService { +@Path("/api/v2/problems") +public class ProblemResource { private static final int PAGE_SIZE = 20; - private final ActorChecker actorChecker; - private final ProblemStore problemStore; - private final StatsStore statsStore; - private final ProblemDifficultyStore difficultyStore; - private final ProblemClient problemClient; - - @Inject - public ProblemResource( - ActorChecker actorChecker, - ProblemStore problemStore, - StatsStore statsStore, - ProblemDifficultyStore difficultyStore, - ProblemClient problemClient) { + @Inject protected ActorChecker actorChecker; + @Inject protected ProblemStore problemStore; + @Inject protected StatsStore statsStore; + @Inject protected ProblemDifficultyStore difficultyStore; + @Inject protected ProblemClient problemClient; - this.actorChecker = actorChecker; - this.problemStore = problemStore; - this.statsStore = statsStore; - this.difficultyStore = difficultyStore; - this.problemClient = problemClient; - } + @Inject public ProblemResource() {} - @Override + @GET + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) public ProblemsResponse getProblems( - Optional authHeader, - Set tags, - Optional pageNumber) { + @HeaderParam(AUTHORIZATION) Optional authHeader, + @QueryParam("tags") Set tags, + @QueryParam("page") Optional pageNumber) { String actorJid = actorChecker.check(authHeader); diff --git a/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/problem/ProblemTagResource.java b/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/problem/ProblemTagResource.java index b45c425c0..b7764ceab 100644 --- a/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/problem/ProblemTagResource.java +++ b/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/problem/ProblemTagResource.java @@ -1,24 +1,27 @@ package judgels.jerahmeel.problem; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; + import io.dropwizard.hibernate.UnitOfWork; import java.util.Map; import java.util.stream.Collectors; import javax.inject.Inject; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; import judgels.jerahmeel.api.problem.ProblemTagCategory; import judgels.jerahmeel.api.problem.ProblemTagOption; -import judgels.jerahmeel.api.problem.ProblemTagService; import judgels.jerahmeel.api.problem.ProblemTagsResponse; import judgels.sandalphon.problem.base.tag.ProblemTagStore; -public class ProblemTagResource implements ProblemTagService { - private final ProblemTagStore tagStore; +@Path("/api/v2/problems/tags") +public class ProblemTagResource { + @Inject protected ProblemTagStore tagStore; - @Inject - public ProblemTagResource(ProblemTagStore tagStore) { - this.tagStore = tagStore; - } + @Inject public ProblemTagResource() {} - @Override + @GET + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) public ProblemTagsResponse getProblemTags() { Map tagCounts = tagStore.getPublicTagCounts(); diff --git a/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/problemset/ProblemSetResource.java b/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/problemset/ProblemSetResource.java index 4764d7b22..0aaa12f7c 100644 --- a/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/problemset/ProblemSetResource.java +++ b/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/problemset/ProblemSetResource.java @@ -2,6 +2,8 @@ import static com.google.common.base.Preconditions.checkArgument; import static java.util.stream.Collectors.toSet; +import static javax.ws.rs.core.HttpHeaders.AUTHORIZATION; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static judgels.service.ServiceUtils.checkAllowed; import static judgels.service.ServiceUtils.checkFound; @@ -15,12 +17,19 @@ import java.util.Set; import java.util.stream.Collectors; import javax.inject.Inject; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; import judgels.jerahmeel.api.archive.Archive; import judgels.jerahmeel.api.problem.ProblemProgress; import judgels.jerahmeel.api.problemset.ProblemSet; import judgels.jerahmeel.api.problemset.ProblemSetCreateData; import judgels.jerahmeel.api.problemset.ProblemSetProgress; -import judgels.jerahmeel.api.problemset.ProblemSetService; import judgels.jerahmeel.api.problemset.ProblemSetStatsResponse; import judgels.jerahmeel.api.problemset.ProblemSetUpdateData; import judgels.jerahmeel.api.problemset.ProblemSetUserProgressesData; @@ -37,43 +46,28 @@ import judgels.service.actor.ActorChecker; import judgels.service.api.actor.AuthHeader; -public class ProblemSetResource implements ProblemSetService { +@Path("/api/v2/problemsets") +public class ProblemSetResource { private static final int PAGE_SIZE = 20; - private final ActorChecker actorChecker; - private final RoleChecker roleChecker; - private final ProblemSetStore problemSetStore; - private final ProblemSetProblemStore problemSetProblemStore; - private final ArchiveStore archiveStore; - private final StatsStore statsStore; - private final UserClient userClient; - - @Inject - public ProblemSetResource( - ActorChecker actorChecker, - RoleChecker roleChecker, - ProblemSetStore problemSetStore, - ProblemSetProblemStore problemSetProblemStore, - ArchiveStore archiveStore, - StatsStore statsStore, - UserClient userClient) { - - this.actorChecker = actorChecker; - this.roleChecker = roleChecker; - this.problemSetStore = problemSetStore; - this.problemSetProblemStore = problemSetProblemStore; - this.archiveStore = archiveStore; - this.statsStore = statsStore; - this.userClient = userClient; - } + @Inject protected ActorChecker actorChecker; + @Inject protected RoleChecker roleChecker; + @Inject protected ProblemSetStore problemSetStore; + @Inject protected ProblemSetProblemStore problemSetProblemStore; + @Inject protected ArchiveStore archiveStore; + @Inject protected StatsStore statsStore; + @Inject protected UserClient userClient; + + @Inject public ProblemSetResource() {} - @Override + @GET + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) public ProblemSetsResponse getProblemSets( - Optional authHeader, - Optional archiveSlug, - Optional nameFilter, - Optional pageNumber) { + @HeaderParam(AUTHORIZATION) Optional authHeader, + @QueryParam("archiveSlug") Optional archiveSlug, + @QueryParam("name") Optional name, + @QueryParam("page") Optional pageNumber) { String actorJid = actorChecker.check(authHeader); @@ -81,7 +75,7 @@ public ProblemSetsResponse getProblemSets( Optional archiveJid = archiveSlug.isPresent() ? Optional.of(archive.map(Archive::getJid).orElse("")) : Optional.empty(); - Page problemSets = problemSetStore.getProblemSets(archiveJid, nameFilter, pageNumber.orElse(1), PAGE_SIZE); + Page problemSets = problemSetStore.getProblemSets(archiveJid, name, pageNumber.orElse(1), PAGE_SIZE); Set problemSetJids = problemSets.getPage().stream().map(ProblemSet::getJid).collect(toSet()); Set archiveJids = problemSets.getPage().stream().map(ProblemSet::getArchiveJid).collect(toSet()); Map archivesMap = archiveStore.getArchivesByJids(archiveJids); @@ -111,9 +105,14 @@ public ProblemSetsResponse getProblemSets( .build(); } - @Override + @GET + @Path("/{problemSetJid}/stats") + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) - public ProblemSetStatsResponse getProblemSetStats(Optional authHeader, String problemSetJid) { + public ProblemSetStatsResponse getProblemSetStats( + @HeaderParam(AUTHORIZATION) Optional authHeader, + @PathParam("problemSetJid") String problemSetJid) { + String actorJid = actorChecker.check(authHeader); ProblemSetProgress progress = statsStore .getProblemSetProgressesMap(actorJid, ImmutableSet.of(problemSetJid)) @@ -123,24 +122,38 @@ public ProblemSetStatsResponse getProblemSetStats(Optional authHeade .build(); } - @Override + @GET + @Path("/slug/{problemSetSlug}") + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) - public ProblemSet getProblemSetBySlug(Optional authHeader, String problemSetSlug) { + public ProblemSet getProblemSetBySlug(@PathParam("problemSetSlug") String problemSetSlug) { return checkFound(problemSetStore.getProblemSetBySlug(problemSetSlug)); } - @Override + @POST + @Consumes(APPLICATION_JSON) + @Produces(APPLICATION_JSON) @UnitOfWork - public ProblemSet createProblemSet(AuthHeader authHeader, ProblemSetCreateData data) { + public ProblemSet createProblemSet( + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + ProblemSetCreateData data) { + String actorJid = actorChecker.check(authHeader); checkAllowed(roleChecker.isAdmin(actorJid)); return problemSetStore.createProblemSet(data); } - @Override + @POST + @Path("/{problemSetJid}") + @Consumes(APPLICATION_JSON) + @Produces(APPLICATION_JSON) @UnitOfWork - public ProblemSet updateProblemSet(AuthHeader authHeader, String problemSetJid, ProblemSetUpdateData data) { + public ProblemSet updateProblemSet( + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("problemSetJid") String problemSetJid, + ProblemSetUpdateData data) { + String actorJid = actorChecker.check(authHeader); checkFound(problemSetStore.getProblemSetByJid(problemSetJid)); checkAllowed(roleChecker.isAdmin(actorJid)); @@ -148,13 +161,18 @@ public ProblemSet updateProblemSet(AuthHeader authHeader, String problemSetJid, return problemSetStore.updateProblemSet(problemSetJid, data); } - @Override - @UnitOfWork - public ProblemSet searchProblemSet(String contestJid) { + @GET + @Path("/search") + @Produces(APPLICATION_JSON) + @UnitOfWork(readOnly = true) + public ProblemSet searchProblemSet(@QueryParam("contestJid") String contestJid) { return checkFound(problemSetStore.getProblemSetByContestJid(contestJid)); } - @Override + @POST + @Path("/user-progresses") + @Consumes(APPLICATION_JSON) + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) public ProblemSetUserProgressesResponse getProblemSetUserProgresses(ProblemSetUserProgressesData data) { checkArgument(data.getUsernames().size() <= 100, "Cannot get more than 100 users."); diff --git a/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/stats/UserStatsResource.java b/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/stats/UserStatsResource.java index 62ebc02fd..d0e922f9d 100644 --- a/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/stats/UserStatsResource.java +++ b/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/stats/UserStatsResource.java @@ -1,6 +1,7 @@ package judgels.jerahmeel.stats; import static java.util.stream.Collectors.toSet; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static judgels.service.ServiceUtils.checkFound; import io.dropwizard.hibernate.UnitOfWork; @@ -8,30 +9,32 @@ import java.util.Optional; import java.util.Set; import javax.inject.Inject; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; import judgels.jerahmeel.api.stats.UserStats; -import judgels.jerahmeel.api.stats.UserStatsService; import judgels.jerahmeel.api.stats.UserTopStatsEntry; import judgels.jerahmeel.api.stats.UserTopStatsResponse; import judgels.jophiel.api.profile.Profile; import judgels.jophiel.user.UserClient; import judgels.persistence.api.Page; -public class UserStatsResource implements UserStatsService { - private final StatsStore statsStore; - private final UserClient userClient; +@Path("/api/v2/stats/users") +public class UserStatsResource { + @Inject protected StatsStore statsStore; + @Inject protected UserClient userClient; - @Inject - public UserStatsResource( - StatsStore statsStore, - UserClient userClient) { + @Inject public UserStatsResource() {} - this.statsStore = statsStore; - this.userClient = userClient; - } - - @Override + @GET + @Path("/top") + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) - public UserTopStatsResponse getTopUserStats(Optional pageNumber, Optional pageSize) { + public UserTopStatsResponse getTopUserStats( + @QueryParam("page") Optional pageNumber, + @QueryParam("pageSize") Optional pageSize) { + Page stats = statsStore.getTopUserStats(pageNumber.orElse(1), pageSize.orElse(50)); Set userJids = stats.getPage().stream().map(UserTopStatsEntry::getUserJid).collect(toSet()); Map profileMap = userClient.getProfiles(userJids); @@ -42,9 +45,10 @@ public UserTopStatsResponse getTopUserStats(Optional pageNumber, Option .build(); } - @Override + @GET + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) - public UserStats getUserStats(String username) { + public UserStats getUserStats(@QueryParam("username") String username) { String userJid = checkFound(userClient.translateUsernameToJid(username)); return statsStore.getUserStats(userJid); } diff --git a/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/submission/bundle/ItemSubmissionResource.java b/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/submission/bundle/ItemSubmissionResource.java index b29e28062..f20098be8 100644 --- a/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/submission/bundle/ItemSubmissionResource.java +++ b/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/submission/bundle/ItemSubmissionResource.java @@ -1,6 +1,8 @@ package judgels.jerahmeel.submission.bundle; import static java.util.stream.Collectors.toSet; +import static javax.ws.rs.core.HttpHeaders.AUTHORIZATION; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static judgels.service.ServiceUtils.checkAllowed; import static judgels.service.ServiceUtils.checkFound; @@ -17,10 +19,17 @@ import java.util.function.Function; import java.util.stream.Collectors; import javax.inject.Inject; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; import judgels.jerahmeel.api.chapter.problem.ChapterProblem; import judgels.jerahmeel.api.problemset.problem.ProblemSetProblem; import judgels.jerahmeel.api.submission.SubmissionConfig; -import judgels.jerahmeel.api.submission.bundle.ItemSubmissionService; import judgels.jerahmeel.api.submission.bundle.ItemSubmissionsResponse; import judgels.jerahmeel.api.submission.bundle.SubmissionSummaryResponse; import judgels.jerahmeel.chapter.problem.ChapterProblemStore; @@ -43,51 +52,32 @@ import judgels.service.actor.ActorChecker; import judgels.service.api.actor.AuthHeader; -public class ItemSubmissionResource implements ItemSubmissionService { +@Path("/api/v2/submissions/bundle") +public class ItemSubmissionResource { private static final int PAGE_SIZE = 20; - private final ActorChecker actorChecker; - private final ItemSubmissionStore submissionStore; - private final SubmissionRoleChecker submissionRoleChecker; - private final ItemSubmissionGraderRegistry itemSubmissionGraderRegistry; - private final ItemSubmissionRegrader itemSubmissionRegrader; - private final UserClient userClient; - private final ProblemClient problemClient; - - private final ProblemSetProblemStore problemSetProblemStore; - private final ChapterProblemStore chapterProblemStore; - - @Inject - public ItemSubmissionResource( - ActorChecker actorChecker, - ItemSubmissionStore submissionStore, - SubmissionRoleChecker submissionRoleChecker, - ItemSubmissionGraderRegistry itemSubmissionGraderRegistry, - ItemSubmissionRegrader itemSubmissionRegrader, - UserClient userClient, - ProblemClient problemClient, - ProblemSetProblemStore problemSetProblemStore, - ChapterProblemStore chapterProblemStore) { - - this.actorChecker = actorChecker; - this.submissionStore = submissionStore; - this.submissionRoleChecker = submissionRoleChecker; - this.itemSubmissionGraderRegistry = itemSubmissionGraderRegistry; - this.itemSubmissionRegrader = itemSubmissionRegrader; - this.userClient = userClient; - this.problemClient = problemClient; - this.problemSetProblemStore = problemSetProblemStore; - this.chapterProblemStore = chapterProblemStore; - } + @Inject protected ActorChecker actorChecker; + @Inject protected ItemSubmissionStore submissionStore; + @Inject protected SubmissionRoleChecker submissionRoleChecker; + @Inject protected ItemSubmissionGraderRegistry itemSubmissionGraderRegistry; + @Inject protected ItemSubmissionRegrader itemSubmissionRegrader; + @Inject protected UserClient userClient; + @Inject protected ProblemClient problemClient; - @Override - @UnitOfWork + @Inject protected ProblemSetProblemStore problemSetProblemStore; + @Inject protected ChapterProblemStore chapterProblemStore; + + @Inject public ItemSubmissionResource() {} + + @GET + @Produces(APPLICATION_JSON) + @UnitOfWork(readOnly = true) public ItemSubmissionsResponse getSubmissions( - Optional authHeader, - String containerJid, - Optional username, - Optional problemAlias, - Optional pageNumber) { + @HeaderParam(AUTHORIZATION) Optional authHeader, + @QueryParam("containerJid") String containerJid, + @QueryParam("username") Optional username, + @QueryParam("problemAlias") Optional problemAlias, + @QueryParam("page") Optional pageNumber) { String actorJid = actorChecker.check(authHeader); @@ -100,7 +90,7 @@ public ItemSubmissionsResponse getSubmissions( problemJid = Optional.of(getProblemJidByAlias(containerJid, problemAlias.get()).orElse("")); } - Page submissions = submissionStore.getSubmissions(containerJid, userJid, problemJid, pageNumber.orElse(1), 20); + Page submissions = submissionStore.getSubmissions(containerJid, userJid, problemJid, pageNumber.orElse(1), PAGE_SIZE); Set userJids = submissions.getPage().stream().map(ItemSubmission::getUserJid).collect(toSet()); Set problemJids = submissions.getPage().stream().map(ItemSubmission::getProblemJid).collect(toSet()); @@ -138,9 +128,13 @@ public ItemSubmissionsResponse getSubmissions( .build(); } - @Override + @POST + @Consumes(APPLICATION_JSON) @UnitOfWork - public void createItemSubmission(AuthHeader authHeader, ItemSubmissionData data) { + public void createItemSubmission( + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + ItemSubmissionData data) { + String actorJid = actorChecker.check(authHeader); Item item = checkFound(problemClient.getItem(data.getProblemJid(), data.getItemJid())); @@ -163,13 +157,15 @@ public void createItemSubmission(AuthHeader authHeader, ItemSubmissionData data) } } - @Override + @GET + @Path("/answers") + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) public Map getLatestSubmissions( - Optional authHeader, - String containerJid, - Optional username, - String problemAlias) { + @HeaderParam(AUTHORIZATION) Optional authHeader, + @QueryParam("containerJid") String containerJid, + @QueryParam("username") Optional username, + @QueryParam("problemAlias") String problemAlias) { String actorJid = actorChecker.check(authHeader); @@ -193,14 +189,16 @@ public Map getLatestSubmissions( .collect(Collectors.toMap(ItemSubmission::getItemJid, Function.identity())); } - @Override + @GET + @Path("/summary") + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) public SubmissionSummaryResponse getSubmissionSummary( - AuthHeader authHeader, - String containerJid, - Optional problemJid, - Optional username, - Optional language) { + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @QueryParam("containerJid") String containerJid, + @QueryParam("problemJid") Optional problemJid, + @QueryParam("username") Optional username, + @QueryParam("language") Optional language) { String actorJid = actorChecker.check(authHeader); @@ -263,9 +261,13 @@ public SubmissionSummaryResponse getSubmissionSummary( .build(); } - @Override + @POST + @Path("/{submissionJid}/regrade") @UnitOfWork - public void regradeSubmission(AuthHeader authHeader, String submissionJid) { + public void regradeSubmission( + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("submissionJid") String submissionJid) { + String actorJid = actorChecker.check(authHeader); ItemSubmission submission = checkFound(submissionStore.getSubmissionByJid(submissionJid)); checkAllowed(submissionRoleChecker.canManage(actorJid)); @@ -273,13 +275,14 @@ public void regradeSubmission(AuthHeader authHeader, String submissionJid) { itemSubmissionRegrader.regradeSubmission(submission); } - @Override + @POST + @Path("/regrade") @UnitOfWork public void regradeSubmissions( - AuthHeader authHeader, - Optional containerJid, - Optional userJid, - Optional problemJid) { + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @QueryParam("containerJid") Optional containerJid, + @QueryParam("userJid") Optional userJid, + @QueryParam("problemJid") Optional problemJid) { String actorJid = actorChecker.check(authHeader); checkAllowed(submissionRoleChecker.canManage(actorJid)); diff --git a/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/submission/programming/SubmissionResource.java b/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/submission/programming/SubmissionResource.java index ac1a05c4d..f4701a891 100644 --- a/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/submission/programming/SubmissionResource.java +++ b/judgels-backends/judgels-server-app/src/main/java/judgels/jerahmeel/submission/programming/SubmissionResource.java @@ -3,6 +3,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import static java.util.stream.Collectors.toSet; import static javax.ws.rs.core.HttpHeaders.AUTHORIZATION; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static javax.ws.rs.core.MediaType.MULTIPART_FORM_DATA; import static judgels.service.ServiceUtils.buildDarkImageResponseFromText; import static judgels.service.ServiceUtils.buildLightImageResponseFromText; @@ -19,9 +20,13 @@ import java.util.Set; import javax.inject.Inject; import javax.ws.rs.Consumes; +import javax.ws.rs.GET; import javax.ws.rs.HeaderParam; import javax.ws.rs.POST; import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; import javax.ws.rs.core.Response; import judgels.gabriel.api.SubmissionSource; import judgels.jerahmeel.api.chapter.Chapter; @@ -29,7 +34,6 @@ import judgels.jerahmeel.api.problemset.ProblemSet; import judgels.jerahmeel.api.problemset.problem.ProblemSetProblem; import judgels.jerahmeel.api.submission.SubmissionConfig; -import judgels.jerahmeel.api.submission.programming.SubmissionService; import judgels.jerahmeel.api.submission.programming.SubmissionsResponse; import judgels.jerahmeel.chapter.ChapterStore; import judgels.jerahmeel.chapter.problem.ChapterProblemStore; @@ -57,66 +61,37 @@ import judgels.service.api.actor.AuthHeader; import org.glassfish.jersey.media.multipart.FormDataMultiPart; -public class SubmissionResource implements SubmissionService { +@Path("/api/v2/submissions/programming") +public class SubmissionResource { private static final int PAGE_SIZE = 20; - private final ActorChecker actorChecker; - private final SubmissionStore submissionStore; - private final SubmissionSourceBuilder submissionSourceBuilder; - private final SubmissionClient submissionClient; - private final SubmissionRegrader submissionRegrader; - private final SubmissionRoleChecker submissionRoleChecker; - private final UserClient userClient; - private final ProblemClient problemClient; - - private final ProblemSetStore problemSetStore; - private final ProblemSetProblemStore problemSetProblemStore; - - private final ChapterStore chapterStore; - private final ChapterProblemStore chapterProblemStore; - - @Inject - public SubmissionResource( - ActorChecker actorChecker, - @JerahmeelSubmissionStore SubmissionStore submissionStore, - SubmissionSourceBuilder submissionSourceBuilder, - SubmissionClient submissionClient, - SubmissionRegrader submissionRegrader, - SubmissionRoleChecker submissionRoleChecker, - UserClient userClient, - ProblemClient problemClient, - - ProblemSetStore problemSetStore, - ProblemSetProblemStore problemSetProblemStore, - - ChapterStore chapterStore, - ChapterProblemStore chapterProblemStore) { - - this.actorChecker = actorChecker; - this.submissionStore = submissionStore; - this.submissionSourceBuilder = submissionSourceBuilder; - this.submissionClient = submissionClient; - this.submissionRegrader = submissionRegrader; - this.submissionRoleChecker = submissionRoleChecker; - this.userClient = userClient; - this.problemClient = problemClient; - - this.problemSetStore = problemSetStore; - this.problemSetProblemStore = problemSetProblemStore; - - this.chapterStore = chapterStore; - this.chapterProblemStore = chapterProblemStore; - } + @Inject protected ActorChecker actorChecker; + @Inject @JerahmeelSubmissionStore protected SubmissionStore submissionStore; + @Inject protected SubmissionSourceBuilder submissionSourceBuilder; + @Inject protected SubmissionClient submissionClient; + @Inject protected SubmissionRegrader submissionRegrader; + @Inject protected SubmissionRoleChecker submissionRoleChecker; + @Inject protected UserClient userClient; + @Inject protected ProblemClient problemClient; + + @Inject protected ProblemSetStore problemSetStore; + @Inject protected ProblemSetProblemStore problemSetProblemStore; + + @Inject protected ChapterStore chapterStore; + @Inject protected ChapterProblemStore chapterProblemStore; - @Override + @Inject public SubmissionResource() {} + + @GET + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) public SubmissionsResponse getSubmissions( - Optional authHeader, - Optional containerJid, - Optional username, - Optional problemJid, - Optional problemAlias, - Optional pageNumber) { + @HeaderParam(AUTHORIZATION) Optional authHeader, + @QueryParam("containerJid") Optional containerJid, + @QueryParam("username") Optional username, + @QueryParam("problemJid") Optional problemJid, + @QueryParam("problemAlias") Optional problemAlias, + @QueryParam("page") Optional pageNumber) { String actorJid = actorChecker.check(authHeader); @@ -179,12 +154,14 @@ public SubmissionsResponse getSubmissions( .build(); } - @Override + @GET + @Path("/id/{submissionId}") + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) public SubmissionWithSourceResponse getSubmissionWithSourceById( - Optional authHeader, - long submissionId, - Optional language) { + @HeaderParam(AUTHORIZATION) Optional authHeader, + @PathParam("submissionId") long submissionId, + @QueryParam("language") Optional language) { String actorJid = actorChecker.check(authHeader); Submission submission = checkFound(submissionStore.getSubmissionById(submissionId)); @@ -237,18 +214,22 @@ public SubmissionWithSourceResponse getSubmissionWithSourceById( .build(); } - @Override + @GET + @Path("/{submissionJid}/image") + @Produces("image/png") @UnitOfWork(readOnly = true) - public Response getSubmissionSourceImage(String submissionJid) { + public Response getSubmissionSourceImage(@PathParam("submissionJid") String submissionJid) { Submission submission = checkFound(submissionStore.getSubmissionByJid(submissionJid)); String source = submissionSourceBuilder.fromPastSubmission(submission.getJid(), true).asString(); return buildLightImageResponseFromText(source, Date.from(submission.getTime())); } - @Override + @GET + @Path("/{submissionJid}/image/dark") + @Produces("image/png") @UnitOfWork(readOnly = true) - public Response getSubmissionSourceDarkImage(String submissionJid) { + public Response getSubmissionSourceDarkImage(@PathParam("submissionJid") String submissionJid) { Submission submission = checkFound(submissionStore.getSubmissionByJid(submissionJid)); String source = submissionSourceBuilder.fromPastSubmission(submission.getJid(), true).asString(); @@ -256,7 +237,6 @@ public Response getSubmissionSourceDarkImage(String submissionJid) { } @POST - @Path("/") @Consumes(MULTIPART_FORM_DATA) @UnitOfWork public void createSubmission(@HeaderParam(AUTHORIZATION) AuthHeader authHeader, FormDataMultiPart parts) { @@ -278,9 +258,13 @@ public void createSubmission(@HeaderParam(AUTHORIZATION) AuthHeader authHeader, submissionSourceBuilder.storeSubmissionSource(submission.getJid(), source); } - @Override + @POST + @Path("/{submissionJid}/regrade") @UnitOfWork - public void regradeSubmission(AuthHeader authHeader, String submissionJid) { + public void regradeSubmission( + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("submissionJid") String submissionJid) { + String actorJid = actorChecker.check(authHeader); Submission submission = checkFound(submissionStore.getSubmissionByJid(submissionJid)); checkAllowed(submissionRoleChecker.canManage(actorJid)); @@ -289,14 +273,15 @@ public void regradeSubmission(AuthHeader authHeader, String submissionJid) { submissionRegrader.regradeSubmission(submission, config); } - @Override + @POST + @Path("/regrade") @UnitOfWork public void regradeSubmissions( - AuthHeader authHeader, - Optional containerJid, - Optional username, - Optional problemJid, - Optional problemAlias) { + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @QueryParam("containerJid") Optional containerJid, + @QueryParam("username") Optional username, + @QueryParam("problemJid") Optional problemJid, + @QueryParam("problemAlias") Optional problemAlias) { String actorJid = actorChecker.check(authHeader); checkAllowed(submissionRoleChecker.canManage(actorJid)); diff --git a/judgels-backends/judgels-server-app/src/main/java/judgels/jophiel/user/UserResource.java b/judgels-backends/judgels-server-app/src/main/java/judgels/jophiel/user/UserResource.java index 041200fd1..24cec3295 100644 --- a/judgels-backends/judgels-server-app/src/main/java/judgels/jophiel/user/UserResource.java +++ b/judgels-backends/judgels-server-app/src/main/java/judgels/jophiel/user/UserResource.java @@ -1,5 +1,8 @@ package judgels.jophiel.user; +import static javax.ws.rs.core.HttpHeaders.AUTHORIZATION; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; +import static javax.ws.rs.core.MediaType.TEXT_PLAIN; import static judgels.service.ServiceUtils.checkAllowed; import static judgels.service.ServiceUtils.checkFound; @@ -17,9 +20,16 @@ import java.util.Set; import java.util.stream.Collectors; import javax.inject.Inject; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; import judgels.jophiel.api.user.User; import judgels.jophiel.api.user.UserData; -import judgels.jophiel.api.user.UserService; import judgels.jophiel.api.user.UsersResponse; import judgels.jophiel.api.user.UsersUpsertResponse; import judgels.jophiel.api.user.info.UserInfo; @@ -32,46 +42,40 @@ import liquibase.util.csv.CSVReader; import liquibase.util.csv.CSVWriter; -public class UserResource implements UserService { +@Path("/api/v2/users") +public class UserResource { private static final int PAGE_SIZE = 250; - private final ActorChecker actorChecker; - private final UserRoleChecker roleChecker; - private final UserStore userStore; - private final UserInfoStore infoStore; - private final SessionStore sessionStore; - - @Inject - public UserResource( - ActorChecker actorChecker, - UserRoleChecker roleChecker, - UserStore userStore, - UserInfoStore infoStore, - SessionStore sessionStore) { - - this.actorChecker = actorChecker; - this.roleChecker = roleChecker; - this.userStore = userStore; - this.infoStore = infoStore; - this.sessionStore = sessionStore; - } + @Inject protected ActorChecker actorChecker; + @Inject protected UserRoleChecker roleChecker; + @Inject protected UserStore userStore; + @Inject protected UserInfoStore infoStore; + @Inject protected SessionStore sessionStore; + + @Inject public UserResource() {} - @Override + @GET + @Path("/{userJid}") + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) - public User getUser(AuthHeader authHeader, String userJid) { + public User getUser( + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("userJid") String userJid) { + String actorJid = actorChecker.check(authHeader); checkAllowed(roleChecker.canManage(actorJid, userJid)); return checkFound(userStore.getUserByJid(userJid)); } - @Override + @GET + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) public UsersResponse getUsers( - AuthHeader authHeader, - Optional pageNumber, - Optional orderBy, - Optional orderDir) { + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @QueryParam("page") Optional pageNumber, + @QueryParam("orderBy") Optional orderBy, + @QueryParam("orderDir") Optional orderDir) { String actorJid = actorChecker.check(authHeader); checkAllowed(roleChecker.canAdminister(actorJid)); @@ -85,18 +89,29 @@ public UsersResponse getUsers( .build(); } - @Override + @POST + @Consumes(APPLICATION_JSON) + @Produces(APPLICATION_JSON) @UnitOfWork - public User createUser(AuthHeader authHeader, UserData data) { + public User createUser( + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + UserData data) { + String actorJid = actorChecker.check(authHeader); checkAllowed(roleChecker.canAdminister(actorJid)); return userStore.createUser(data); } - @Override + @POST + @Path("/batch-get") + @Consumes(APPLICATION_JSON) + @Produces(TEXT_PLAIN) @UnitOfWork(readOnly = true) - public String exportUsers(AuthHeader authHeader, List usernames) { + public String exportUsers( + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + List usernames) { + String actorJid = actorChecker.check(authHeader); checkAllowed(roleChecker.canAdminister(actorJid)); @@ -116,9 +131,15 @@ public String exportUsers(AuthHeader authHeader, List usernames) { return csv.toString(); } - @Override + @POST + @Path("/batch-upsert") + @Consumes(TEXT_PLAIN) + @Produces(APPLICATION_JSON) @UnitOfWork - public UsersUpsertResponse upsertUsers(AuthHeader authHeader, String csv) throws IOException { + public UsersUpsertResponse upsertUsers( + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + String csv) throws IOException { + String actorJid = actorChecker.check(authHeader); checkAllowed(roleChecker.canAdminister(actorJid)); diff --git a/judgels-backends/judgels-server-app/src/main/java/judgels/jophiel/user/account/UserAccountResource.java b/judgels-backends/judgels-server-app/src/main/java/judgels/jophiel/user/account/UserAccountResource.java index ce9ba985f..654feca06 100644 --- a/judgels-backends/judgels-server-app/src/main/java/judgels/jophiel/user/account/UserAccountResource.java +++ b/judgels-backends/judgels-server-app/src/main/java/judgels/jophiel/user/account/UserAccountResource.java @@ -1,57 +1,60 @@ package judgels.jophiel.user.account; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static judgels.service.ServiceUtils.checkFound; import io.dropwizard.hibernate.UnitOfWork; import java.util.Optional; import javax.inject.Inject; +import javax.ws.rs.Consumes; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; import judgels.jophiel.api.user.User; import judgels.jophiel.api.user.account.GoogleUserRegistrationData; import judgels.jophiel.api.user.account.PasswordResetData; -import judgels.jophiel.api.user.account.UserAccountService; import judgels.jophiel.api.user.account.UserRegistrationData; import judgels.jophiel.user.UserStore; -public class UserAccountResource implements UserAccountService { - private final UserStore userStore; - private final Optional userRegisterer; - private final Optional userPasswordResetter; - private final UserRegistrationEmailStore userRegistrationEmailStore; +@Path("/api/v2/user-account") +public class UserAccountResource { + @Inject protected UserStore userStore; + @Inject protected Optional userRegisterer; + @Inject protected Optional userPasswordResetter; + @Inject protected UserRegistrationEmailStore userRegistrationEmailStore; - @Inject - public UserAccountResource( - UserStore userStore, - Optional userRegisterer, - Optional userPasswordResetter, - UserRegistrationEmailStore userRegistrationEmailStore) { + @Inject public UserAccountResource() {} - this.userStore = userStore; - this.userRegisterer = userRegisterer; - this.userPasswordResetter = userPasswordResetter; - this.userRegistrationEmailStore = userRegistrationEmailStore; - } - - @Override + @POST + @Path("/register") + @Consumes(APPLICATION_JSON) + @Produces(APPLICATION_JSON) @UnitOfWork public User registerUser(UserRegistrationData data) { return checkFound(userRegisterer).register(data); } - @Override + @POST + @Path("/register-google") + @Consumes(APPLICATION_JSON) + @Produces(APPLICATION_JSON) @UnitOfWork public User registerGoogleUser(GoogleUserRegistrationData data) { return checkFound(userRegisterer).registerGoogleUser(data); } - @Override + @POST + @Path("/activate/{emailCode}") @UnitOfWork - public void activateUser(String emailCode) { + public void activateUser(@PathParam("emailCode") String emailCode) { checkFound(userRegisterer).activate(emailCode); } - @Override + @POST + @Path("/request-reset-password/{email}") @UnitOfWork - public void requestToResetPassword(String email) { + public void requestToResetPassword(@PathParam("email") String email) { Optional user = userStore .getUserByEmail(email) .filter(u -> userRegistrationEmailStore.isUserActivated(u.getJid())); @@ -61,15 +64,18 @@ public void requestToResetPassword(String email) { } } - @Override + @POST + @Path("/resend-activation-email/{email}") @UnitOfWork - public void resendActivationEmail(String email) { + public void resendActivationEmail(@PathParam("email") String email) { User user = checkFound(userStore.getUserByEmail(email) .filter(u -> !userRegistrationEmailStore.isUserActivated(u.getJid()))); checkFound(userRegisterer).resendActivationEmail(user); } - @Override + @POST + @Path("/reset-password") + @Consumes(APPLICATION_JSON) @UnitOfWork public void resetPassword(PasswordResetData data) { checkFound(userPasswordResetter).reset(data); diff --git a/judgels-backends/judgels-server-app/src/main/java/judgels/jophiel/user/avatar/UserAvatarResource.java b/judgels-backends/judgels-server-app/src/main/java/judgels/jophiel/user/avatar/UserAvatarResource.java index e426cbdc8..1bda0d635 100644 --- a/judgels-backends/judgels-server-app/src/main/java/judgels/jophiel/user/avatar/UserAvatarResource.java +++ b/judgels-backends/judgels-server-app/src/main/java/judgels/jophiel/user/avatar/UserAvatarResource.java @@ -3,6 +3,7 @@ import static javax.ws.rs.core.HttpHeaders.AUTHORIZATION; import static javax.ws.rs.core.HttpHeaders.CONTENT_LENGTH; import static javax.ws.rs.core.HttpHeaders.IF_MODIFIED_SINCE; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static javax.ws.rs.core.MediaType.MULTIPART_FORM_DATA; import static judgels.service.ServiceUtils.checkAllowed; import static judgels.service.ServiceUtils.checkFound; @@ -15,14 +16,16 @@ import java.util.Optional; import javax.inject.Inject; import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.HeaderParam; import javax.ws.rs.POST; +import javax.ws.rs.Path; import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; import javax.ws.rs.core.Response; import judgels.fs.FileSystem; import judgels.jophiel.api.user.User; -import judgels.jophiel.api.user.avatar.UserAvatarService; import judgels.jophiel.user.UserRoleChecker; import judgels.jophiel.user.UserStore; import judgels.service.RandomCodeGenerator; @@ -32,39 +35,34 @@ import org.glassfish.jersey.media.multipart.FormDataContentDisposition; import org.glassfish.jersey.media.multipart.FormDataParam; -public class UserAvatarResource implements UserAvatarService { +@Path("/api/v2/users/{userJid}/avatar") +public class UserAvatarResource { private static final String DEFAULT_AVATAR = "assets/avatar-default.png"; - private final ActorChecker actorChecker; - private final UserRoleChecker roleChecker; - private final UserStore userStore; - private final FileSystem avatarFs; - - @Inject - public UserAvatarResource( - ActorChecker actorChecker, - UserRoleChecker roleChecker, - UserStore userStore, - @UserAvatarFs FileSystem avatarFs) { - - this.actorChecker = actorChecker; - this.roleChecker = roleChecker; - this.avatarFs = avatarFs; - this.userStore = userStore; - } + @Inject protected ActorChecker actorChecker; + @Inject protected UserRoleChecker roleChecker; + @Inject protected UserStore userStore; + @Inject @UserAvatarFs protected FileSystem avatarFs; + + @Inject public UserAvatarResource() {} - @Override + @DELETE @UnitOfWork - public void deleteAvatar(AuthHeader authHeader, String userJid) { + public void deleteAvatar( + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("userJid") String userJid) { + String actorJid = actorChecker.check(authHeader); checkAllowed(roleChecker.canManage(actorJid, userJid)); userStore.updateUserAvatar(userJid, null); } - @Override + @GET + @Path("/exists") + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) - public boolean avatarExists(String userJid) { + public boolean avatarExists(@PathParam("userJid") String userJid) { return userStore.getUserAvatarFilename(userJid).isPresent(); } diff --git a/judgels-backends/judgels-server-app/src/main/java/judgels/jophiel/user/info/UserInfoResource.java b/judgels-backends/judgels-server-app/src/main/java/judgels/jophiel/user/info/UserInfoResource.java index e8ec85a3e..4b88cdb86 100644 --- a/judgels-backends/judgels-server-app/src/main/java/judgels/jophiel/user/info/UserInfoResource.java +++ b/judgels-backends/judgels-server-app/src/main/java/judgels/jophiel/user/info/UserInfoResource.java @@ -1,40 +1,42 @@ package judgels.jophiel.user.info; +import static javax.ws.rs.core.HttpHeaders.AUTHORIZATION; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static judgels.service.ServiceUtils.checkAllowed; import static judgels.service.ServiceUtils.checkFound; import io.dropwizard.hibernate.UnitOfWork; import javax.inject.Inject; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; import judgels.jophiel.api.user.User; import judgels.jophiel.api.user.info.UserInfo; -import judgels.jophiel.api.user.info.UserInfoService; import judgels.jophiel.user.UserRoleChecker; import judgels.jophiel.user.UserStore; import judgels.service.actor.ActorChecker; import judgels.service.api.actor.AuthHeader; -public class UserInfoResource implements UserInfoService { - private final ActorChecker actorChecker; - private final UserRoleChecker roleChecker; - private final UserStore userStore; - private final UserInfoStore infoStore; - - @Inject - public UserInfoResource( - ActorChecker actorChecker, - UserRoleChecker roleChecker, - UserStore userStore, - UserInfoStore infoStore) { - - this.actorChecker = actorChecker; - this.roleChecker = roleChecker; - this.userStore = userStore; - this.infoStore = infoStore; - } +@Path("/api/v2/users/{userJid}/info") +public class UserInfoResource { + @Inject protected ActorChecker actorChecker; + @Inject protected UserRoleChecker roleChecker; + @Inject protected UserStore userStore; + @Inject protected UserInfoStore infoStore; + + @Inject public UserInfoResource() {} - @Override + @GET + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) - public UserInfo getInfo(AuthHeader authHeader, String userJid) { + public UserInfo getInfo( + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("userJid") String userJid) { + String actorJid = actorChecker.check(authHeader); checkAllowed(roleChecker.canManage(actorJid, userJid)); @@ -42,9 +44,15 @@ public UserInfo getInfo(AuthHeader authHeader, String userJid) { return infoStore.getInfo(user.getJid()); } - @Override + @PUT + @Consumes(APPLICATION_JSON) + @Produces(APPLICATION_JSON) @UnitOfWork - public UserInfo updateInfo(AuthHeader authHeader, String userJid, UserInfo userInfo) { + public UserInfo updateInfo( + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("userJid") String userJid, + UserInfo userInfo) { + String actorJid = actorChecker.check(authHeader); checkAllowed(roleChecker.canManage(actorJid, userJid)); diff --git a/judgels-backends/judgels-server-app/src/main/java/judgels/jophiel/user/me/MyUserResource.java b/judgels-backends/judgels-server-app/src/main/java/judgels/jophiel/user/me/MyUserResource.java index 67503906d..28e6beaed 100644 --- a/judgels-backends/judgels-server-app/src/main/java/judgels/jophiel/user/me/MyUserResource.java +++ b/judgels-backends/judgels-server-app/src/main/java/judgels/jophiel/user/me/MyUserResource.java @@ -1,49 +1,60 @@ package judgels.jophiel.user.me; +import static javax.ws.rs.core.HttpHeaders.AUTHORIZATION; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static judgels.service.ServiceUtils.checkFound; import io.dropwizard.hibernate.UnitOfWork; import javax.inject.Inject; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; import judgels.jophiel.api.role.UserRole; import judgels.jophiel.api.user.User; -import judgels.jophiel.api.user.me.MyUserService; import judgels.jophiel.api.user.me.PasswordUpdateData; import judgels.jophiel.role.UserRoleStore; import judgels.jophiel.user.UserStore; import judgels.service.actor.ActorChecker; import judgels.service.api.actor.AuthHeader; -public class MyUserResource implements MyUserService { - private final ActorChecker actorChecker; - private final UserRoleStore roleStore; - private final UserStore userStore; +@Path("/api/v2/users/me") +public class MyUserResource { + @Inject protected ActorChecker actorChecker; + @Inject protected UserRoleStore roleStore; + @Inject protected UserStore userStore; - @Inject - public MyUserResource(ActorChecker actorChecker, UserRoleStore roleStore, UserStore userStore) { - this.actorChecker = actorChecker; - this.roleStore = roleStore; - this.userStore = userStore; - } + @Inject public MyUserResource() {} - @Override + @GET + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) - public User getMyself(AuthHeader authHeader) { + public User getMyself(@HeaderParam(AUTHORIZATION) AuthHeader authHeader) { String actorJid = actorChecker.check(authHeader); return checkFound(userStore.getUserByJid(actorJid)); } - @Override + @POST + @Path("/password") + @Consumes(APPLICATION_JSON) @UnitOfWork - public void updateMyPassword(AuthHeader authHeader, PasswordUpdateData data) { + public void updateMyPassword( + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + PasswordUpdateData data) { + String actorJid = actorChecker.check(authHeader); userStore.validateUserPassword(actorJid, data.getOldPassword()); userStore.updateUserPassword(actorJid, data.getNewPassword()); } - @Override + @GET + @Path("/role") + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) - public UserRole getMyRole(AuthHeader authHeader) { + public UserRole getMyRole(@HeaderParam(AUTHORIZATION) AuthHeader authHeader) { String actorJid = actorChecker.check(authHeader); return roleStore.getRole(actorJid); } diff --git a/judgels-backends/judgels-server-app/src/main/java/judgels/jophiel/user/rating/UserRatingResource.java b/judgels-backends/judgels-server-app/src/main/java/judgels/jophiel/user/rating/UserRatingResource.java index b3496fac7..2815b803a 100644 --- a/judgels-backends/judgels-server-app/src/main/java/judgels/jophiel/user/rating/UserRatingResource.java +++ b/judgels-backends/judgels-server-app/src/main/java/judgels/jophiel/user/rating/UserRatingResource.java @@ -1,53 +1,59 @@ package judgels.jophiel.user.rating; +import static javax.ws.rs.core.HttpHeaders.AUTHORIZATION; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static judgels.service.ServiceUtils.checkAllowed; import io.dropwizard.hibernate.UnitOfWork; import java.util.List; import java.util.Optional; import javax.inject.Inject; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; import judgels.jophiel.api.user.rating.RatingEvent; import judgels.jophiel.api.user.rating.UserRatingEvent; -import judgels.jophiel.api.user.rating.UserRatingService; import judgels.jophiel.api.user.rating.UserRatingUpdateData; import judgels.jophiel.user.UserRoleChecker; import judgels.service.actor.ActorChecker; import judgels.service.api.actor.AuthHeader; -public class UserRatingResource implements UserRatingService { - private final ActorChecker actorChecker; - private final UserRoleChecker roleChecker; - private final UserRatingStore ratingStore; +@Path("/api/v2/user-rating") +public class UserRatingResource { + @Inject protected ActorChecker actorChecker; + @Inject protected UserRoleChecker roleChecker; + @Inject protected UserRatingStore ratingStore; - @Inject - public UserRatingResource( - ActorChecker actorChecker, - UserRoleChecker roleChecker, - UserRatingStore ratingStore) { + @Inject public UserRatingResource() {} - this.actorChecker = actorChecker; - this.roleChecker = roleChecker; - this.ratingStore = ratingStore; - } - - @Override + @POST + @Consumes(APPLICATION_JSON) @UnitOfWork - public void updateRatings(AuthHeader authHeader, UserRatingUpdateData data) { + public void updateRatings(@HeaderParam(AUTHORIZATION) AuthHeader authHeader, UserRatingUpdateData data) { String actorJid = actorChecker.check(authHeader); checkAllowed(roleChecker.canAdminister(actorJid)); ratingStore.updateRatings(data.getTime(), data.getEventJid(), data.getRatingsMap()); } - @Override + @GET + @Path("/events/latest") + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) public Optional getLatestRatingEvent() { return ratingStore.getLatestRatingEvent(); } - @Override + @GET + @Path("/history") + @Consumes(APPLICATION_JSON) + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) - public List getRatingHistory(String userJid) { + public List getRatingHistory(@QueryParam("userJid") String userJid) { return ratingStore.getUserRatingEvents(userJid); } } diff --git a/judgels-backends/judgels-server-app/src/main/java/judgels/jophiel/user/registration/web/UserRegistrationWebResource.java b/judgels-backends/judgels-server-app/src/main/java/judgels/jophiel/user/registration/web/UserRegistrationWebResource.java index 740dd8327..2c59d0f93 100644 --- a/judgels-backends/judgels-server-app/src/main/java/judgels/jophiel/user/registration/web/UserRegistrationWebResource.java +++ b/judgels-backends/judgels-server-app/src/main/java/judgels/jophiel/user/registration/web/UserRegistrationWebResource.java @@ -9,12 +9,9 @@ @Path("/api/v2/users/registration/web") public class UserRegistrationWebResource { - private final UserRegistrationWebConfig config; + @Inject protected UserRegistrationWebConfig config; - @Inject - public UserRegistrationWebResource(UserRegistrationWebConfig config) { - this.config = config; - } + @Inject public UserRegistrationWebResource() {} @GET @Path("/config") diff --git a/judgels-backends/judgels-server-app/src/main/java/judgels/jophiel/user/search/UserSearchResource.java b/judgels-backends/judgels-server-app/src/main/java/judgels/jophiel/user/search/UserSearchResource.java index 443d37685..73e75c04d 100644 --- a/judgels-backends/judgels-server-app/src/main/java/judgels/jophiel/user/search/UserSearchResource.java +++ b/judgels-backends/judgels-server-app/src/main/java/judgels/jophiel/user/search/UserSearchResource.java @@ -1,33 +1,45 @@ package judgels.jophiel.user.search; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; + import io.dropwizard.hibernate.UnitOfWork; import java.util.Map; import java.util.Set; import javax.inject.Inject; -import judgels.jophiel.api.user.search.UserSearchService; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; import judgels.jophiel.user.UserStore; -public class UserSearchResource implements UserSearchService { - private final UserStore userStore; +@Path("/api/v2/user-search") +public class UserSearchResource { + @Inject protected UserStore userStore; - @Inject - public UserSearchResource(UserStore userStore) { - this.userStore = userStore; - } + @Inject public UserSearchResource() {} - @Override + @GET + @Path("/username-exists/{username}") + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) - public boolean usernameExists(String username) { + public boolean usernameExists(@PathParam("username") String username) { return userStore.getUserByUsername(username).isPresent(); } - @Override + @GET + @Path("/email-exists/{email}") + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) - public boolean emailExists(String email) { + public boolean emailExists(@PathParam("email") String email) { return userStore.getUserByEmail(email).isPresent(); } - @Override + @POST + @Path("/username-to-jid") + @Consumes(APPLICATION_JSON) + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) public Map translateUsernamesToJids(Set usernames) { return userStore.translateUsernamesToJids(usernames); diff --git a/judgels-backends/judgels-server-app/src/main/java/judgels/jophiel/user/web/UserWebResource.java b/judgels-backends/judgels-server-app/src/main/java/judgels/jophiel/user/web/UserWebResource.java index 431b7b324..808b1ab1c 100644 --- a/judgels-backends/judgels-server-app/src/main/java/judgels/jophiel/user/web/UserWebResource.java +++ b/judgels-backends/judgels-server-app/src/main/java/judgels/jophiel/user/web/UserWebResource.java @@ -1,38 +1,37 @@ package judgels.jophiel.user.web; +import static javax.ws.rs.core.HttpHeaders.AUTHORIZATION; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; + import io.dropwizard.hibernate.UnitOfWork; import java.util.Optional; import javax.inject.Inject; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; import judgels.jophiel.api.role.JophielRole; import judgels.jophiel.api.role.UserRole; import judgels.jophiel.api.user.web.UserWebConfig; -import judgels.jophiel.api.user.web.UserWebService; import judgels.jophiel.profile.ProfileResource; import judgels.jophiel.user.me.MyUserResource; import judgels.service.actor.ActorChecker; import judgels.service.api.actor.AuthHeader; -public class UserWebResource implements UserWebService { - private final ActorChecker actorChecker; - private final MyUserResource myResource; - private final ProfileResource profileResource; - private final WebConfiguration webConfig; +@Path("/api/v2/user-web") +public class UserWebResource { + @Inject protected ActorChecker actorChecker; + @Inject protected MyUserResource myResource; + @Inject protected ProfileResource profileResource; + @Inject protected WebConfiguration webConfig; - @Inject - public UserWebResource( - ActorChecker actorChecker, - MyUserResource myResource, - ProfileResource profileResource, - WebConfiguration webConfig) { - this.actorChecker = actorChecker; - this.myResource = myResource; - this.profileResource = profileResource; - this.webConfig = webConfig; - } + @Inject public UserWebResource() {} - @Override + @GET + @Path("/config") + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) - public UserWebConfig getWebConfig(Optional authHeader) { + public UserWebConfig getWebConfig(@HeaderParam(AUTHORIZATION) Optional authHeader) { UserWebConfig.Builder config = new UserWebConfig.Builder() .announcements(webConfig.getAnnouncements()); diff --git a/judgels-backends/judgels-server-app/src/main/java/judgels/michael/problem/editorial/ProblemEditorialResource.java b/judgels-backends/judgels-server-app/src/main/java/judgels/michael/problem/editorial/ProblemEditorialResource.java index 5848cc9b1..c3aee67fe 100644 --- a/judgels-backends/judgels-server-app/src/main/java/judgels/michael/problem/editorial/ProblemEditorialResource.java +++ b/judgels-backends/judgels-server-app/src/main/java/judgels/michael/problem/editorial/ProblemEditorialResource.java @@ -42,7 +42,6 @@ public class ProblemEditorialResource extends BaseProblemResource { @Inject public ProblemEditorialResource() {} @GET - @Path("") @UnitOfWork(readOnly = true) public View viewEditorial(@Context HttpServletRequest req, @PathParam("problemId") int problemId) { Actor actor = actorChecker.check(req); @@ -67,7 +66,6 @@ public View viewEditorial(@Context HttpServletRequest req, @PathParam("problemId } @POST - @Path("") @UnitOfWork public Response createEditorial( @Context HttpServletRequest req, diff --git a/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/ContestResource.java b/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/ContestResource.java index f63f0c966..b4f96e46b 100644 --- a/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/ContestResource.java +++ b/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/ContestResource.java @@ -1,5 +1,7 @@ package judgels.uriel.contest; +import static javax.ws.rs.core.HttpHeaders.AUTHORIZATION; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static judgels.service.ServiceUtils.checkAllowed; import static judgels.service.ServiceUtils.checkFound; @@ -9,6 +11,15 @@ import java.util.Optional; import java.util.stream.Collectors; import javax.inject.Inject; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; import judgels.jophiel.profile.ProfileStore; import judgels.persistence.api.Page; import judgels.service.actor.ActorChecker; @@ -18,7 +29,6 @@ import judgels.uriel.api.contest.ContestConfig; import judgels.uriel.api.contest.ContestCreateData; import judgels.uriel.api.contest.ContestDescription; -import judgels.uriel.api.contest.ContestService; import judgels.uriel.api.contest.ContestUpdateData; import judgels.uriel.api.contest.ContestsResponse; import judgels.uriel.api.contest.module.IcpcStyleModuleConfig; @@ -27,39 +37,28 @@ import judgels.uriel.contest.log.ContestLogger; import judgels.uriel.contest.module.ContestModuleStore; -public class ContestResource implements ContestService { +@Path("/api/v2/contests") +public class ContestResource { private static final int PAGE_SIZE = 20; - private final ActorChecker actorChecker; - private final ContestRoleChecker contestRoleChecker; - private final ContestStore contestStore; - private final ContestLogger contestLogger; - private final ContestModuleStore moduleStore; - private final ContestContestantStore contestantStore; - private final ProfileStore profileStore; - - @Inject - public ContestResource( - ActorChecker actorChecker, - ContestRoleChecker contestRoleChecker, - ContestStore contestStore, - ContestLogger contestLogger, - ContestModuleStore moduleStore, - ContestContestantStore contestantStore, - ProfileStore profileStore) { - - this.actorChecker = actorChecker; - this.contestRoleChecker = contestRoleChecker; - this.contestStore = contestStore; - this.contestLogger = contestLogger; - this.moduleStore = moduleStore; - this.contestantStore = contestantStore; - this.profileStore = profileStore; - } + @Inject protected ActorChecker actorChecker; + @Inject protected ContestRoleChecker contestRoleChecker; + @Inject protected ContestStore contestStore; + @Inject protected ContestLogger contestLogger; + @Inject protected ContestModuleStore moduleStore; + @Inject protected ContestContestantStore contestantStore; + @Inject protected ProfileStore profileStore; + + @Inject public ContestResource() {} - @Override + @GET + @Path("/{contestJid}") + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) - public Contest getContest(Optional authHeader, String contestJid) { + public Contest getContest( + @HeaderParam(AUTHORIZATION) Optional authHeader, + @PathParam("contestJid") String contestJid) { + String actorJid = actorChecker.check(authHeader); Contest contest = checkFound(contestStore.getContestByJid(contestJid)); @@ -67,9 +66,16 @@ public Contest getContest(Optional authHeader, String contestJid) { return contest; } - @Override + @POST + @Path("/{contestJid}") + @Consumes(APPLICATION_JSON) + @Produces(APPLICATION_JSON) @UnitOfWork - public Contest updateContest(AuthHeader authHeader, String contestJid, ContestUpdateData data) { + public Contest updateContest( + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("contestJid") String contestJid, + ContestUpdateData data) { + String actorJid = actorChecker.check(authHeader); Contest contest = checkFound(contestStore.getContestByJid(contestJid)); @@ -81,9 +87,14 @@ public Contest updateContest(AuthHeader authHeader, String contestJid, ContestUp return contest; } - @Override + @GET + @Path("/slug/{contestSlug}") + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) - public Contest getContestBySlug(Optional authHeader, String contestSlug) { + public Contest getContestBySlug( + @HeaderParam(AUTHORIZATION) Optional authHeader, + @PathParam("contestSlug") String contestSlug) { + String actorJid = actorChecker.check(authHeader); Contest contest = checkFound(contestStore.getContestBySlug(contestSlug)); @@ -91,9 +102,13 @@ public Contest getContestBySlug(Optional authHeader, String contestS return contest; } - @Override + @POST + @Path("/{contestJid}/virtual") @UnitOfWork - public void startVirtualContest(AuthHeader authHeader, String contestJid) { + public void startVirtualContest( + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("contestJid") String contestJid) { + String actorJid = actorChecker.check(authHeader); Contest contest = checkFound(contestStore.getContestByJid(contestJid)); checkAllowed(contestRoleChecker.canStartVirtual(actorJid, contest)); @@ -103,9 +118,13 @@ public void startVirtualContest(AuthHeader authHeader, String contestJid) { contestLogger.log(contestJid, "START_VIRTUAL_CONTEST"); } - @Override + @PUT + @Path("/{contestJid}/virtual/reset") @UnitOfWork - public void resetVirtualContest(AuthHeader authHeader, String contestJid) { + public void resetVirtualContest( + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("contestJid") String contestJid) { + String actorJid = actorChecker.check(authHeader); Contest contest = checkFound(contestStore.getContestByJid(contestJid)); checkAllowed(contestRoleChecker.canResetVirtual(actorJid, contest)); @@ -115,18 +134,19 @@ public void resetVirtualContest(AuthHeader authHeader, String contestJid) { contestLogger.log(contestJid, "RESET_VIRTUAL_CONTEST"); } - @Override + @GET + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) public ContestsResponse getContests( - Optional authHeader, - Optional nameFilter, - Optional pageNumber) { + @HeaderParam(AUTHORIZATION) Optional authHeader, + @QueryParam("name") Optional name, + @QueryParam("page") Optional pageNumber) { String actorJid = actorChecker.check(authHeader); boolean isAdmin = contestRoleChecker.canAdminister(actorJid); Optional userJid = isAdmin ? Optional.empty() : Optional.of(actorJid); - Page contests = contestStore.getContests(userJid, nameFilter, pageNumber.orElse(1), PAGE_SIZE); + Page contests = contestStore.getContests(userJid, name, pageNumber.orElse(1), PAGE_SIZE); Map rolesMap = contests.getPage() .stream() @@ -146,9 +166,13 @@ public ContestsResponse getContests( .build(); } - @Override + @GET + @Path("/active") + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) - public ActiveContestsResponse getActiveContests(Optional authHeader) { + public ActiveContestsResponse getActiveContests( + @HeaderParam(AUTHORIZATION) Optional authHeader) { + String actorJid = actorChecker.check(authHeader); boolean isAdmin = contestRoleChecker.canAdminister(actorJid); @@ -167,9 +191,14 @@ public ActiveContestsResponse getActiveContests(Optional authHeader) .build(); } - @Override + @POST + @Consumes(APPLICATION_JSON) + @Produces(APPLICATION_JSON) @UnitOfWork - public Contest createContest(AuthHeader authHeader, ContestCreateData data) { + public Contest createContest( + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + ContestCreateData data) { + String actorJid = actorChecker.check(authHeader); checkAllowed(contestRoleChecker.canAdminister(actorJid)); @@ -181,9 +210,14 @@ public Contest createContest(AuthHeader authHeader, ContestCreateData data) { return contest; } - @Override + @GET + @Path("/{contestJid}/description") + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) - public ContestDescription getContestDescription(Optional authHeader, String contestJid) { + public ContestDescription getContestDescription( + @HeaderParam(AUTHORIZATION) Optional authHeader, + @PathParam("contestJid") String contestJid) { + String actorJid = actorChecker.check(authHeader); Contest contest = checkFound(contestStore.getContestByJid(contestJid)); checkAllowed(contestRoleChecker.canView(actorJid, contest)); @@ -197,11 +231,14 @@ public ContestDescription getContestDescription(Optional authHeader, .build(); } - @Override + @POST + @Path("/{contestJid}/description") + @Consumes(APPLICATION_JSON) + @Produces(APPLICATION_JSON) @UnitOfWork public ContestDescription updateContestDescription( - AuthHeader authHeader, - String contestJid, + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("contestJid") String contestJid, ContestDescription description) { String actorJid = actorChecker.check(authHeader); diff --git a/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/announcement/ContestAnnouncementResource.java b/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/announcement/ContestAnnouncementResource.java index c54954daf..b9e646cf0 100644 --- a/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/announcement/ContestAnnouncementResource.java +++ b/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/announcement/ContestAnnouncementResource.java @@ -1,5 +1,7 @@ package judgels.uriel.contest.announcement; +import static javax.ws.rs.core.HttpHeaders.AUTHORIZATION; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static judgels.service.ServiceUtils.checkAllowed; import static judgels.service.ServiceUtils.checkFound; import static judgels.uriel.api.contest.announcement.ContestAnnouncementStatus.PUBLISHED; @@ -10,6 +12,15 @@ import java.util.Set; import java.util.stream.Collectors; import javax.inject.Inject; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; import judgels.jophiel.api.profile.Profile; import judgels.jophiel.user.UserClient; import judgels.persistence.api.Page; @@ -19,44 +30,30 @@ import judgels.uriel.api.contest.announcement.ContestAnnouncement; import judgels.uriel.api.contest.announcement.ContestAnnouncementConfig; import judgels.uriel.api.contest.announcement.ContestAnnouncementData; -import judgels.uriel.api.contest.announcement.ContestAnnouncementService; import judgels.uriel.api.contest.announcement.ContestAnnouncementsResponse; import judgels.uriel.contest.ContestStore; import judgels.uriel.contest.log.ContestLogger; -public class ContestAnnouncementResource implements ContestAnnouncementService { +@Path("/api/v2/contests/{contestJid}/announcements") +public class ContestAnnouncementResource { private static final int PAGE_SIZE = 20; - private final ActorChecker actorChecker; - private final ContestStore contestStore; - private final ContestLogger contestLogger; - private final ContestAnnouncementRoleChecker announcementRoleChecker; - private final ContestAnnouncementStore announcementStore; - private final UserClient userClient; - - @Inject - public ContestAnnouncementResource( - ActorChecker actorChecker, - ContestStore contestStore, - ContestLogger contestLogger, - ContestAnnouncementRoleChecker announcementRoleChecker, - ContestAnnouncementStore announcementStore, - UserClient userClient) { - - this.actorChecker = actorChecker; - this.announcementRoleChecker = announcementRoleChecker; - this.contestStore = contestStore; - this.announcementStore = announcementStore; - this.contestLogger = contestLogger; - this.userClient = userClient; - } + @Inject protected ActorChecker actorChecker; + @Inject protected ContestStore contestStore; + @Inject protected ContestLogger contestLogger; + @Inject protected ContestAnnouncementRoleChecker announcementRoleChecker; + @Inject protected ContestAnnouncementStore announcementStore; + @Inject protected UserClient userClient; + + @Inject public ContestAnnouncementResource() {} - @Override + @GET + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) public ContestAnnouncementsResponse getAnnouncements( - Optional authHeader, - String contestJid, - Optional pageNumber) { + @HeaderParam(AUTHORIZATION) Optional authHeader, + @PathParam("contestJid") String contestJid, + @QueryParam("page") Optional pageNumber) { String actorJid = actorChecker.check(authHeader); Contest contest = checkFound(contestStore.getContestByJid(contestJid)); @@ -87,12 +84,15 @@ public ContestAnnouncementsResponse getAnnouncements( .build(); } - @Override + @POST + @Produces(APPLICATION_JSON) + @Consumes(APPLICATION_JSON) @UnitOfWork public ContestAnnouncement createAnnouncement( - AuthHeader authHeader, - String contestJid, + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("contestJid") String contestJid, ContestAnnouncementData data) { + String actorJid = actorChecker.check(authHeader); Contest contest = checkFound(contestStore.getContestByJid(contestJid)); checkAllowed(announcementRoleChecker.canManage(actorJid, contest)); @@ -103,13 +103,17 @@ public ContestAnnouncement createAnnouncement( return announcement; } - @Override + @PUT + @Path("/{announcementJid}") + @Produces(APPLICATION_JSON) + @Consumes(APPLICATION_JSON) @UnitOfWork public ContestAnnouncement updateAnnouncement( - AuthHeader authHeader, - String contestJid, - String announcementJid, + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("contestJid") String contestJid, + @PathParam("announcementJid") String announcementJid, ContestAnnouncementData data) { + String actorJid = actorChecker.check(authHeader); Contest contest = checkFound(contestStore.getContestByJid(contestJid)); checkAllowed(announcementRoleChecker.canManage(actorJid, contest)); diff --git a/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/clarification/ContestClarificationResource.java b/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/clarification/ContestClarificationResource.java index f1b60c64e..8b2e7e14c 100644 --- a/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/clarification/ContestClarificationResource.java +++ b/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/clarification/ContestClarificationResource.java @@ -1,5 +1,7 @@ package judgels.uriel.contest.clarification; +import static javax.ws.rs.core.HttpHeaders.AUTHORIZATION; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static judgels.service.ServiceUtils.checkAllowed; import static judgels.service.ServiceUtils.checkFound; @@ -13,6 +15,15 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import javax.inject.Inject; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; import judgels.jophiel.api.profile.Profile; import judgels.jophiel.user.UserClient; import judgels.persistence.api.Page; @@ -24,50 +35,33 @@ import judgels.uriel.api.contest.clarification.ContestClarificationAnswerData; import judgels.uriel.api.contest.clarification.ContestClarificationConfig; import judgels.uriel.api.contest.clarification.ContestClarificationData; -import judgels.uriel.api.contest.clarification.ContestClarificationService; import judgels.uriel.api.contest.clarification.ContestClarificationsResponse; import judgels.uriel.contest.ContestStore; import judgels.uriel.contest.log.ContestLogger; import judgels.uriel.contest.problem.ContestProblemStore; -public class ContestClarificationResource implements ContestClarificationService { +@Path("/api/v2/contests/{contestJid}/clarifications") +public class ContestClarificationResource { private static final int PAGE_SIZE = 20; - private final ActorChecker actorChecker; - private final ContestStore contestStore; - private final ContestLogger contestLogger; - private final ContestClarificationRoleChecker clarificationRoleChecker; - private final ContestClarificationStore clarificationStore; - private final ContestProblemStore problemStore; - private final UserClient userClient; - private final ProblemClient problemClient; - - @Inject - public ContestClarificationResource( - ActorChecker actorChecker, - ContestStore contestStore, - ContestLogger contestLogger, - ContestClarificationRoleChecker clarificationRoleChecker, - ContestClarificationStore clarificationStore, - ContestProblemStore problemStore, - UserClient userClient, - ProblemClient problemClient) { - - this.actorChecker = actorChecker; - this.contestStore = contestStore; - this.contestLogger = contestLogger; - this.clarificationRoleChecker = clarificationRoleChecker; - this.clarificationStore = clarificationStore; - this.problemStore = problemStore; - this.userClient = userClient; - this.problemClient = problemClient; - } + @Inject protected ActorChecker actorChecker; + @Inject protected ContestStore contestStore; + @Inject protected ContestLogger contestLogger; + @Inject protected ContestClarificationRoleChecker clarificationRoleChecker; + @Inject protected ContestClarificationStore clarificationStore; + @Inject protected ContestProblemStore problemStore; + @Inject protected UserClient userClient; + @Inject protected ProblemClient problemClient; + + @Inject public ContestClarificationResource() {} - @Override + @POST + @Consumes(APPLICATION_JSON) + @Produces(APPLICATION_JSON) @UnitOfWork public ContestClarification createClarification( - AuthHeader authHeader, - String contestJid, + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("contestJid") String contestJid, ContestClarificationData data) { String actorJid = actorChecker.check(authHeader); @@ -80,14 +74,15 @@ public ContestClarification createClarification( return clarification; } - @Override + @GET + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) public ContestClarificationsResponse getClarifications( - AuthHeader authHeader, - String contestJid, - Optional status, - Optional language, - Optional pageNumber) { + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("contestJid") String contestJid, + @QueryParam("status") Optional status, + @QueryParam("language") Optional language, + @QueryParam("page") Optional pageNumber) { String actorJid = actorChecker.check(authHeader); Contest contest = checkFound(contestStore.getContestByJid(contestJid)); @@ -153,12 +148,15 @@ public ContestClarificationsResponse getClarifications( .build(); } - @Override + @PUT + @Path("/{clarificationJid}/answer") + @Consumes(APPLICATION_JSON) + @Produces(APPLICATION_JSON) @UnitOfWork public ContestClarification answerClarification( - AuthHeader authHeader, - String contestJid, - String clarificationJid, + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("contestJid") String contestJid, + @PathParam("clarificationJid") String clarificationJid, ContestClarificationAnswerData data) { String actorJid = actorChecker.check(authHeader); diff --git a/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/contestant/ContestContestantResource.java b/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/contestant/ContestContestantResource.java index d49179040..d868378f8 100644 --- a/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/contestant/ContestContestantResource.java +++ b/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/contestant/ContestContestantResource.java @@ -1,6 +1,8 @@ package judgels.uriel.contest.contestant; import static com.google.common.base.Preconditions.checkArgument; +import static javax.ws.rs.core.HttpHeaders.AUTHORIZATION; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static judgels.service.ServiceUtils.checkAllowed; import static judgels.service.ServiceUtils.checkFound; @@ -12,6 +14,15 @@ import java.util.Set; import java.util.stream.Collectors; import javax.inject.Inject; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; import judgels.jophiel.api.profile.Profile; import judgels.jophiel.user.UserClient; import judgels.persistence.api.Page; @@ -21,7 +32,6 @@ import judgels.uriel.api.contest.contestant.ApprovedContestContestantsResponse; import judgels.uriel.api.contest.contestant.ContestContestant; import judgels.uriel.api.contest.contestant.ContestContestantConfig; -import judgels.uriel.api.contest.contestant.ContestContestantService; import judgels.uriel.api.contest.contestant.ContestContestantState; import judgels.uriel.api.contest.contestant.ContestContestantsDeleteResponse; import judgels.uriel.api.contest.contestant.ContestContestantsResponse; @@ -31,39 +41,28 @@ import judgels.uriel.contest.log.ContestLogger; import judgels.uriel.contest.module.ContestModuleStore; -public class ContestContestantResource implements ContestContestantService { +@Path("/api/v2/contests/{contestJid}/contestants") +public class ContestContestantResource { private static final int PAGE_SIZE = 1000; - private final ActorChecker actorChecker; - private final ContestStore contestStore; - private final ContestLogger contestLogger; - private final ContestContestantRoleChecker contestantRoleChecker; - private final ContestContestantStore contestantStore; - private final ContestModuleStore moduleStore; - private final UserClient userClient; - - @Inject - public ContestContestantResource( - ActorChecker actorChecker, - ContestStore contestStore, - ContestLogger contestLogger, - ContestContestantRoleChecker contestantRoleChecker, - ContestContestantStore contestantStore, - ContestModuleStore moduleStore, - UserClient userClient) { - - this.actorChecker = actorChecker; - this.contestStore = contestStore; - this.contestLogger = contestLogger; - this.contestantRoleChecker = contestantRoleChecker; - this.contestantStore = contestantStore; - this.moduleStore = moduleStore; - this.userClient = userClient; - } + @Inject protected ActorChecker actorChecker; + @Inject protected ContestStore contestStore; + @Inject protected ContestLogger contestLogger; + @Inject protected ContestContestantRoleChecker contestantRoleChecker; + @Inject protected ContestContestantStore contestantStore; + @Inject protected ContestModuleStore moduleStore; + @Inject protected UserClient userClient; + + @Inject public ContestContestantResource() {} - @Override + @GET + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) - public ContestContestantsResponse getContestants(AuthHeader authHeader, String contestJid, Optional pageNumber) { + public ContestContestantsResponse getContestants( + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("contestJid") String contestJid, + @QueryParam("page") Optional pageNumber) { + String actorJid = actorChecker.check(authHeader); Contest contest = checkFound(contestStore.getContestByJid(contestJid)); checkAllowed(contestantRoleChecker.canSupervise(actorJid, contest)); @@ -89,9 +88,14 @@ public ContestContestantsResponse getContestants(AuthHeader authHeader, String c .build(); } - @Override + @GET + @Path("/approved") + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) - public ApprovedContestContestantsResponse getApprovedContestants(AuthHeader authHeader, String contestJid) { + public ApprovedContestContestantsResponse getApprovedContestants( + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("contestJid") String contestJid) { + String actorJid = actorChecker.check(authHeader); Contest contest = checkFound(contestStore.getContestByJid(contestJid)); checkAllowed(contestantRoleChecker.canViewApproved(actorJid, contest)); @@ -105,9 +109,14 @@ public ApprovedContestContestantsResponse getApprovedContestants(AuthHeader auth .build(); } - @Override + @GET + @Path("/approved/count") + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) - public long getApprovedContestantsCount(AuthHeader authHeader, String contestJid) { + public long getApprovedContestantsCount( + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("contestJid") String contestJid) { + String actorJid = actorChecker.check(authHeader); Contest contest = checkFound(contestStore.getContestByJid(contestJid)); checkAllowed(contestantRoleChecker.canViewApproved(actorJid, contest)); @@ -115,9 +124,13 @@ public long getApprovedContestantsCount(AuthHeader authHeader, String contestJid return contestantStore.getApprovedContestantsCount(contestJid); } - @Override + @POST + @Path("/me") @UnitOfWork - public void registerMyselfAsContestant(AuthHeader authHeader, String contestJid) { + public void registerMyselfAsContestant( + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("contestJid") String contestJid) { + String actorJid = actorChecker.check(authHeader); Contest contest = checkFound(contestStore.getContestByJid(contestJid)); Profile profile = userClient.getProfile(actorJid); @@ -128,9 +141,13 @@ public void registerMyselfAsContestant(AuthHeader authHeader, String contestJid) contestantStore.upsertContestant(contestJid, actorJid); } - @Override + @DELETE + @Path("/me") @UnitOfWork - public void unregisterMyselfAsContestant(AuthHeader authHeader, String contestJid) { + public void unregisterMyselfAsContestant( + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("contestJid") String contestJid) { + String actorJid = actorChecker.check(authHeader); Contest contest = checkFound(contestStore.getContestByJid(contestJid)); checkAllowed(contestantRoleChecker.canUnregister(actorJid, contest)); @@ -140,9 +157,14 @@ public void unregisterMyselfAsContestant(AuthHeader authHeader, String contestJi contestantStore.deleteContestant(contestJid, actorJid); } - @Override + @GET + @Path("/me/state") + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) - public ContestContestantState getMyContestantState(AuthHeader authHeader, String contestJid) { + public ContestContestantState getMyContestantState( + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("contestJid") String contestJid) { + String actorJid = actorChecker.check(authHeader); Contest contest = checkFound(contestStore.getContestByJid(contestJid)); Profile profile = userClient.getProfile(actorJid); @@ -150,11 +172,14 @@ public ContestContestantState getMyContestantState(AuthHeader authHeader, String return contestantRoleChecker.getContestantState(actorJid, profile.getRating(), contest); } - @Override + @POST + @Path("/batch-upsert") + @Consumes(APPLICATION_JSON) + @Produces(APPLICATION_JSON) @UnitOfWork public ContestContestantsUpsertResponse upsertContestants( - AuthHeader authHeader, - String contestJid, + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("contestJid") String contestJid, Set usernames) { String actorJid = actorChecker.check(authHeader); @@ -192,11 +217,14 @@ public ContestContestantsUpsertResponse upsertContestants( .build(); } - @Override + @POST + @Path("/batch-delete") + @Consumes(APPLICATION_JSON) + @Produces(APPLICATION_JSON) @UnitOfWork public ContestContestantsDeleteResponse deleteContestants( - AuthHeader authHeader, - String contestJid, + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("contestJid") String contestJid, Set usernames) { String actorJid = actorChecker.check(authHeader); diff --git a/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/editorial/ContestEditorialResource.java b/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/editorial/ContestEditorialResource.java index 05a89462d..5a99c4ed8 100644 --- a/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/editorial/ContestEditorialResource.java +++ b/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/editorial/ContestEditorialResource.java @@ -1,5 +1,6 @@ package judgels.uriel.contest.editorial; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static judgels.service.ServiceUtils.checkAllowed; import static judgels.service.ServiceUtils.checkFound; @@ -12,6 +13,12 @@ import java.util.Set; import java.util.stream.Collectors; import javax.inject.Inject; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; import javax.ws.rs.core.UriInfo; import judgels.jophiel.api.profile.Profile; import judgels.jophiel.user.UserClient; @@ -21,7 +28,6 @@ import judgels.sandalphon.problem.ProblemClient; import judgels.uriel.api.contest.Contest; import judgels.uriel.api.contest.editorial.ContestEditorialResponse; -import judgels.uriel.api.contest.editorial.ContestEditorialService; import judgels.uriel.api.contest.module.EditorialModuleConfig; import judgels.uriel.api.contest.problem.ContestProblem; import judgels.uriel.contest.ContestStore; @@ -29,35 +35,26 @@ import judgels.uriel.contest.module.ContestModuleStore; import judgels.uriel.contest.problem.ContestProblemStore; -public class ContestEditorialResource implements ContestEditorialService { - private final ContestLogger contestLogger; - private final ContestEditorialRoleChecker roleChecker; - private final ContestStore contestStore; - private final ContestModuleStore contestModuleStore; - private final ContestProblemStore problemStore; - private final UserClient userClient; - private final ProblemClient problemClient; +@Path("/api/v2/contests/{contestJid}/editorial") +public class ContestEditorialResource { + @Inject protected ContestLogger contestLogger; + @Inject protected ContestEditorialRoleChecker roleChecker; + @Inject protected ContestStore contestStore; + @Inject protected ContestModuleStore contestModuleStore; + @Inject protected ContestProblemStore problemStore; + @Inject protected UserClient userClient; + @Inject protected ProblemClient problemClient; - @Inject - public ContestEditorialResource( - ContestLogger contestLogger, - ContestEditorialRoleChecker roleChecker, - ContestStore contestStore, - ContestModuleStore contestModuleStore, - ContestProblemStore problemStore, - UserClient userClient, ProblemClient problemClient) { - this.contestLogger = contestLogger; - this.roleChecker = roleChecker; - this.contestStore = contestStore; - this.contestModuleStore = contestModuleStore; - this.problemStore = problemStore; - this.userClient = userClient; - this.problemClient = problemClient; - } + @Inject public ContestEditorialResource() {} - @Override + @GET + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) - public ContestEditorialResponse getEditorial(UriInfo uriInfo, String contestJid, Optional language) { + public ContestEditorialResponse getEditorial( + @Context UriInfo uriInfo, + @PathParam("contestJid") String contestJid, + @QueryParam("language") Optional language) { + Contest contest = checkFound(contestStore.getContestByJid(contestJid)); checkAllowed(roleChecker.canView(contest)); diff --git a/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/file/ContestFileResource.java b/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/file/ContestFileResource.java index 653f8bcf5..d6b54f02d 100644 --- a/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/file/ContestFileResource.java +++ b/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/file/ContestFileResource.java @@ -2,6 +2,7 @@ import static javax.ws.rs.core.HttpHeaders.AUTHORIZATION; import static javax.ws.rs.core.HttpHeaders.CONTENT_LENGTH; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static javax.ws.rs.core.MediaType.MULTIPART_FORM_DATA; import static judgels.service.ServiceUtils.checkAllowed; import static judgels.service.ServiceUtils.checkFound; @@ -18,6 +19,7 @@ import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; import javax.ws.rs.core.Response; import judgels.fs.FileSystem; import judgels.service.ServiceUtils; @@ -26,7 +28,6 @@ import judgels.uriel.api.contest.Contest; import judgels.uriel.api.contest.file.ContestFile; import judgels.uriel.api.contest.file.ContestFileConfig; -import judgels.uriel.api.contest.file.ContestFileService; import judgels.uriel.api.contest.file.ContestFilesResponse; import judgels.uriel.contest.ContestStore; import judgels.uriel.contest.log.ContestLogger; @@ -34,31 +35,23 @@ import org.glassfish.jersey.media.multipart.FormDataContentDisposition; import org.glassfish.jersey.media.multipart.FormDataParam; -public class ContestFileResource implements ContestFileService { - private final ActorChecker actorChecker; - private final ContestFileRoleChecker fileRoleChecker; - private final ContestStore contestStore; - private final ContestLogger contestLogger; - private final FileSystem fileFs; - - @Inject - public ContestFileResource( - ActorChecker actorChecker, - ContestFileRoleChecker fileRoleChecker, - ContestStore contestStore, - ContestLogger contestLogger, - @FileFs FileSystem fileFs) { - - this.actorChecker = actorChecker; - this.fileRoleChecker = fileRoleChecker; - this.contestStore = contestStore; - this.contestLogger = contestLogger; - this.fileFs = fileFs; - } +@Path("/api/v2/contests/{contestJid}/files") +public class ContestFileResource { + @Inject protected ActorChecker actorChecker; + @Inject protected ContestFileRoleChecker fileRoleChecker; + @Inject protected ContestStore contestStore; + @Inject protected ContestLogger contestLogger; + @Inject @FileFs protected FileSystem fileFs; + + @Inject public ContestFileResource() {} - @Override + @GET + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) - public ContestFilesResponse getFiles(AuthHeader authHeader, String contestJid) { + public ContestFilesResponse getFiles( + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("contestJid") String contestJid) { + String actorJid = actorChecker.check(authHeader); Contest contest = checkFound(contestStore.getContestByJid(contestJid)); @@ -87,7 +80,10 @@ public ContestFilesResponse getFiles(AuthHeader authHeader, String contestJid) { @GET @Path("/{filename}") @UnitOfWork(readOnly = true) - public Response downloadFile(@PathParam("contestJid") String contestJid, @PathParam("filename") String filename) { + public Response downloadFile( + @PathParam("contestJid") String contestJid, + @PathParam("filename") String filename) { + checkFound(contestStore.getContestByJid(contestJid)); Response response = ServiceUtils.buildDownloadResponse(fileFs.getPrivateFileUrl(Paths.get(contestJid, filename))); @@ -98,7 +94,6 @@ public Response downloadFile(@PathParam("contestJid") String contestJid, @PathPa } @POST - @Path("/") @Consumes(MULTIPART_FORM_DATA) @UnitOfWork public void uploadFile( diff --git a/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/history/ContestHistoryResource.java b/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/history/ContestHistoryResource.java index afcec0a9c..4e15af26b 100644 --- a/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/history/ContestHistoryResource.java +++ b/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/history/ContestHistoryResource.java @@ -1,5 +1,6 @@ package judgels.uriel.contest.history; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static judgels.service.ServiceUtils.checkFound; import io.dropwizard.hibernate.UnitOfWork; @@ -8,6 +9,10 @@ import java.util.Optional; import java.util.stream.Collectors; import javax.inject.Inject; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; import judgels.jophiel.api.user.rating.UserRating; import judgels.jophiel.api.user.rating.UserRatingEvent; import judgels.jophiel.user.UserClient; @@ -15,29 +20,22 @@ import judgels.uriel.api.contest.ContestInfo; import judgels.uriel.api.contest.history.ContestHistoryEvent; import judgels.uriel.api.contest.history.ContestHistoryResponse; -import judgels.uriel.api.contest.history.ContestHistoryService; import judgels.uriel.contest.ContestStore; import judgels.uriel.contest.contestant.ContestContestantStore; -public class ContestHistoryResource implements ContestHistoryService { - private final ContestStore contestStore; - private final ContestContestantStore contestantStore; - private final UserClient userClient; +@Path("/api/v2/contest-history") +public class ContestHistoryResource { + @Inject protected ContestStore contestStore; + @Inject protected ContestContestantStore contestantStore; + @Inject protected UserClient userClient; - @Inject - public ContestHistoryResource( - ContestStore contestStore, - ContestContestantStore contestantStore, - UserClient userClient) { + @Inject public ContestHistoryResource() {} - this.contestStore = contestStore; - this.contestantStore = contestantStore; - this.userClient = userClient; - } - - @Override + @GET + @Path("/public") + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) - public ContestHistoryResponse getPublicHistory(String username) { + public ContestHistoryResponse getPublicHistory(@QueryParam("username") String username) { String userJid = checkFound(userClient.translateUsernameToJid(username)); List contests = contestStore.getPubliclyParticipatedContests(userJid); diff --git a/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/log/ContestLogResource.java b/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/log/ContestLogResource.java index 6387188d6..87dccd9b4 100644 --- a/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/log/ContestLogResource.java +++ b/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/log/ContestLogResource.java @@ -1,5 +1,7 @@ package judgels.uriel.contest.log; +import static javax.ws.rs.core.HttpHeaders.AUTHORIZATION; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static judgels.service.ServiceUtils.checkAllowed; import static judgels.service.ServiceUtils.checkFound; @@ -11,6 +13,12 @@ import java.util.Optional; import java.util.Set; import javax.inject.Inject; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; import judgels.jophiel.api.profile.Profile; import judgels.jophiel.user.UserClient; import judgels.persistence.api.Page; @@ -19,7 +27,6 @@ import judgels.uriel.api.contest.Contest; import judgels.uriel.api.contest.log.ContestLog; import judgels.uriel.api.contest.log.ContestLogConfig; -import judgels.uriel.api.contest.log.ContestLogService; import judgels.uriel.api.contest.log.ContestLogsResponse; import judgels.uriel.api.contest.problem.ContestProblem; import judgels.uriel.contest.ContestRoleChecker; @@ -28,47 +35,30 @@ import judgels.uriel.contest.problem.ContestProblemStore; import judgels.uriel.contest.supervisor.ContestSupervisorStore; -public class ContestLogResource implements ContestLogService { +@Path("/api/v2/contests/{contestJid}/logs") +public class ContestLogResource { private static final int PAGE_SIZE = 100; - private final ActorChecker actorChecker; - private final ContestRoleChecker contestRoleChecker; - private final ContestStore contestStore; - private final ContestLogStore logStore; - private final ContestContestantStore contestantStore; - private final ContestSupervisorStore supervisorStore; - private final ContestProblemStore problemStore; - private final UserClient userClient; - - @Inject - public ContestLogResource( - ActorChecker actorChecker, - ContestRoleChecker contestRoleChecker, - ContestStore contestStore, - ContestLogStore logStore, - ContestContestantStore contestantStore, - ContestSupervisorStore supervisorStore, - ContestProblemStore problemStore, - UserClient userClient) { - - this.actorChecker = actorChecker; - this.contestRoleChecker = contestRoleChecker; - this.contestStore = contestStore; - this.logStore = logStore; - this.contestantStore = contestantStore; - this.supervisorStore = supervisorStore; - this.problemStore = problemStore; - this.userClient = userClient; - } + @Inject protected ActorChecker actorChecker; + @Inject protected ContestRoleChecker contestRoleChecker; + @Inject protected ContestStore contestStore; + @Inject protected ContestLogStore logStore; + @Inject protected ContestContestantStore contestantStore; + @Inject protected ContestSupervisorStore supervisorStore; + @Inject protected ContestProblemStore problemStore; + @Inject protected UserClient userClient; + + @Inject public ContestLogResource() {} - @Override + @GET + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) public ContestLogsResponse getLogs( - AuthHeader authHeader, - String contestJid, - Optional username, - Optional problemAlias, - Optional pageNumber) { + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("contestJid") String contestJid, + @QueryParam("username") Optional username, + @QueryParam("problemAlias") Optional problemAlias, + @QueryParam("page") Optional pageNumber) { String actorJid = actorChecker.check(authHeader); Contest contest = checkFound(contestStore.getContestByJid(contestJid)); diff --git a/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/manager/ContestManagerResource.java b/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/manager/ContestManagerResource.java index 3a3b01091..9784f3b98 100644 --- a/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/manager/ContestManagerResource.java +++ b/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/manager/ContestManagerResource.java @@ -1,6 +1,8 @@ package judgels.uriel.contest.manager; import static com.google.common.base.Preconditions.checkArgument; +import static javax.ws.rs.core.HttpHeaders.AUTHORIZATION; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static judgels.service.ServiceUtils.checkAllowed; import static judgels.service.ServiceUtils.checkFound; @@ -12,6 +14,14 @@ import java.util.Set; import java.util.stream.Collectors; import javax.inject.Inject; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; import judgels.jophiel.api.profile.Profile; import judgels.jophiel.user.UserClient; import judgels.persistence.api.Page; @@ -20,43 +30,33 @@ import judgels.uriel.api.contest.Contest; import judgels.uriel.api.contest.manager.ContestManager; import judgels.uriel.api.contest.manager.ContestManagerConfig; -import judgels.uriel.api.contest.manager.ContestManagerService; import judgels.uriel.api.contest.manager.ContestManagersDeleteResponse; import judgels.uriel.api.contest.manager.ContestManagersResponse; import judgels.uriel.api.contest.manager.ContestManagersUpsertResponse; import judgels.uriel.contest.ContestStore; import judgels.uriel.contest.log.ContestLogger; -public class ContestManagerResource implements ContestManagerService { +@Path("/api/v2/contests/{contestJid}/managers") +public class ContestManagerResource { private static final int PAGE_SIZE = 250; - private final ActorChecker actorChecker; - private final ContestStore contestStore; - private final ContestLogger contestLogger; - private final ContestManagerRoleChecker managerRoleChecker; - private final ContestManagerStore managerStore; - private final UserClient userClient; - - @Inject - public ContestManagerResource( - ActorChecker actorChecker, - ContestStore contestStore, - ContestLogger contestLogger, - ContestManagerRoleChecker managerRoleChecker, - ContestManagerStore managerStore, - UserClient userClient) { - - this.actorChecker = actorChecker; - this.contestStore = contestStore; - this.contestLogger = contestLogger; - this.managerRoleChecker = managerRoleChecker; - this.managerStore = managerStore; - this.userClient = userClient; - } + @Inject protected ActorChecker actorChecker; + @Inject protected ContestStore contestStore; + @Inject protected ContestLogger contestLogger; + @Inject protected ContestManagerRoleChecker managerRoleChecker; + @Inject protected ContestManagerStore managerStore; + @Inject protected UserClient userClient; + + @Inject public ContestManagerResource() {} - @Override + @GET + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) - public ContestManagersResponse getManagers(AuthHeader authHeader, String contestJid, Optional pageNumber) { + public ContestManagersResponse getManagers( + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("contestJid") String contestJid, + @QueryParam("page") Optional pageNumber) { + String actorJid = actorChecker.check(authHeader); Contest contest = checkFound(contestStore.getContestByJid(contestJid)); checkAllowed(managerRoleChecker.canView(actorJid, contest)); @@ -79,11 +79,14 @@ public ContestManagersResponse getManagers(AuthHeader authHeader, String contest .build(); } - @Override + @POST + @Path("/batch-upsert") + @Consumes(APPLICATION_JSON) + @Produces(APPLICATION_JSON) @UnitOfWork public ContestManagersUpsertResponse upsertManagers( - AuthHeader authHeader, - String contestJid, + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("contestJid") String contestJid, Set usernames) { String actorJid = actorChecker.check(authHeader); @@ -121,11 +124,14 @@ public ContestManagersUpsertResponse upsertManagers( .build(); } - @Override + @POST + @Path("/batch-delete") + @Consumes(APPLICATION_JSON) + @Produces(APPLICATION_JSON) @UnitOfWork public ContestManagersDeleteResponse deleteManagers( - AuthHeader authHeader, - String contestJid, + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("contestJid") String contestJid, Set usernames) { String actorJid = actorChecker.check(authHeader); diff --git a/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/module/ContestModuleResource.java b/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/module/ContestModuleResource.java index 764cb0a4c..a86af4275 100644 --- a/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/module/ContestModuleResource.java +++ b/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/module/ContestModuleResource.java @@ -1,50 +1,49 @@ package judgels.uriel.contest.module; +import static javax.ws.rs.core.HttpHeaders.AUTHORIZATION; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static judgels.service.ServiceUtils.checkAllowed; import static judgels.service.ServiceUtils.checkFound; import io.dropwizard.hibernate.UnitOfWork; import java.util.Set; import javax.inject.Inject; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; import judgels.jophiel.user.UserClient; import judgels.service.actor.ActorChecker; import judgels.service.api.actor.AuthHeader; import judgels.uriel.api.contest.Contest; -import judgels.uriel.api.contest.module.ContestModuleService; import judgels.uriel.api.contest.module.ContestModuleType; import judgels.uriel.api.contest.module.ContestModulesConfig; import judgels.uriel.contest.ContestRoleChecker; import judgels.uriel.contest.ContestStore; import judgels.uriel.contest.log.ContestLogger; -public class ContestModuleResource implements ContestModuleService { - private final ActorChecker actorChecker; - private final ContestRoleChecker contestRoleChecker; - private final ContestStore contestStore; - private final ContestLogger contestLogger; - private final ContestModuleStore moduleStore; - private final UserClient userClient; - - @Inject - public ContestModuleResource( - ActorChecker actorChecker, - ContestRoleChecker contestRoleChecker, - ContestStore contestStore, - ContestLogger contestLogger, - ContestModuleStore moduleStore, - UserClient userClient) { - - this.actorChecker = actorChecker; - this.contestRoleChecker = contestRoleChecker; - this.contestStore = contestStore; - this.contestLogger = contestLogger; - this.moduleStore = moduleStore; - this.userClient = userClient; - } +@Path("/api/v2/contests/{contestJid}/modules") +public class ContestModuleResource { + @Inject protected ActorChecker actorChecker; + @Inject protected ContestRoleChecker contestRoleChecker; + @Inject protected ContestStore contestStore; + @Inject protected ContestLogger contestLogger; + @Inject protected ContestModuleStore moduleStore; + @Inject protected UserClient userClient; + + @Inject public ContestModuleResource() {} - @Override + @GET + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) - public Set getModules(AuthHeader authHeader, String contestJid) { + public Set getModules( + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("contestJid") String contestJid) { + String actorJid = actorChecker.check(authHeader); Contest contest = checkFound(contestStore.getContestByJid(contestJid)); @@ -55,9 +54,14 @@ public Set getModules(AuthHeader authHeader, String contestJi return moduleStore.getEnabledModules(contest.getJid()); } - @Override + @PUT + @Path("/{type}") @UnitOfWork - public void enableModule(AuthHeader authHeader, String contestJid, ContestModuleType type) { + public void enableModule( + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("contestJid") String contestJid, + @PathParam("type") ContestModuleType type) { + String actorJid = actorChecker.check(authHeader); Contest contest = checkFound(contestStore.getContestByJid(contestJid)); @@ -67,9 +71,14 @@ public void enableModule(AuthHeader authHeader, String contestJid, ContestModule contestLogger.log(contestJid, "ENABLE_MODULE", type.name()); } - @Override + @DELETE + @Path("/{type}") @UnitOfWork - public void disableModule(AuthHeader authHeader, String contestJid, ContestModuleType type) { + public void disableModule( + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("contestJid") String contestJid, + @PathParam("type") ContestModuleType type) { + String actorJid = actorChecker.check(authHeader); Contest contest = checkFound(contestStore.getContestByJid(contestJid)); @@ -79,9 +88,14 @@ public void disableModule(AuthHeader authHeader, String contestJid, ContestModul contestLogger.log(contestJid, "DISABLE_MODULE", type.name()); } - @Override + @GET + @Path("/config") + @Produces(APPLICATION_JSON) @UnitOfWork - public ContestModulesConfig getConfig(AuthHeader authHeader, String contestJid) { + public ContestModulesConfig getConfig( + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("contestJid") String contestJid) { + String actorJid = actorChecker.check(authHeader); Contest contest = checkFound(contestStore.getContestByJid(contestJid)); @@ -96,9 +110,15 @@ public ContestModulesConfig getConfig(AuthHeader authHeader, String contestJid) return config; } - @Override + @PUT + @Path("/config") + @Consumes(APPLICATION_JSON) @UnitOfWork - public void upsertConfig(AuthHeader authHeader, String contestJid, ContestModulesConfig config) { + public void upsertConfig( + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("contestJid") String contestJid, + ContestModulesConfig config) { + String actorJid = actorChecker.check(authHeader); Contest contest = checkFound(contestStore.getContestByJid(contestJid)); diff --git a/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/problem/ContestProblemResource.java b/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/problem/ContestProblemResource.java index 7a0964b56..deeb32933 100644 --- a/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/problem/ContestProblemResource.java +++ b/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/problem/ContestProblemResource.java @@ -1,6 +1,8 @@ package judgels.uriel.contest.problem; import static com.google.common.base.Preconditions.checkArgument; +import static javax.ws.rs.core.HttpHeaders.AUTHORIZATION; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static judgels.service.ServiceUtils.checkAllowed; import static judgels.service.ServiceUtils.checkFound; import static judgels.service.actor.Actors.GUEST; @@ -12,6 +14,15 @@ import java.util.Set; import java.util.stream.Collectors; import javax.inject.Inject; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; import javax.ws.rs.core.UriInfo; import judgels.gabriel.api.LanguageRestriction; import judgels.sandalphon.api.problem.ProblemInfo; @@ -26,48 +37,30 @@ import judgels.uriel.api.contest.problem.ContestProblem; import judgels.uriel.api.contest.problem.ContestProblemConfig; import judgels.uriel.api.contest.problem.ContestProblemData; -import judgels.uriel.api.contest.problem.ContestProblemService; import judgels.uriel.api.contest.problem.ContestProblemsResponse; import judgels.uriel.contest.ContestStore; import judgels.uriel.contest.log.ContestLogger; import judgels.uriel.contest.module.ContestModuleStore; -public class ContestProblemResource implements ContestProblemService { - private final ActorChecker actorChecker; - private final ContestProblemRoleChecker roleChecker; - private final ContestLogger contestLogger; - private final ContestStore contestStore; - private final ContestProblemStore problemStore; - private final ContestModuleStore moduleStore; - private final SubmissionStore submissionStore; - private final ProblemClient problemClient; - - @Inject - public ContestProblemResource( - ActorChecker actorChecker, - ContestProblemRoleChecker roleChecker, - ContestLogger contestLogger, - ContestStore contestStore, - ContestProblemStore problemStore, - ContestModuleStore moduleStore, - SubmissionStore submissionStore, - ProblemClient problemClient) { - - this.actorChecker = actorChecker; - this.roleChecker = roleChecker; - this.contestLogger = contestLogger; - this.contestStore = contestStore; - this.problemStore = problemStore; - this.moduleStore = moduleStore; - this.submissionStore = submissionStore; - this.problemClient = problemClient; - } - - @Override +@Path("/api/v2/contests/{contestJid}/problems") +public class ContestProblemResource { + @Inject protected ActorChecker actorChecker; + @Inject protected ContestProblemRoleChecker roleChecker; + @Inject protected ContestLogger contestLogger; + @Inject protected ContestStore contestStore; + @Inject protected ContestProblemStore problemStore; + @Inject protected ContestModuleStore moduleStore; + @Inject protected SubmissionStore submissionStore; + @Inject protected ProblemClient problemClient; + + @Inject public ContestProblemResource() {} + + @PUT + @Consumes(APPLICATION_JSON) @UnitOfWork public void setProblems( - AuthHeader authHeader, - String contestJid, + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("contestJid") String contestJid, List data) { String actorJid = actorChecker.check(authHeader); @@ -107,9 +100,13 @@ public void setProblems( contestLogger.log(contestJid, "SET_PROBLEMS"); } - @Override + @GET + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) - public ContestProblemsResponse getProblems(Optional authHeader, String contestJid) { + public ContestProblemsResponse getProblems( + @HeaderParam(AUTHORIZATION) Optional authHeader, + @PathParam("contestJid") String contestJid) { + String actorJid = actorChecker.check(authHeader); Contest contest = checkFound(contestStore.getContestByJid(contestJid)); checkAllowed(roleChecker.canView(actorJid, contest)); @@ -146,14 +143,16 @@ public ContestProblemsResponse getProblems(Optional authHeader, Stri .build(); } - @Override + @GET + @Path("/{problemAlias}/programming/worksheet") + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) public judgels.uriel.api.contest.problem.programming.ContestProblemWorksheet getProgrammingProblemWorksheet( - UriInfo uriInfo, - Optional authHeader, - String contestJid, - String problemAlias, - Optional language) { + @Context UriInfo uriInfo, + @HeaderParam(AUTHORIZATION) Optional authHeader, + @PathParam("contestJid") String contestJid, + @PathParam("problemAlias") String problemAlias, + @QueryParam("language") Optional language) { String actorJid = actorChecker.check(authHeader); Contest contest = checkFound(contestStore.getContestByJid(contestJid)); @@ -202,14 +201,16 @@ public judgels.uriel.api.contest.problem.programming.ContestProblemWorksheet get .build(); } - @Override + @GET + @Path("/{problemAlias}/bundle/worksheet") + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) public judgels.uriel.api.contest.problem.bundle.ContestProblemWorksheet getBundleProblemWorksheet( - UriInfo uriInfo, - Optional authHeader, - String contestJid, - String problemAlias, - Optional language) { + @Context UriInfo uriInfo, + @HeaderParam(AUTHORIZATION) Optional authHeader, + @PathParam("contestJid") String contestJid, + @PathParam("problemAlias") String problemAlias, + @QueryParam("language") Optional language) { String actorJid = actorChecker.check(authHeader); Contest contest = checkFound(contestStore.getContestByJid(contestJid)); diff --git a/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/rating/ContestRatingResource.java b/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/rating/ContestRatingResource.java index 6ed44394e..27e23e1c7 100644 --- a/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/rating/ContestRatingResource.java +++ b/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/rating/ContestRatingResource.java @@ -1,5 +1,7 @@ package judgels.uriel.contest.rating; +import static javax.ws.rs.core.HttpHeaders.AUTHORIZATION; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static judgels.service.ServiceUtils.checkAllowed; import static judgels.service.ServiceUtils.checkFound; import static judgels.uriel.api.contest.scoreboard.ContestScoreboardType.OFFICIAL; @@ -14,6 +16,11 @@ import java.util.Set; import java.util.stream.Collectors; import javax.inject.Inject; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; import judgels.jophiel.api.profile.Profile; import judgels.jophiel.api.user.rating.RatingEvent; import judgels.jophiel.api.user.rating.UserRating; @@ -28,7 +35,6 @@ import judgels.uriel.api.contest.rating.ContestRating; import judgels.uriel.api.contest.rating.ContestRatingChanges; import judgels.uriel.api.contest.rating.ContestRatingHistoryResponse; -import judgels.uriel.api.contest.rating.ContestRatingService; import judgels.uriel.api.contest.rating.ContestsPendingRatingResponse; import judgels.uriel.api.contest.scoreboard.Scoreboard; import judgels.uriel.api.contest.scoreboard.ScoreboardEntry; @@ -38,43 +44,25 @@ import judgels.uriel.contest.scoreboard.ContestScoreboardStore; import judgels.uriel.contest.scoreboard.RawContestScoreboard; -public class ContestRatingResource implements ContestRatingService { - private final ActorChecker actorChecker; - private final ContestRoleChecker contestRoleChecker; - private final ContestStore contestStore; - private final ContestScoreboardStore scoreboardStore; - private final ContestScoreboardBuilder scoreboardBuilder; - private final ContestRatingComputer ratingComputer; - private final UserStore userStore; - private final UserRatingStore userRatingStore; - private final ProfileStore profileStore; - - @Inject - public ContestRatingResource( - ActorChecker actorChecker, - ContestRoleChecker contestRoleChecker, - ContestStore contestStore, - ContestScoreboardStore scoreboardStore, - ContestScoreboardBuilder scoreboardBuilder, - ContestRatingComputer ratingComputer, - UserStore userStore, - UserRatingStore userRatingStore, - ProfileStore profileStore) { - - this.actorChecker = actorChecker; - this.contestRoleChecker = contestRoleChecker; - this.contestStore = contestStore; - this.scoreboardStore = scoreboardStore; - this.scoreboardBuilder = scoreboardBuilder; - this.ratingComputer = ratingComputer; - this.userStore = userStore; - this.userRatingStore = userRatingStore; - this.profileStore = profileStore; - } - - @Override +@Path("/api/v2/contest-rating") +public class ContestRatingResource { + @Inject protected ActorChecker actorChecker; + @Inject protected ContestRoleChecker contestRoleChecker; + @Inject protected ContestStore contestStore; + @Inject protected ContestScoreboardStore scoreboardStore; + @Inject protected ContestScoreboardBuilder scoreboardBuilder; + @Inject protected ContestRatingComputer ratingComputer; + @Inject protected UserStore userStore; + @Inject protected UserRatingStore userRatingStore; + @Inject protected ProfileStore profileStore; + + @Inject public ContestRatingResource() {} + + @GET + @Path("/pending") + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) - public ContestsPendingRatingResponse getContestsPendingRating(AuthHeader authHeader) { + public ContestsPendingRatingResponse getContestsPendingRating(@HeaderParam(AUTHORIZATION) AuthHeader authHeader) { String actorJid = actorChecker.check(authHeader); checkAllowed(contestRoleChecker.canAdminister(actorJid)); @@ -91,9 +79,11 @@ public ContestsPendingRatingResponse getContestsPendingRating(AuthHeader authHea .build(); } - @Override + @GET + @Path("/history") + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) - public ContestRatingHistoryResponse getRatingHistory(String username) { + public ContestRatingHistoryResponse getRatingHistory(@QueryParam("username") String username) { String userJid = checkFound(userStore.translateUsernameToJid(username)); List userRatingEvents = userRatingStore.getUserRatingEvents(userJid); diff --git a/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/scoreboard/ContestScoreboardResource.java b/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/scoreboard/ContestScoreboardResource.java index b9e316139..e62c0fc51 100644 --- a/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/scoreboard/ContestScoreboardResource.java +++ b/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/scoreboard/ContestScoreboardResource.java @@ -1,5 +1,7 @@ package judgels.uriel.contest.scoreboard; +import static javax.ws.rs.core.HttpHeaders.AUTHORIZATION; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static judgels.service.ServiceUtils.checkAllowed; import static judgels.service.ServiceUtils.checkFound; @@ -9,6 +11,13 @@ import java.util.Set; import java.util.stream.Collectors; import javax.inject.Inject; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; import judgels.jophiel.api.profile.Profile; import judgels.jophiel.user.UserClient; import judgels.service.actor.ActorChecker; @@ -16,55 +25,36 @@ import judgels.uriel.api.contest.Contest; import judgels.uriel.api.contest.scoreboard.ContestScoreboardConfig; import judgels.uriel.api.contest.scoreboard.ContestScoreboardResponse; -import judgels.uriel.api.contest.scoreboard.ContestScoreboardService; import judgels.uriel.api.contest.scoreboard.ScoreboardEntry; import judgels.uriel.contest.ContestStore; import judgels.uriel.contest.log.ContestLogger; import judgels.uriel.contest.submission.ContestSubmissionRoleChecker; -public class ContestScoreboardResource implements ContestScoreboardService { - private final ActorChecker actorChecker; - private final ContestStore contestStore; - private final ContestLogger contestLogger; - private final ContestSubmissionRoleChecker submissionRoleChecker; - private final ContestScoreboardRoleChecker scoreboardRoleChecker; - private final ContestScoreboardFetcher scoreboardFetcher; - private final ContestScoreboardPoller scoreboardUpdaterDispatcher; - private final ScoreboardIncrementalMarker scoreboardIncrementalMarker; - private final UserClient userClient; +@Path("/api/v2/contests/{contestJid}/scoreboard") +public class ContestScoreboardResource { private static final int PAGE_SIZE = 250; - @Inject - public ContestScoreboardResource( - ActorChecker actorChecker, - ContestStore contestStore, - ContestLogger contestLogger, - ContestSubmissionRoleChecker submissionRoleChecker, - ContestScoreboardRoleChecker scoreboardRoleChecker, - ContestScoreboardFetcher scoreboardFetcher, - ContestScoreboardPoller scoreboardUpdaterDispatcher, - ScoreboardIncrementalMarker scoreboardIncrementalMarker, - UserClient userClient) { - - this.actorChecker = actorChecker; - this.contestStore = contestStore; - this.contestLogger = contestLogger; - this.submissionRoleChecker = submissionRoleChecker; - this.scoreboardRoleChecker = scoreboardRoleChecker; - this.scoreboardFetcher = scoreboardFetcher; - this.scoreboardUpdaterDispatcher = scoreboardUpdaterDispatcher; - this.scoreboardIncrementalMarker = scoreboardIncrementalMarker; - this.userClient = userClient; - } + @Inject protected ActorChecker actorChecker; + @Inject protected ContestStore contestStore; + @Inject protected ContestLogger contestLogger; + @Inject protected ContestSubmissionRoleChecker submissionRoleChecker; + @Inject protected ContestScoreboardRoleChecker scoreboardRoleChecker; + @Inject protected ContestScoreboardFetcher scoreboardFetcher; + @Inject protected ContestScoreboardPoller scoreboardUpdaterDispatcher; + @Inject protected ScoreboardIncrementalMarker scoreboardIncrementalMarker; + @Inject protected UserClient userClient; + + @Inject public ContestScoreboardResource() {} - @Override + @GET + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) public Optional getScoreboard( - Optional authHeader, - String contestJid, - boolean frozen, - boolean showClosedProblems, - Optional page) { + @HeaderParam(AUTHORIZATION) Optional authHeader, + @PathParam("contestJid") String contestJid, + @QueryParam("frozen") boolean frozen, + @QueryParam("showClosedProblems") boolean showClosedProblems, + @QueryParam("page") Optional page) { String actorJid = actorChecker.check(authHeader); Contest contest = checkFound(contestStore.getContestByJid(contestJid)); @@ -104,9 +94,13 @@ public Optional getScoreboard( }); } - @Override + @POST + @Path("/refresh") @UnitOfWork - public void refreshScoreboard(AuthHeader authHeader, String contestJid) { + public void refreshScoreboard( + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("contestJid") String contestJid) { + String actorJid = actorChecker.check(authHeader); Contest contest = checkFound(contestStore.getContestByJid(contestJid)); checkAllowed(scoreboardRoleChecker.canManage(actorJid, contest)); diff --git a/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/submission/bundle/ContestItemSubmissionResource.java b/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/submission/bundle/ContestItemSubmissionResource.java index 672e13e85..77b1f25ba 100644 --- a/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/submission/bundle/ContestItemSubmissionResource.java +++ b/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/submission/bundle/ContestItemSubmissionResource.java @@ -1,5 +1,7 @@ package judgels.uriel.contest.submission.bundle; +import static javax.ws.rs.core.HttpHeaders.AUTHORIZATION; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static judgels.service.ServiceUtils.checkAllowed; import static judgels.service.ServiceUtils.checkFound; @@ -18,6 +20,14 @@ import java.util.function.Function; import java.util.stream.Collectors; import javax.inject.Inject; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; import judgels.jophiel.api.profile.Profile; import judgels.jophiel.user.UserClient; import judgels.persistence.api.Page; @@ -51,61 +61,36 @@ import org.slf4j.Marker; import org.slf4j.MarkerFactory; +@Path("/api/v2/contests/submissions/bundle") public class ContestItemSubmissionResource implements ContestItemSubmissionService { private static final Logger LOGGER = LoggerFactory.getLogger(ContestItemSubmissionResource.class); private static final Marker ITEM_SUBMISSION_MARKER = MarkerFactory.getMarker("ITEM_SUBMISSION"); private static final int PAGE_SIZE = 20; - private final ActorChecker actorChecker; - private final ContestStore contestStore; - private final ContestContestantStore contestContestantStore; - private final ItemSubmissionStore submissionStore; - private final ContestRoleChecker contestRoleChecker; - private final ContestSubmissionRoleChecker submissionRoleChecker; - private final ContestProblemRoleChecker problemRoleChecker; - private final ContestProblemStore problemStore; - private final ItemSubmissionGraderRegistry itemSubmissionGraderRegistry; - private final ItemSubmissionRegrader itemSubmissionRegrader; - private final UserClient userClient; - private final ProblemClient problemClient; - - @Inject - public ContestItemSubmissionResource( - ActorChecker actorChecker, - ContestStore contestStore, - ContestContestantStore contestContestantStore, - ItemSubmissionStore submissionStore, - ContestRoleChecker contestRoleChecker, - ContestSubmissionRoleChecker submissionRoleChecker, - ContestProblemRoleChecker problemRoleChecker, - ContestProblemStore problemStore, - ItemSubmissionGraderRegistry itemSubmissionGraderRegistry, - ItemSubmissionRegrader itemSubmissionRegrader, - UserClient userClient, - ProblemClient problemClient) { - - this.actorChecker = actorChecker; - this.contestStore = contestStore; - this.contestContestantStore = contestContestantStore; - this.submissionStore = submissionStore; - this.contestRoleChecker = contestRoleChecker; - this.submissionRoleChecker = submissionRoleChecker; - this.problemRoleChecker = problemRoleChecker; - this.problemStore = problemStore; - this.itemSubmissionGraderRegistry = itemSubmissionGraderRegistry; - this.itemSubmissionRegrader = itemSubmissionRegrader; - this.userClient = userClient; - this.problemClient = problemClient; - } - - @Override + @Inject protected ActorChecker actorChecker; + @Inject protected ContestStore contestStore; + @Inject protected ContestContestantStore contestContestantStore; + @Inject protected ItemSubmissionStore submissionStore; + @Inject protected ContestRoleChecker contestRoleChecker; + @Inject protected ContestSubmissionRoleChecker submissionRoleChecker; + @Inject protected ContestProblemRoleChecker problemRoleChecker; + @Inject protected ContestProblemStore problemStore; + @Inject protected ItemSubmissionGraderRegistry itemSubmissionGraderRegistry; + @Inject protected ItemSubmissionRegrader itemSubmissionRegrader; + @Inject protected UserClient userClient; + @Inject protected ProblemClient problemClient; + + @Inject public ContestItemSubmissionResource() {} + + @GET + @Produces(APPLICATION_JSON) @UnitOfWork public ContestItemSubmissionsResponse getSubmissions( - AuthHeader authHeader, - String contestJid, - Optional username, - Optional problemAlias, - Optional pageNumber) { + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @QueryParam("contestJid") String contestJid, + @QueryParam("username") Optional username, + @QueryParam("problemAlias") Optional problemAlias, + @QueryParam("page") Optional pageNumber) { String actorJid = actorChecker.check(authHeader); Contest contest = checkFound(contestStore.getContestByJid(contestJid)); @@ -190,9 +175,13 @@ public ContestItemSubmissionsResponse getSubmissions( .build(); } - @Override + @POST + @Consumes(APPLICATION_JSON) @UnitOfWork - public void createItemSubmission(AuthHeader authHeader, ItemSubmissionData data) { + public void createItemSubmission( + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + ItemSubmissionData data) { + String actorJid = actorChecker.check(authHeader); Contest contest = checkFound(contestStore.getContestByJid(data.getContainerJid())); ContestProblem problem = checkFound(problemStore.getProblem(data.getContainerJid(), data.getProblemJid())); @@ -233,13 +222,15 @@ public void createItemSubmission(AuthHeader authHeader, ItemSubmissionData data) } } - @Override + @GET + @Path("/answers") + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) public Map getLatestSubmissions( - AuthHeader authHeader, - String contestJid, - Optional username, - String problemAlias) { + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @QueryParam("contestJid") String contestJid, + @QueryParam("username") Optional username, + @QueryParam("problemAlias") String problemAlias) { String actorJid = actorChecker.check(authHeader); Contest contest = checkFound(contestStore.getContestByJid(contestJid)); @@ -260,13 +251,15 @@ public Map getLatestSubmissions( .collect(Collectors.toMap(ItemSubmission::getItemJid, Function.identity())); } - @Override + @GET + @Path("/summary") + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) public ContestSubmissionSummaryResponse getSubmissionSummary( - AuthHeader authHeader, - String contestJid, - Optional username, - Optional language) { + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @QueryParam("contestJid") String contestJid, + @QueryParam("username") Optional username, + @QueryParam("language") Optional language) { String actorJid = actorChecker.check(authHeader); Contest contest = checkFound(contestStore.getContestByJid(contestJid)); @@ -333,9 +326,13 @@ public ContestSubmissionSummaryResponse getSubmissionSummary( .build(); } - @Override + @POST + @Path("/{submissionJid}/regrade") @UnitOfWork - public void regradeSubmission(AuthHeader authHeader, String submissionJid) { + public void regradeSubmission( + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("submissionJid") String submissionJid) { + String actorJid = actorChecker.check(authHeader); ItemSubmission submission = checkFound(submissionStore.getSubmissionByJid(submissionJid)); Contest contest = checkFound(contestStore.getContestByJid(submission.getContainerJid())); @@ -344,14 +341,15 @@ public void regradeSubmission(AuthHeader authHeader, String submissionJid) { itemSubmissionRegrader.regradeSubmission(submission); } - @Override + @POST + @Path("/regrade") @UnitOfWork public void regradeSubmissions( - AuthHeader authHeader, - Optional contestJid, - Optional username, - Optional problemJid, - Optional problemAlias) { + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @QueryParam("contestJid") Optional contestJid, + @QueryParam("username") Optional username, + @QueryParam("problemJid") Optional problemJid, + @QueryParam("problemAlias") Optional problemAlias) { String actorJid = actorChecker.check(authHeader); if (contestJid.isPresent()) { diff --git a/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/submission/programming/ContestSubmissionResource.java b/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/submission/programming/ContestSubmissionResource.java index a757bd303..838287c5f 100644 --- a/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/submission/programming/ContestSubmissionResource.java +++ b/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/submission/programming/ContestSubmissionResource.java @@ -4,6 +4,7 @@ import static java.util.stream.Collectors.toMap; import static java.util.stream.Collectors.toSet; import static javax.ws.rs.core.HttpHeaders.AUTHORIZATION; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM; import static javax.ws.rs.core.MediaType.MULTIPART_FORM_DATA; import static judgels.service.ServiceUtils.buildDarkImageResponseFromText; @@ -56,7 +57,6 @@ import judgels.uriel.api.contest.module.StyleModuleConfig; import judgels.uriel.api.contest.problem.ContestProblem; import judgels.uriel.api.contest.submission.ContestSubmissionConfig; -import judgels.uriel.api.contest.submission.programming.ContestSubmissionService; import judgels.uriel.api.contest.submission.programming.ContestSubmissionsResponse; import judgels.uriel.contest.ContestStore; import judgels.uriel.contest.contestant.ContestContestantStore; @@ -70,76 +70,41 @@ import org.glassfish.jersey.media.multipart.ContentDisposition; import org.glassfish.jersey.media.multipart.FormDataMultiPart; -public class ContestSubmissionResource implements ContestSubmissionService { +@Path("/api/v2/contests/submissions/programming") +public class ContestSubmissionResource { private static final int MAX_DOWNLOAD_SUBMISSIONS_LIMIT = 5000; private static final String LAST_SUBMISSION_ID_HEADER = "Last-Submission-Id"; private static final int PAGE_SIZE = 20; - private final ActorChecker actorChecker; - private final ContestStore contestStore; - private final ContestLogger contestLogger; - private final SubmissionStore submissionStore; - private final SubmissionSourceBuilder submissionSourceBuilder; - private final SubmissionDownloader submissionDownloader; - private final SubmissionClient submissionClient; - private final SubmissionRegrader submissionRegrader; - private final ScoreboardIncrementalMarker scoreboardIncrementalMarker; - private final ContestSubmissionRoleChecker submissionRoleChecker; - private final ContestProblemRoleChecker problemRoleChecker; - private final ContestModuleStore moduleStore; - private final ContestContestantStore contestantStore; - private final ContestSupervisorStore supervisorStore; - private final ContestProblemStore problemStore; - private final UserClient userClient; - private final ProblemClient problemClient; - - @Inject - public ContestSubmissionResource( - ActorChecker actorChecker, - ContestStore contestStore, - ContestLogger contestLogger, - SubmissionStore submissionStore, - SubmissionSourceBuilder submissionSourceBuilder, - SubmissionDownloader submissionDownloader, - SubmissionClient submissionClient, - SubmissionRegrader submissionRegrader, - ScoreboardIncrementalMarker scoreboardIncrementalMarker, - ContestSubmissionRoleChecker submissionRoleChecker, - ContestProblemRoleChecker problemRoleChecker, - ContestModuleStore moduleStore, - ContestContestantStore contestantStore, - ContestSupervisorStore supervisorStore, - ContestProblemStore problemStore, - UserClient userClient, - ProblemClient problemClient) { - - this.actorChecker = actorChecker; - this.contestStore = contestStore; - this.contestLogger = contestLogger; - this.submissionStore = submissionStore; - this.submissionSourceBuilder = submissionSourceBuilder; - this.submissionDownloader = submissionDownloader; - this.submissionClient = submissionClient; - this.submissionRegrader = submissionRegrader; - this.submissionRoleChecker = submissionRoleChecker; - this.scoreboardIncrementalMarker = scoreboardIncrementalMarker; - this.problemRoleChecker = problemRoleChecker; - this.moduleStore = moduleStore; - this.contestantStore = contestantStore; - this.supervisorStore = supervisorStore; - this.problemStore = problemStore; - this.userClient = userClient; - this.problemClient = problemClient; - } + @Inject protected ActorChecker actorChecker; + @Inject protected ContestStore contestStore; + @Inject protected ContestLogger contestLogger; + @Inject protected SubmissionStore submissionStore; + @Inject protected SubmissionSourceBuilder submissionSourceBuilder; + @Inject protected SubmissionDownloader submissionDownloader; + @Inject protected SubmissionClient submissionClient; + @Inject protected SubmissionRegrader submissionRegrader; + @Inject protected ScoreboardIncrementalMarker scoreboardIncrementalMarker; + @Inject protected ContestSubmissionRoleChecker submissionRoleChecker; + @Inject protected ContestProblemRoleChecker problemRoleChecker; + @Inject protected ContestModuleStore moduleStore; + @Inject protected ContestContestantStore contestantStore; + @Inject protected ContestSupervisorStore supervisorStore; + @Inject protected ContestProblemStore problemStore; + @Inject protected UserClient userClient; + @Inject protected ProblemClient problemClient; + + @Inject public ContestSubmissionResource() {} - @Override + @GET + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) public ContestSubmissionsResponse getSubmissions( - AuthHeader authHeader, - String contestJid, - Optional username, - Optional problemAlias, - Optional pageNumber) { + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @QueryParam("contestJid") String contestJid, + @QueryParam("username") Optional username, + @QueryParam("problemAlias") Optional problemAlias, + @QueryParam("page") Optional pageNumber) { String actorJid = actorChecker.check(authHeader); Contest contest = checkFound(contestStore.getContestByJid(contestJid)); @@ -202,12 +167,14 @@ public ContestSubmissionsResponse getSubmissions( .build(); } - @Override + @GET + @Path("/id/{submissionId}") + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) public SubmissionWithSourceResponse getSubmissionWithSourceById( - AuthHeader authHeader, - long submissionId, - Optional language) { + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("submissionId") long submissionId, + @QueryParam("language") Optional language) { String actorJid = actorChecker.check(authHeader); Submission submission = checkFound(submissionStore.getSubmissionById(submissionId)); @@ -236,9 +203,15 @@ public SubmissionWithSourceResponse getSubmissionWithSourceById( .build(); } - @Override + @GET + @Path("/info") + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) - public SubmissionInfo getSubmissionInfo(String contestJid, String userJid, String problemJid) { + public SubmissionInfo getSubmissionInfo( + @QueryParam("contestJid") String contestJid, + @QueryParam("userJid") String userJid, + @QueryParam("problemJid") String problemJid) { + Contest contest = checkFound(contestStore.getContestByJid(contestJid)); checkAllowed(submissionRoleChecker.canViewAll(contest)); @@ -249,9 +222,15 @@ public SubmissionInfo getSubmissionInfo(String contestJid, String userJid, Strin return new SubmissionInfo.Builder().id(submission.getId()).profile(profile).build(); } - @Override + @GET + @Path("/image") + @Produces("image/png") @UnitOfWork(readOnly = true) - public Response getSubmissionSourceImage(String contestJid, String userJid, String problemJid) { + public Response getSubmissionSourceImage( + @QueryParam("contestJid") String contestJid, + @QueryParam("userJid") String userJid, + @QueryParam("problemJid") String problemJid) { + Contest contest = checkFound(contestStore.getContestByJid(contestJid)); checkAllowed(submissionRoleChecker.canViewAll(contest)); @@ -262,9 +241,15 @@ public Response getSubmissionSourceImage(String contestJid, String userJid, Stri return buildLightImageResponseFromText(source, Date.from(submission.getTime())); } - @Override + @GET + @Path("/image/dark") + @Produces("image/png") @UnitOfWork(readOnly = true) - public Response getSubmissionSourceDarkImage(String contestJid, String userJid, String problemJid) { + public Response getSubmissionSourceDarkImage( + @QueryParam("contestJid") String contestJid, + @QueryParam("userJid") String userJid, + @QueryParam("problemJid") String problemJid) { + Contest contest = checkFound(contestStore.getContestByJid(contestJid)); checkAllowed(submissionRoleChecker.canViewAll(contest)); @@ -276,10 +261,12 @@ public Response getSubmissionSourceDarkImage(String contestJid, String userJid, } @POST - @Path("/") @Consumes(MULTIPART_FORM_DATA) @UnitOfWork - public void createSubmission(@HeaderParam(AUTHORIZATION) AuthHeader authHeader, FormDataMultiPart parts) { + public void createSubmission( + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + FormDataMultiPart parts) { + String actorJid = actorChecker.check(authHeader); String contestJid = checkNotNull(parts.getField("contestJid"), "contestJid").getValue(); String problemJid = checkNotNull(parts.getField("problemJid"), "problemJid").getValue(); @@ -308,9 +295,13 @@ public void createSubmission(@HeaderParam(AUTHORIZATION) AuthHeader authHeader, contestLogger.log(contestJid, "SUBMIT", submission.getJid(), problemJid); } - @Override + @POST + @Path("/{submissionJid}/regrade") @UnitOfWork - public void regradeSubmission(AuthHeader authHeader, String submissionJid) { + public void regradeSubmission( + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("submissionJid") String submissionJid) { + String actorJid = actorChecker.check(authHeader); Submission submission = checkFound(submissionStore.getSubmissionByJid(submissionJid)); Contest contest = checkFound(contestStore.getContestByJid(submission.getContainerJid())); @@ -324,13 +315,14 @@ public void regradeSubmission(AuthHeader authHeader, String submissionJid) { contestLogger.log(contest.getJid(), "REGRADE_SUBMISSION", submissionJid, submission.getProblemJid()); } - @Override + @POST + @Path("/regrade") @UnitOfWork public void regradeSubmissions( - AuthHeader authHeader, - String contestJid, - Optional username, - Optional problemAlias) { + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @QueryParam("contestJid") String contestJid, + @QueryParam("username") Optional username, + @QueryParam("problemAlias") Optional problemAlias) { String actorJid = actorChecker.check(authHeader); Contest contest = checkFound(contestStore.getContestByJid(contestJid)); diff --git a/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/supervisor/ContestSupervisorResource.java b/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/supervisor/ContestSupervisorResource.java index 2a5d77b20..e84b3cb00 100644 --- a/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/supervisor/ContestSupervisorResource.java +++ b/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/supervisor/ContestSupervisorResource.java @@ -1,6 +1,8 @@ package judgels.uriel.contest.supervisor; import static com.google.common.base.Preconditions.checkArgument; +import static javax.ws.rs.core.HttpHeaders.AUTHORIZATION; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static judgels.service.ServiceUtils.checkAllowed; import static judgels.service.ServiceUtils.checkFound; @@ -12,6 +14,14 @@ import java.util.Set; import java.util.stream.Collectors; import javax.inject.Inject; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; import judgels.jophiel.api.profile.Profile; import judgels.jophiel.user.UserClient; import judgels.persistence.api.Page; @@ -19,7 +29,6 @@ import judgels.service.api.actor.AuthHeader; import judgels.uriel.api.contest.Contest; import judgels.uriel.api.contest.supervisor.ContestSupervisor; -import judgels.uriel.api.contest.supervisor.ContestSupervisorService; import judgels.uriel.api.contest.supervisor.ContestSupervisorUpsertData; import judgels.uriel.api.contest.supervisor.ContestSupervisorsDeleteResponse; import judgels.uriel.api.contest.supervisor.ContestSupervisorsResponse; @@ -28,36 +37,27 @@ import judgels.uriel.contest.ContestStore; import judgels.uriel.contest.log.ContestLogger; -public class ContestSupervisorResource implements ContestSupervisorService { +@Path("/api/v2/contests/{contestJid}/supervisors") +public class ContestSupervisorResource { private static final int PAGE_SIZE = 250; - private final ActorChecker actorChecker; - private final ContestStore contestStore; - private final ContestLogger contestLogger; - private final ContestRoleChecker roleChecker; - private final ContestSupervisorStore supervisorStore; - private final UserClient userClient; - - @Inject - public ContestSupervisorResource( - ActorChecker actorChecker, - ContestStore contestStore, - ContestLogger contestLogger, - ContestRoleChecker roleChecker, - ContestSupervisorStore supervisorStore, - UserClient userClient) { - - this.actorChecker = actorChecker; - this.contestStore = contestStore; - this.contestLogger = contestLogger; - this.roleChecker = roleChecker; - this.supervisorStore = supervisorStore; - this.userClient = userClient; - } + @Inject protected ActorChecker actorChecker; + @Inject protected ContestStore contestStore; + @Inject protected ContestLogger contestLogger; + @Inject protected ContestRoleChecker roleChecker; + @Inject protected ContestSupervisorStore supervisorStore; + @Inject protected UserClient userClient; + + @Inject public ContestSupervisorResource() {} - @Override + @GET + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) - public ContestSupervisorsResponse getSupervisors(AuthHeader authHeader, String contestJid, Optional pageNumber) { + public ContestSupervisorsResponse getSupervisors( + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("contestJid") String contestJid, + @QueryParam("page") Optional pageNumber) { + String actorJid = actorChecker.check(authHeader); Contest contest = checkFound(contestStore.getContestByJid(contestJid)); checkAllowed(roleChecker.canSupervise(actorJid, contest)); @@ -75,11 +75,14 @@ public ContestSupervisorsResponse getSupervisors(AuthHeader authHeader, String c .build(); } - @Override + @POST + @Path("/batch-upsert") + @Consumes(APPLICATION_JSON) + @Produces(APPLICATION_JSON) @UnitOfWork public ContestSupervisorsUpsertResponse upsertSupervisors( - AuthHeader authHeader, - String contestJid, + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("contestJid") String contestJid, ContestSupervisorUpsertData data) { String actorJid = actorChecker.check(authHeader); @@ -109,11 +112,14 @@ public ContestSupervisorsUpsertResponse upsertSupervisors( .build(); } - @Override + @POST + @Path("/batch-delete") + @Consumes(APPLICATION_JSON) + @Produces(APPLICATION_JSON) @UnitOfWork public ContestSupervisorsDeleteResponse deleteSupervisors( - AuthHeader authHeader, - String contestJid, + @HeaderParam(AUTHORIZATION) AuthHeader authHeader, + @PathParam("contestJid") String contestJid, Set usernames) { String actorJid = actorChecker.check(authHeader); diff --git a/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/web/ContestWebResource.java b/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/web/ContestWebResource.java index 821d0b4f5..92abb6e21 100644 --- a/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/web/ContestWebResource.java +++ b/judgels-backends/judgels-server-app/src/main/java/judgels/uriel/contest/web/ContestWebResource.java @@ -1,42 +1,43 @@ package judgels.uriel.contest.web; +import static javax.ws.rs.core.HttpHeaders.AUTHORIZATION; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static judgels.service.ServiceUtils.checkAllowed; import static judgels.service.ServiceUtils.checkFound; import io.dropwizard.hibernate.UnitOfWork; import java.util.Optional; import javax.inject.Inject; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; import judgels.service.actor.ActorChecker; import judgels.service.api.actor.AuthHeader; import judgels.uriel.api.contest.Contest; import judgels.uriel.api.contest.web.ContestWebConfig; -import judgels.uriel.api.contest.web.ContestWebService; import judgels.uriel.api.contest.web.ContestWithWebConfig; import judgels.uriel.contest.ContestRoleChecker; import judgels.uriel.contest.ContestStore; -public class ContestWebResource implements ContestWebService { - private final ActorChecker actorChecker; - private final ContestRoleChecker contestRoleChecker; - private final ContestStore contestStore; - private final ContestWebConfigFetcher webConfigFetcher; +@Path("/api/v2/contest-web") +public class ContestWebResource { + @Inject protected ActorChecker actorChecker; + @Inject protected ContestRoleChecker contestRoleChecker; + @Inject protected ContestStore contestStore; + @Inject protected ContestWebConfigFetcher webConfigFetcher; - @Inject - public ContestWebResource( - ActorChecker actorChecker, - ContestRoleChecker contestRoleChecker, - ContestStore contestStore, - ContestWebConfigFetcher webConfigFetcher) { + @Inject public ContestWebResource() {} - this.actorChecker = actorChecker; - this.contestRoleChecker = contestRoleChecker; - this.contestStore = contestStore; - this.webConfigFetcher = webConfigFetcher; - } - - @Override + @GET + @Path("/slug/{contestSlug}/with-config") + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) - public ContestWithWebConfig getContestBySlugWithWebConfig(Optional authHeader, String contestSlug) { + public ContestWithWebConfig getContestBySlugWithWebConfig( + @HeaderParam(AUTHORIZATION) Optional authHeader, + @PathParam("contestSlug") String contestSlug) { + String actorJid = actorChecker.check(authHeader); Contest contest = checkFound(contestStore.getContestBySlug(contestSlug)); checkAllowed(contestRoleChecker.canView(actorJid, contest)); @@ -46,9 +47,14 @@ public ContestWithWebConfig getContestBySlugWithWebConfig(Optional a .build(); } - @Override + @GET + @Path("/{contestJid}/with-config") + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) - public ContestWithWebConfig getContestByJidWithWebConfig(Optional authHeader, String contestJid) { + public ContestWithWebConfig getContestByJidWithWebConfig( + @HeaderParam(AUTHORIZATION) Optional authHeader, + @PathParam("contestJid") String contestJid) { + String actorJid = actorChecker.check(authHeader); Contest contest = checkFound(contestStore.getContestByJid(contestJid)); checkAllowed(contestRoleChecker.canView(actorJid, contest)); @@ -58,9 +64,14 @@ public ContestWithWebConfig getContestByJidWithWebConfig(Optional au .build(); } - @Override + @GET + @Path("/{contestJid}/config") + @Produces(APPLICATION_JSON) @UnitOfWork(readOnly = true) - public ContestWebConfig getWebConfig(Optional authHeader, String contestJid) { + public ContestWebConfig getWebConfig( + @HeaderParam(AUTHORIZATION) Optional authHeader, + @PathParam("contestJid") String contestJid) { + String actorJid = actorChecker.check(authHeader); Contest contest = checkFound(contestStore.getContestByJid(contestJid)); checkAllowed(contestRoleChecker.canView(actorJid, contest));