parent
							
								
									73d6058e18
								
							
						
					
					
						commit
						731f3b70ca
					
				| @ -0,0 +1,4 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.rpc.exception; | ||||||
|  | 
 | ||||||
|  | public class CommonRpcException extends RuntimeException { | ||||||
|  | } | ||||||
| @ -1,59 +0,0 @@ | |||||||
| <?xml version="1.0" encoding="UTF-8"?> |  | ||||||
| <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" |  | ||||||
|     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> |  | ||||||
|   <modelVersion>4.0.0</modelVersion> |  | ||||||
|   <groupId>cn.wustlinghang.wusthelper</groupId> |  | ||||||
|   <artifactId>graduate</artifactId> |  | ||||||
|   <version>0.0.1-SNAPSHOT</version> |  | ||||||
|   <dependencies> |  | ||||||
|     <dependency> |  | ||||||
|       <groupId>cn.wustlinghang</groupId> |  | ||||||
|       <artifactId>mywust-core</artifactId> |  | ||||||
|       <version>0.0.2-SNAPSHOT</version> |  | ||||||
|       <scope>compile</scope> |  | ||||||
|     </dependency> |  | ||||||
|     <dependency> |  | ||||||
|       <groupId>cn.wustlinghang</groupId> |  | ||||||
|       <artifactId>mywust-network-okhttp</artifactId> |  | ||||||
|       <version>0.0.2-SNAPSHOT</version> |  | ||||||
|       <scope>compile</scope> |  | ||||||
|     </dependency> |  | ||||||
|     <dependency> |  | ||||||
|       <groupId>cn.wustlinghang.wusthelper</groupId> |  | ||||||
|       <artifactId>common</artifactId> |  | ||||||
|       <version>0.0.1-SNAPSHOT</version> |  | ||||||
|       <scope>compile</scope> |  | ||||||
|     </dependency> |  | ||||||
|     <dependency> |  | ||||||
|       <groupId>jakarta.annotation</groupId> |  | ||||||
|       <artifactId>jakarta.annotation-api</artifactId> |  | ||||||
|       <version>2.1.1</version> |  | ||||||
|       <scope>compile</scope> |  | ||||||
|     </dependency> |  | ||||||
|     <dependency> |  | ||||||
|       <groupId>javax.annotation</groupId> |  | ||||||
|       <artifactId>javax.annotation-api</artifactId> |  | ||||||
|       <version>1.3.2</version> |  | ||||||
|       <scope>compile</scope> |  | ||||||
|     </dependency> |  | ||||||
|     <dependency> |  | ||||||
|       <groupId>org.projectlombok</groupId> |  | ||||||
|       <artifactId>lombok</artifactId> |  | ||||||
|       <version>1.18.26</version> |  | ||||||
|       <scope>provided</scope> |  | ||||||
|     </dependency> |  | ||||||
|   </dependencies> |  | ||||||
|   <repositories> |  | ||||||
|     <repository> |  | ||||||
|       <id>central</id> |  | ||||||
|       <url>https://repo1.maven.org/maven2</url> |  | ||||||
|     </repository> |  | ||||||
|     <repository> |  | ||||||
|       <snapshots> |  | ||||||
|         <enabled>true</enabled> |  | ||||||
|       </snapshots> |  | ||||||
|       <id>github</id> |  | ||||||
|       <url>https://maven.pkg.github.com/LingHangStudio/mywust</url> |  | ||||||
|     </repository> |  | ||||||
|   </repositories> |  | ||||||
| </project> |  | ||||||
| @ -0,0 +1,54 @@ | |||||||
|  | #### | ||||||
|  | # This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode | ||||||
|  | # | ||||||
|  | # Before building the container image run: | ||||||
|  | # | ||||||
|  | # ./mvnw package | ||||||
|  | # | ||||||
|  | # Then, build the image with: | ||||||
|  | # | ||||||
|  | # docker build -f src/main/docker/Dockerfile.jvm -t quarkus/getting-started-jvm . | ||||||
|  | # | ||||||
|  | # Then run the container using: | ||||||
|  | # | ||||||
|  | # docker run -i --rm -p 8080:8080 quarkus/getting-started-jvm | ||||||
|  | # | ||||||
|  | # If you want to include the debug port into your docker image | ||||||
|  | # you will have to expose the debug port (default 5005) like this :  EXPOSE 8080 5050 | ||||||
|  | # | ||||||
|  | # Then run the container using : | ||||||
|  | # | ||||||
|  | # docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" quarkus/getting-started-jvm | ||||||
|  | # | ||||||
|  | ### | ||||||
|  | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.3  | ||||||
|  | 
 | ||||||
|  | ARG JAVA_PACKAGE=java-11-openjdk-headless | ||||||
|  | ARG RUN_JAVA_VERSION=1.3.8 | ||||||
|  | ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' | ||||||
|  | # Install java and the run-java script | ||||||
|  | # Also set up permissions for user `1001` | ||||||
|  | RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \ | ||||||
|  |     && microdnf update \ | ||||||
|  |     && microdnf clean all \ | ||||||
|  |     && mkdir /deployments \ | ||||||
|  |     && chown 1001 /deployments \ | ||||||
|  |     && chmod "g+rwX" /deployments \ | ||||||
|  |     && chown 1001:root /deployments \ | ||||||
|  |     && curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \ | ||||||
|  |     && chown 1001 /deployments/run-java.sh \ | ||||||
|  |     && chmod 540 /deployments/run-java.sh \ | ||||||
|  |     && echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/lib/security/java.security | ||||||
|  | 
 | ||||||
|  | # Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size. | ||||||
|  | ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" | ||||||
|  | # We make four distinct layers so if there are application changes the library layers can be re-used | ||||||
|  | COPY --chown=1001 target/quarkus-app/lib/ /deployments/lib/ | ||||||
|  | COPY --chown=1001 target/quarkus-app/*.jar /deployments/ | ||||||
|  | COPY --chown=1001 target/quarkus-app/app/ /deployments/app/ | ||||||
|  | COPY --chown=1001 target/quarkus-app/quarkus/ /deployments/quarkus/ | ||||||
|  | 
 | ||||||
|  | EXPOSE 8080 | ||||||
|  | USER 1001 | ||||||
|  | 
 | ||||||
|  | ENTRYPOINT [ "/deployments/run-java.sh" ] | ||||||
| @ -0,0 +1,51 @@ | |||||||
|  | #### | ||||||
|  | # This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode | ||||||
|  | # | ||||||
|  | # Before building the container image run: | ||||||
|  | # | ||||||
|  | # ./mvnw package -Dquarkus.package.type=legacy-jar | ||||||
|  | # | ||||||
|  | # Then, build the image with: | ||||||
|  | # | ||||||
|  | # docker build -f src/main/docker/Dockerfile.legacy-jar -t quarkus/getting-started-legacy-jar . | ||||||
|  | # | ||||||
|  | # Then run the container using: | ||||||
|  | # | ||||||
|  | # docker run -i --rm -p 8080:8080 quarkus/getting-started-legacy-jar | ||||||
|  | # | ||||||
|  | # If you want to include the debug port into your docker image | ||||||
|  | # you will have to expose the debug port (default 5005) like this :  EXPOSE 8080 5050 | ||||||
|  | # | ||||||
|  | # Then run the container using : | ||||||
|  | # | ||||||
|  | # docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" quarkus/getting-started-legacy-jar | ||||||
|  | # | ||||||
|  | ### | ||||||
|  | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.3  | ||||||
|  | 
 | ||||||
|  | ARG JAVA_PACKAGE=java-11-openjdk-headless | ||||||
|  | ARG RUN_JAVA_VERSION=1.3.8 | ||||||
|  | ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' | ||||||
|  | # Install java and the run-java script | ||||||
|  | # Also set up permissions for user `1001` | ||||||
|  | RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \ | ||||||
|  |     && microdnf update \ | ||||||
|  |     && microdnf clean all \ | ||||||
|  |     && mkdir /deployments \ | ||||||
|  |     && chown 1001 /deployments \ | ||||||
|  |     && chmod "g+rwX" /deployments \ | ||||||
|  |     && chown 1001:root /deployments \ | ||||||
|  |     && curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \ | ||||||
|  |     && chown 1001 /deployments/run-java.sh \ | ||||||
|  |     && chmod 540 /deployments/run-java.sh \ | ||||||
|  |     && echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/lib/security/java.security | ||||||
|  | 
 | ||||||
|  | # Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size. | ||||||
|  | ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" | ||||||
|  | COPY target/lib/* /deployments/lib/ | ||||||
|  | COPY target/*-runner.jar /deployments/app.jar | ||||||
|  | 
 | ||||||
|  | EXPOSE 8080 | ||||||
|  | USER 1001 | ||||||
|  | 
 | ||||||
|  | ENTRYPOINT [ "/deployments/run-java.sh" ] | ||||||
| @ -0,0 +1,27 @@ | |||||||
|  | #### | ||||||
|  | # This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode | ||||||
|  | # | ||||||
|  | # Before building the container image run: | ||||||
|  | # | ||||||
|  | # ./mvnw package -Pnative | ||||||
|  | # | ||||||
|  | # Then, build the image with: | ||||||
|  | # | ||||||
|  | # docker build -f src/main/docker/Dockerfile.native -t quarkus/getting-started . | ||||||
|  | # | ||||||
|  | # Then run the container using: | ||||||
|  | # | ||||||
|  | # docker run -i --rm -p 8080:8080 quarkus/getting-started | ||||||
|  | # | ||||||
|  | ### | ||||||
|  | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.3 | ||||||
|  | WORKDIR /work/ | ||||||
|  | RUN chown 1001 /work \ | ||||||
|  |     && chmod "g+rwX" /work \ | ||||||
|  |     && chown 1001:root /work | ||||||
|  | COPY --chown=1001:root target/*-runner /work/application | ||||||
|  | 
 | ||||||
|  | EXPOSE 8080 | ||||||
|  | USER 1001 | ||||||
|  | 
 | ||||||
|  | CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] | ||||||
| @ -0,0 +1,23 @@ | |||||||
|  | #### | ||||||
|  | # This Dockerfile is used in order to build a distroless container that runs the Quarkus application in native (no JVM) mode | ||||||
|  | # | ||||||
|  | # Before building the container image run: | ||||||
|  | # | ||||||
|  | # ./mvnw package -Pnative | ||||||
|  | # | ||||||
|  | # Then, build the image with: | ||||||
|  | # | ||||||
|  | # docker build -f src/main/docker/Dockerfile.native-micro -t quarkus/getting-started . | ||||||
|  | # | ||||||
|  | # Then run the container using: | ||||||
|  | # | ||||||
|  | # docker run -i --rm -p 8080:8080 quarkus/getting-started | ||||||
|  | # | ||||||
|  | ### | ||||||
|  | FROM quay.io/quarkus/quarkus-micro-image:1.0 | ||||||
|  | COPY target/*-runner /application | ||||||
|  | 
 | ||||||
|  | EXPOSE 8080 | ||||||
|  | USER 1001 | ||||||
|  | 
 | ||||||
|  | CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] | ||||||
| @ -1,7 +0,0 @@ | |||||||
| package cn.wustlinghang; |  | ||||||
| 
 |  | ||||||
| public class Main { |  | ||||||
|     public static void main(String[] args) { |  | ||||||
|         System.out.println("Hello world!"); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -0,0 +1,32 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.graduate.api.json; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.mywust.exception.ApiException; | ||||||
|  | import cn.wustlinghang.wusthelper.internal.graduate.services.LoginService; | ||||||
|  | import jakarta.validation.constraints.NotNull; | ||||||
|  | import jakarta.ws.rs.GET; | ||||||
|  | import jakarta.ws.rs.Path; | ||||||
|  | import jakarta.ws.rs.QueryParam; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | 
 | ||||||
|  | @Path("/cookie") | ||||||
|  | public class CookieApi { | ||||||
|  |     private final LoginService loginService; | ||||||
|  | 
 | ||||||
|  |     public CookieApi(LoginService loginService) { | ||||||
|  |         this.loginService = loginService; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @GET | ||||||
|  |     @Path("/") | ||||||
|  |     public String login(@QueryParam("username") @NotNull String username, | ||||||
|  |                         @QueryParam("password") @NotNull String password) throws IOException, ApiException { | ||||||
|  |         return loginService.login(username, password, false); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @GET | ||||||
|  |     @Path("/verify") | ||||||
|  |     public Boolean verify(@QueryParam("cookie") @NotNull String cookie) throws IOException { | ||||||
|  |         return loginService.verify(cookie); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,52 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.graduate.api.json; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.mywust.core.parser.undergraduate.UndergradCourseTableParser; | ||||||
|  | import cn.wustlinghang.mywust.core.request.service.undergraduate.UndergradCourseTableApiService; | ||||||
|  | import cn.wustlinghang.mywust.data.global.Course; | ||||||
|  | import cn.wustlinghang.mywust.data.global.StudentInfo; | ||||||
|  | import cn.wustlinghang.mywust.exception.ApiException; | ||||||
|  | import cn.wustlinghang.mywust.exception.ParseException; | ||||||
|  | import cn.wustlinghang.wusthelper.rpc.response.RpcResponse; | ||||||
|  | import jakarta.enterprise.context.ApplicationScoped; | ||||||
|  | import jakarta.validation.constraints.NotNull; | ||||||
|  | import jakarta.ws.rs.GET; | ||||||
|  | import jakarta.ws.rs.POST; | ||||||
|  | import jakarta.ws.rs.Path; | ||||||
|  | import jakarta.ws.rs.QueryParam; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | import java.util.List; | ||||||
|  | 
 | ||||||
|  | @Path("/course_table") | ||||||
|  | @ApplicationScoped | ||||||
|  | public class CourseTableApi { | ||||||
|  |     private final UndergradCourseTableApiService studentInfoApiService; | ||||||
|  |     private final UndergradCourseTableParser studentInfoPageParser; | ||||||
|  | 
 | ||||||
|  |     public CourseTableApi(UndergradCourseTableApiService studentInfoApiService, | ||||||
|  |                           UndergradCourseTableParser studentInfoPageParser) { | ||||||
|  |         this.studentInfoApiService = studentInfoApiService; | ||||||
|  |         this.studentInfoPageParser = studentInfoPageParser; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @GET | ||||||
|  |     @Path("/") | ||||||
|  |     public List<Course> get(@QueryParam("cookie") @NotNull String cookie, @QueryParam("term") String term) | ||||||
|  |             throws IOException, ApiException, ParseException { | ||||||
|  |         String html = studentInfoApiService.getPage(term, cookie); | ||||||
|  |         return this.parse(html); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @GET | ||||||
|  |     @Path("/agent") | ||||||
|  |     public String agent(@QueryParam("cookie") @NotNull String cookie, @QueryParam("term") String term) | ||||||
|  |             throws IOException, ApiException { | ||||||
|  |         return studentInfoApiService.getPage(term, cookie); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @POST | ||||||
|  |     @Path("/parse") | ||||||
|  |     public List<Course> parse(String html) throws ParseException { | ||||||
|  |         return studentInfoPageParser.parse(html); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,54 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.graduate.api.json; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.mywust.core.parser.undergraduate.UndergradCreditStatusParser; | ||||||
|  | import cn.wustlinghang.mywust.core.request.service.undergraduate.UndergradCreditStatusApiService; | ||||||
|  | import cn.wustlinghang.mywust.data.global.StudentInfo; | ||||||
|  | import cn.wustlinghang.mywust.exception.ApiException; | ||||||
|  | import cn.wustlinghang.mywust.exception.ParseException; | ||||||
|  | import cn.wustlinghang.mywust.network.RequestClientOption; | ||||||
|  | import cn.wustlinghang.wusthelper.rpc.response.RpcResponse; | ||||||
|  | import jakarta.enterprise.context.ApplicationScoped; | ||||||
|  | import jakarta.validation.constraints.NotNull; | ||||||
|  | import jakarta.ws.rs.GET; | ||||||
|  | import jakarta.ws.rs.POST; | ||||||
|  | import jakarta.ws.rs.Path; | ||||||
|  | import jakarta.ws.rs.QueryParam; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | 
 | ||||||
|  | @Path("/credit_status") | ||||||
|  | @ApplicationScoped | ||||||
|  | public class CreditStatusApi { | ||||||
|  |     private final UndergradCreditStatusApiService creditStatusApiService; | ||||||
|  |     private final UndergradCreditStatusParser creditStatusParser; | ||||||
|  | 
 | ||||||
|  |     private final RequestClientOption option; | ||||||
|  | 
 | ||||||
|  |     public CreditStatusApi(UndergradCreditStatusApiService creditStatusApiService, | ||||||
|  |                            UndergradCreditStatusParser creditStatusParser, | ||||||
|  |                            RequestClientOption option) { | ||||||
|  |         this.creditStatusApiService = creditStatusApiService; | ||||||
|  |         this.creditStatusParser = creditStatusParser; | ||||||
|  |         this.option = option; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @GET | ||||||
|  |     @Path("/") | ||||||
|  |     public String get(String cookie) throws IOException, ApiException, ParseException { | ||||||
|  |         String html =  creditStatusApiService.getPage(cookie, option, false); | ||||||
|  |         return this.parse(html); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @GET | ||||||
|  |     @Path("/agent") | ||||||
|  |     public String agent(@QueryParam("cookie") @NotNull String cookie) | ||||||
|  |             throws IOException, ApiException { | ||||||
|  |         return creditStatusApiService.getPage(cookie, option, false); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @POST | ||||||
|  |     @Path("/parse") | ||||||
|  |     public String parse(String html) throws ParseException { | ||||||
|  |         return creditStatusParser.parse(html); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,50 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.graduate.api.json; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.mywust.core.parser.undergraduate.UndergradScoreParser; | ||||||
|  | import cn.wustlinghang.mywust.core.request.service.undergraduate.UndergradScoreApiService; | ||||||
|  | import cn.wustlinghang.mywust.data.global.Score; | ||||||
|  | import cn.wustlinghang.mywust.data.global.StudentInfo; | ||||||
|  | import cn.wustlinghang.mywust.exception.ApiException; | ||||||
|  | import cn.wustlinghang.mywust.exception.ParseException; | ||||||
|  | import cn.wustlinghang.wusthelper.rpc.response.RpcResponse; | ||||||
|  | import jakarta.enterprise.context.ApplicationScoped; | ||||||
|  | import jakarta.validation.constraints.NotNull; | ||||||
|  | import jakarta.ws.rs.GET; | ||||||
|  | import jakarta.ws.rs.POST; | ||||||
|  | import jakarta.ws.rs.Path; | ||||||
|  | import jakarta.ws.rs.QueryParam; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | import java.util.List; | ||||||
|  | 
 | ||||||
|  | @Path("/score") | ||||||
|  | @ApplicationScoped | ||||||
|  | public class ScoreApi { | ||||||
|  |     private final UndergradScoreApiService scoreApiService; | ||||||
|  |     private final UndergradScoreParser scoreParser; | ||||||
|  | 
 | ||||||
|  |     public ScoreApi(UndergradScoreApiService scoreApiService, UndergradScoreParser scoreParser) { | ||||||
|  |         this.scoreApiService = scoreApiService; | ||||||
|  |         this.scoreParser = scoreParser; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @GET | ||||||
|  |     @Path("/") | ||||||
|  |     public List<Score> get(String cookie) throws IOException, ApiException, ParseException { | ||||||
|  |         String html =  scoreApiService.getPage(cookie); | ||||||
|  |         return this.parse(html); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @GET | ||||||
|  |     @Path("/agent") | ||||||
|  |     public String agent(@QueryParam("cookie") @NotNull String cookie) | ||||||
|  |             throws IOException, ApiException { | ||||||
|  |         return scoreApiService.getPage(cookie); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @POST | ||||||
|  |     @Path("/parse") | ||||||
|  |     public List<Score> parse(String html) throws ParseException { | ||||||
|  |         return scoreParser.parse(html); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,47 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.graduate.api.json; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.mywust.core.parser.undergraduate.UndergradStudentInfoPageParser; | ||||||
|  | import cn.wustlinghang.mywust.core.request.service.undergraduate.UndergradStudentInfoApiService; | ||||||
|  | import cn.wustlinghang.mywust.data.global.StudentInfo; | ||||||
|  | import cn.wustlinghang.mywust.exception.ApiException; | ||||||
|  | import cn.wustlinghang.mywust.exception.ParseException; | ||||||
|  | import jakarta.enterprise.context.ApplicationScoped; | ||||||
|  | import jakarta.validation.constraints.NotNull; | ||||||
|  | import jakarta.ws.rs.GET; | ||||||
|  | import jakarta.ws.rs.POST; | ||||||
|  | import jakarta.ws.rs.Path; | ||||||
|  | import jakarta.ws.rs.QueryParam; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | 
 | ||||||
|  | @Path("/student_info") | ||||||
|  | @ApplicationScoped | ||||||
|  | public class StudentInfoApi { | ||||||
|  |     private final UndergradStudentInfoApiService studentInfoApiService; | ||||||
|  |     private final UndergradStudentInfoPageParser studentInfoPageParser; | ||||||
|  | 
 | ||||||
|  |     public StudentInfoApi(UndergradStudentInfoApiService studentInfoApiService, | ||||||
|  |                           UndergradStudentInfoPageParser studentInfoPageParser) { | ||||||
|  |         this.studentInfoApiService = studentInfoApiService; | ||||||
|  |         this.studentInfoPageParser = studentInfoPageParser; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @GET | ||||||
|  |     @Path("/") | ||||||
|  |     public StudentInfo get(@QueryParam("cookie") @NotNull String cookie) throws IOException, ApiException, ParseException { | ||||||
|  |         return this.parse(this.agent(cookie)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @GET | ||||||
|  |     @Path("/agent") | ||||||
|  |     public String agent(@QueryParam("cookie") @NotNull String cookie) | ||||||
|  |             throws IOException, ApiException { | ||||||
|  |         return studentInfoApiService.getPage(cookie); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @POST | ||||||
|  |     @Path("/parse") | ||||||
|  |     public StudentInfo parse(String html) throws ParseException { | ||||||
|  |         return studentInfoPageParser.parse(html); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,47 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.graduate.api.json; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.mywust.core.parser.undergraduate.UndergradTrainingPlanPageParser; | ||||||
|  | import cn.wustlinghang.mywust.core.request.service.undergraduate.UndergradTrainingPlanApiService; | ||||||
|  | import cn.wustlinghang.mywust.exception.ApiException; | ||||||
|  | import cn.wustlinghang.mywust.exception.ParseException; | ||||||
|  | import jakarta.enterprise.context.ApplicationScoped; | ||||||
|  | import jakarta.validation.constraints.NotNull; | ||||||
|  | import jakarta.ws.rs.GET; | ||||||
|  | import jakarta.ws.rs.POST; | ||||||
|  | import jakarta.ws.rs.Path; | ||||||
|  | import jakarta.ws.rs.QueryParam; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | 
 | ||||||
|  | @Path("/training_plan") | ||||||
|  | @ApplicationScoped | ||||||
|  | public class TrainingPlanApi { | ||||||
|  |     private final UndergradTrainingPlanApiService trainingPlanApiService; | ||||||
|  |     private final UndergradTrainingPlanPageParser trainingPlanPageParser; | ||||||
|  | 
 | ||||||
|  |     public TrainingPlanApi(UndergradTrainingPlanApiService trainingPlanApiService, | ||||||
|  |                            UndergradTrainingPlanPageParser trainingPlanPageParser) { | ||||||
|  |         this.trainingPlanApiService = trainingPlanApiService; | ||||||
|  |         this.trainingPlanPageParser = trainingPlanPageParser; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @GET | ||||||
|  |     @Path("/") | ||||||
|  |     public String get(String cookie) throws IOException, ApiException, ParseException { | ||||||
|  |         String html =  trainingPlanApiService.getPage(cookie); | ||||||
|  |         return this.parse(html); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @GET | ||||||
|  |     @Path("/agent") | ||||||
|  |     public String agent(@QueryParam("cookie") @NotNull String cookie) | ||||||
|  |             throws IOException, ApiException { | ||||||
|  |         return trainingPlanApiService.getPage(cookie); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @POST | ||||||
|  |     @Path("/parse") | ||||||
|  |     public String parse(String html) throws ParseException { | ||||||
|  |         return trainingPlanPageParser.parse(html); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,14 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.graduate.api.json.handler; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.mywust.exception.ApiException; | ||||||
|  | import jakarta.ws.rs.core.Response; | ||||||
|  | import jakarta.ws.rs.ext.ExceptionMapper; | ||||||
|  | import jakarta.ws.rs.ext.Provider; | ||||||
|  | 
 | ||||||
|  | @Provider | ||||||
|  | public class ApiExceptionHandler extends ExceptionHandlerBase implements ExceptionMapper<ApiException> { | ||||||
|  |     @Override | ||||||
|  |     public Response toResponse(ApiException e) { | ||||||
|  |         return super.toResponse(e.getCodeValue(), e.toString(), "ApiExceptionHandler"); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,21 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.graduate.api.json.handler; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.wusthelper.rpc.response.ResponseCode; | ||||||
|  | import jakarta.ws.rs.core.Response; | ||||||
|  | import jakarta.ws.rs.ext.ExceptionMapper; | ||||||
|  | import jakarta.ws.rs.ext.Provider; | ||||||
|  | import lombok.extern.slf4j.Slf4j; | ||||||
|  | 
 | ||||||
|  | @Slf4j | ||||||
|  | @Provider | ||||||
|  | public class DefaultExceptionHandler extends ExceptionHandlerBase implements ExceptionMapper<Exception> { | ||||||
|  |     @Override | ||||||
|  |     public Response toResponse(Exception e) { | ||||||
|  |         log.error("未知异常:", e); | ||||||
|  |         return super.toResponse( | ||||||
|  |                 ResponseCode.SERVER_INTERNAL_ERROR, | ||||||
|  |                 e.toString(), | ||||||
|  |                 "DefaultExceptionHandler" | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,33 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.graduate.api.json.handler; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.wusthelper.rpc.response.ResponseCode; | ||||||
|  | import cn.wustlinghang.wusthelper.rpc.response.RpcResponse; | ||||||
|  | import com.fasterxml.jackson.core.JsonProcessingException; | ||||||
|  | import com.fasterxml.jackson.databind.ObjectMapper; | ||||||
|  | import jakarta.ws.rs.core.MediaType; | ||||||
|  | import jakarta.ws.rs.core.Response; | ||||||
|  | 
 | ||||||
|  | public abstract class ExceptionHandlerBase { | ||||||
|  |     public static final String EXCEPTION_HEADER_KEY = "X-exception-handler"; | ||||||
|  | 
 | ||||||
|  |     private static final ObjectMapper objectMapper = new ObjectMapper(); | ||||||
|  | 
 | ||||||
|  |     public Response toResponse(ResponseCode code, String msg, String handlerName) { | ||||||
|  |         return toResponse(code.getCode(), msg, handlerName); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Response toResponse(int code, String msg, String handlerName) { | ||||||
|  |         Object response; | ||||||
|  |         try { | ||||||
|  |             response = objectMapper.writeValueAsString(RpcResponse.error(code, msg)); | ||||||
|  |         } catch (JsonProcessingException e) { | ||||||
|  |             response = RpcResponse.error(ResponseCode.SERVER_INTERNAL_ERROR); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return Response.status(Response.Status.INTERNAL_SERVER_ERROR) | ||||||
|  |                 .entity(response) | ||||||
|  |                 .header(EXCEPTION_HEADER_KEY, handlerName) | ||||||
|  |                 .type(MediaType.APPLICATION_JSON) | ||||||
|  |                 .build(); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,23 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.graduate.api.json.handler; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.wusthelper.rpc.response.ResponseCode; | ||||||
|  | import jakarta.ws.rs.core.Response; | ||||||
|  | import jakarta.ws.rs.ext.ExceptionMapper; | ||||||
|  | import jakarta.ws.rs.ext.Provider; | ||||||
|  | import lombok.extern.slf4j.Slf4j; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | 
 | ||||||
|  | @Slf4j | ||||||
|  | @Provider | ||||||
|  | public class IOExceptionHandler extends ExceptionHandlerBase implements ExceptionMapper<IOException> { | ||||||
|  |     @Override | ||||||
|  |     public Response toResponse(IOException e) { | ||||||
|  |         log.error("IO异常:", e); | ||||||
|  |         return super.toResponse( | ||||||
|  |                 ResponseCode.SERVER_INTERNAL_ERROR, | ||||||
|  |                 e.toString(), | ||||||
|  |                 "IOExceptionHandler" | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,22 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.graduate.api.json.handler; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.mywust.exception.ParseException; | ||||||
|  | import cn.wustlinghang.wusthelper.rpc.response.ResponseCode; | ||||||
|  | import jakarta.ws.rs.core.Response; | ||||||
|  | import jakarta.ws.rs.ext.ExceptionMapper; | ||||||
|  | import jakarta.ws.rs.ext.Provider; | ||||||
|  | import lombok.extern.slf4j.Slf4j; | ||||||
|  | 
 | ||||||
|  | @Slf4j | ||||||
|  | @Provider | ||||||
|  | public class ParseExceptionHandler extends ExceptionHandlerBase implements ExceptionMapper<ParseException> { | ||||||
|  |     @Override | ||||||
|  |     public Response toResponse(ParseException e) { | ||||||
|  |         log.error("解析异常:", e); | ||||||
|  |         return super.toResponse( | ||||||
|  |                 ResponseCode.SERVER_INTERNAL_ERROR, | ||||||
|  |                 e.toString(), | ||||||
|  |                 "ParseExceptionHandler" | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,22 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.graduate.api.json.handler; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.wusthelper.rpc.response.ResponseCode; | ||||||
|  | import jakarta.validation.ValidationException; | ||||||
|  | import jakarta.ws.rs.core.Response; | ||||||
|  | import jakarta.ws.rs.ext.ExceptionMapper; | ||||||
|  | import jakarta.ws.rs.ext.Provider; | ||||||
|  | import lombok.extern.slf4j.Slf4j; | ||||||
|  | 
 | ||||||
|  | @Slf4j | ||||||
|  | @Provider | ||||||
|  | public class ValidationExceptionHandler extends ExceptionHandlerBase | ||||||
|  |         implements ExceptionMapper<ValidationException> { | ||||||
|  |     @Override | ||||||
|  |     public Response toResponse(ValidationException e) { | ||||||
|  |         return super.toResponse( | ||||||
|  |                 ResponseCode.PARAM_WRONG, | ||||||
|  |                 "参数错误:" + e.toString(), | ||||||
|  |                 "ValidationExceptionHandler" | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,36 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.graduate.api.json.interceptor; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.wusthelper.internal.graduate.api.json.handler.ExceptionHandlerBase; | ||||||
|  | import cn.wustlinghang.wusthelper.rpc.response.RpcResponse; | ||||||
|  | import com.fasterxml.jackson.databind.ObjectMapper; | ||||||
|  | import jakarta.ws.rs.WebApplicationException; | ||||||
|  | import jakarta.ws.rs.core.HttpHeaders; | ||||||
|  | import jakarta.ws.rs.core.MediaType; | ||||||
|  | import jakarta.ws.rs.ext.Provider; | ||||||
|  | import jakarta.ws.rs.ext.WriterInterceptor; | ||||||
|  | import jakarta.ws.rs.ext.WriterInterceptorContext; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | 
 | ||||||
|  | @Provider | ||||||
|  | public class ResponseWrapperInterceptor implements WriterInterceptor { | ||||||
|  |     private final ObjectMapper objectMapper; | ||||||
|  | 
 | ||||||
|  |     public ResponseWrapperInterceptor(ObjectMapper objectMapper) { | ||||||
|  |         this.objectMapper = objectMapper; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException { | ||||||
|  |         boolean hasException = context.getHeaders().get(ExceptionHandlerBase.EXCEPTION_HEADER_KEY) != null; | ||||||
|  |         if (!hasException) { | ||||||
|  |             Object data = context.getEntity(); | ||||||
|  |             RpcResponse<Object> wrappedResponse = RpcResponse.success(data); | ||||||
|  |             String json = objectMapper.writeValueAsString(wrappedResponse); | ||||||
|  |             context.getHeaders().putSingle(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON); | ||||||
|  |             context.setEntity(json); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         context.proceed(); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,12 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.graduate.bean; | ||||||
|  | 
 | ||||||
|  | import com.fasterxml.jackson.databind.ObjectMapper; | ||||||
|  | import jakarta.enterprise.context.ApplicationScoped; | ||||||
|  | import jakarta.inject.Singleton; | ||||||
|  | 
 | ||||||
|  | public class JacksonBean { | ||||||
|  |     @ApplicationScoped | ||||||
|  |     public ObjectMapper objectMapper() { | ||||||
|  |         return new ObjectMapper(); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,36 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.graduate.bean; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.mywust.core.parser.undergraduate.*; | ||||||
|  | import jakarta.enterprise.context.ApplicationScoped; | ||||||
|  | 
 | ||||||
|  | public class MywustParserBeans { | ||||||
|  |     @ApplicationScoped | ||||||
|  |     public UndergradCourseTableParser undergradCourseTableParser() { | ||||||
|  |         return new UndergradCourseTableParser(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @ApplicationScoped | ||||||
|  |     public UndergradScoreParser undergradScoreParser() { | ||||||
|  |         return new UndergradScoreParser(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @ApplicationScoped | ||||||
|  |     public UndergradStudentInfoPageParser undergradStudentInfoPageParser() { | ||||||
|  |         return new UndergradStudentInfoPageParser(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @ApplicationScoped | ||||||
|  |     public UndergradTrainingPlanPageParser undergradTrainingPlanPageParser() { | ||||||
|  |         return new UndergradTrainingPlanPageParser(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @ApplicationScoped | ||||||
|  |     public UndergradCreditStatusParser undergradCreditStatusParser() { | ||||||
|  |         return new UndergradCreditStatusParser(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @ApplicationScoped | ||||||
|  |     public UndergradExamDelayParser undergradExamDelayParser() { | ||||||
|  |         return new UndergradExamDelayParser(); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,63 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.graduate.bean; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.mywust.core.request.service.auth.UndergraduateLogin; | ||||||
|  | import cn.wustlinghang.mywust.core.request.service.undergraduate.*; | ||||||
|  | import cn.wustlinghang.mywust.network.RequestClientOption; | ||||||
|  | import cn.wustlinghang.mywust.network.Requester; | ||||||
|  | import cn.wustlinghang.mywust.network.okhttp.SimpleOkhttpRequester; | ||||||
|  | import jakarta.inject.Singleton; | ||||||
|  | 
 | ||||||
|  | public class MywustRequestAgentBeans { | ||||||
|  | 
 | ||||||
|  |     @Singleton | ||||||
|  |     public RequestClientOption requestClientOption() { | ||||||
|  |         RequestClientOption.Proxy proxy = RequestClientOption.Proxy.builder() | ||||||
|  |                 .address("127.0.0.1") | ||||||
|  |                 .port(8080) | ||||||
|  |                 .build(); | ||||||
|  |         RequestClientOption option = new RequestClientOption(); | ||||||
|  | //        option.setProxy(proxy);
 | ||||||
|  | 
 | ||||||
|  |         return option; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Singleton | ||||||
|  |     public Requester requester(RequestClientOption option) { | ||||||
|  |         return new SimpleOkhttpRequester(option, true); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Singleton | ||||||
|  |     public UndergraduateLogin undergraduateLogin(Requester requester) { | ||||||
|  |         return new UndergraduateLogin(requester); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Singleton | ||||||
|  |     public UndergradCourseTableApiService undergradCourseTableApiService(Requester requester) { | ||||||
|  |         return new UndergradCourseTableApiService(requester); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Singleton | ||||||
|  |     public UndergradScoreApiService undergradScoreApiService(Requester requester) { | ||||||
|  |         return new UndergradScoreApiService(requester); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Singleton | ||||||
|  |     public UndergradStudentInfoApiService undergradStudentInfoApiService(Requester requester) { | ||||||
|  |         return new UndergradStudentInfoApiService(requester); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Singleton | ||||||
|  |     public UndergradTrainingPlanApiService undergradTrainingPlanApiService(Requester requester) { | ||||||
|  |         return new UndergradTrainingPlanApiService(requester); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Singleton | ||||||
|  |     public UndergradCreditStatusApiService undergradCreditStatusApiService(Requester requester) { | ||||||
|  |         return new UndergradCreditStatusApiService(requester); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Singleton | ||||||
|  |     public UndergradExamDelayApiService undergradExamDelayApiService(Requester requester) { | ||||||
|  |         return new UndergradExamDelayApiService(requester); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,32 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.graduate.services; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.mywust.core.request.service.auth.UndergraduateLogin; | ||||||
|  | import cn.wustlinghang.mywust.exception.ApiException; | ||||||
|  | import cn.wustlinghang.mywust.network.RequestClientOption; | ||||||
|  | import jakarta.enterprise.context.ApplicationScoped; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | 
 | ||||||
|  | @ApplicationScoped | ||||||
|  | public class LoginService { | ||||||
|  |     private final RequestClientOption option; | ||||||
|  |     private final UndergraduateLogin undergraduateLogin; | ||||||
|  | 
 | ||||||
|  |     public LoginService(RequestClientOption option, | ||||||
|  |                         UndergraduateLogin undergraduateLogin) { | ||||||
|  |         this.option = option; | ||||||
|  |         this.undergraduateLogin = undergraduateLogin; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String login(String username, String password, boolean legacy) throws IOException, ApiException { | ||||||
|  |         if (legacy) { | ||||||
|  |             return undergraduateLogin.getLoginCookieLegacy(username, password, option); | ||||||
|  |         } else { | ||||||
|  |             return undergraduateLogin.getLoginCookie(username, password, option); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public boolean verify(String cookie) throws IOException { | ||||||
|  |         return !undergraduateLogin.checkCookiesFail(cookie); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,60 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.graduate.services; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.mywust.core.parser.undergraduate.*; | ||||||
|  | import cn.wustlinghang.mywust.data.global.Course; | ||||||
|  | import cn.wustlinghang.mywust.data.global.Score; | ||||||
|  | import cn.wustlinghang.mywust.data.global.StudentInfo; | ||||||
|  | import cn.wustlinghang.mywust.data.undergrad.ExamDelayApplication; | ||||||
|  | import cn.wustlinghang.mywust.exception.ParseException; | ||||||
|  | import jakarta.enterprise.context.ApplicationScoped; | ||||||
|  | 
 | ||||||
|  | import java.util.List; | ||||||
|  | 
 | ||||||
|  | @ApplicationScoped | ||||||
|  | public class ParseService { | ||||||
|  |     private final UndergradCourseTableParser courseTableParser; | ||||||
|  |     private final UndergradScoreParser scoreParser; | ||||||
|  |     private final UndergradStudentInfoPageParser studentInfoPageParser; | ||||||
|  |     private final UndergradTrainingPlanPageParser trainingPlanPageParser; | ||||||
|  |     private final UndergradCreditStatusParser creditStatusParser; | ||||||
|  |     private final UndergradExamDelayParser examDelayParser; | ||||||
|  | 
 | ||||||
|  |     public ParseService(UndergradCourseTableParser courseTableParser, | ||||||
|  |                         UndergradScoreParser scoreParser, | ||||||
|  |                         UndergradStudentInfoPageParser studentInfoPageParser, | ||||||
|  |                         UndergradTrainingPlanPageParser trainingPlanPageParser, | ||||||
|  |                         UndergradCreditStatusParser creditStatusParser, | ||||||
|  |                         UndergradExamDelayParser examDelayParser) { | ||||||
|  | 
 | ||||||
|  |         this.courseTableParser = courseTableParser; | ||||||
|  |         this.scoreParser = scoreParser; | ||||||
|  |         this.studentInfoPageParser = studentInfoPageParser; | ||||||
|  |         this.trainingPlanPageParser = trainingPlanPageParser; | ||||||
|  |         this.creditStatusParser = creditStatusParser; | ||||||
|  |         this.examDelayParser = examDelayParser; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public List<Course> parseCourseTable(String data) throws ParseException { | ||||||
|  |         return courseTableParser.parse(data); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public List<Score> parseScore(String data) throws ParseException { | ||||||
|  |         return scoreParser.parse(data); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public StudentInfo parseStudentInfo(String data) throws ParseException { | ||||||
|  |         return studentInfoPageParser.parse(data); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String parseTrainingPlan(String data) throws ParseException { | ||||||
|  |         return trainingPlanPageParser.parse(data); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String parseCreditStatus(String data) throws ParseException { | ||||||
|  |         return creditStatusParser.parse(data); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public List<ExamDelayApplication> parseExamDelayApplications(String data) throws ParseException { | ||||||
|  |         return examDelayParser.parse(data); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,62 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.graduate.services; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.mywust.core.request.service.undergraduate.*; | ||||||
|  | import cn.wustlinghang.mywust.exception.ApiException; | ||||||
|  | import jakarta.enterprise.context.ApplicationScoped; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | 
 | ||||||
|  | @ApplicationScoped | ||||||
|  | public class RequestAgentService { | ||||||
|  |     private final UndergradCourseTableApiService courseTableApiService; | ||||||
|  |     private final UndergradScoreApiService scoreApiService; | ||||||
|  |     private final UndergradStudentInfoApiService studentInfoApiService; | ||||||
|  |     private final UndergradTrainingPlanApiService trainingPlanApiService; | ||||||
|  |     private final UndergradCreditStatusApiService creditStatusApiService; | ||||||
|  |     private final UndergradExamDelayApiService examDelayApiService; | ||||||
|  | 
 | ||||||
|  |     public RequestAgentService(UndergradCourseTableApiService courseTableApiService, | ||||||
|  |                                UndergradScoreApiService scoreApiService, | ||||||
|  |                                UndergradStudentInfoApiService studentInfoApiService, | ||||||
|  |                                UndergradTrainingPlanApiService trainingPlanApiService, | ||||||
|  |                                UndergradCreditStatusApiService creditStatusApiService, | ||||||
|  |                                UndergradExamDelayApiService examDelayApiService) { | ||||||
|  | 
 | ||||||
|  |         this.courseTableApiService = courseTableApiService; | ||||||
|  |         this.scoreApiService = scoreApiService; | ||||||
|  |         this.studentInfoApiService = studentInfoApiService; | ||||||
|  |         this.trainingPlanApiService = trainingPlanApiService; | ||||||
|  |         this.creditStatusApiService = creditStatusApiService; | ||||||
|  |         this.examDelayApiService = examDelayApiService; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String getStudentInfoPage(String cookie) throws IOException, ApiException { | ||||||
|  |         return studentInfoApiService.getPage(cookie); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String getCourseTable(String cookie, String term) throws IOException, ApiException { | ||||||
|  |         return courseTableApiService.getPage(term, cookie); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String getScore(String cookie) throws IOException, ApiException { | ||||||
|  |         return scoreApiService.getPage(cookie); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String getTrainingPlan(String cookie) throws IOException, ApiException { | ||||||
|  |         return trainingPlanApiService.getPage(cookie); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String getCreditStatus(String cookie) throws IOException, ApiException { | ||||||
|  |         return creditStatusApiService.getPage(cookie, null, false); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public UndergradExamDelayApiService.ExamActivity[] getExamActivities(String cookie, String term) | ||||||
|  |             throws IOException, ApiException { | ||||||
|  |         return examDelayApiService.getActivities(term, cookie); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String getExamDelayApplications(String cookie, String term, String activityId) | ||||||
|  |             throws IOException, ApiException { | ||||||
|  |         return examDelayApiService.getPage(term, activityId, cookie); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,152 @@ | |||||||
|  | <!DOCTYPE html> | ||||||
|  | <html lang="en"> | ||||||
|  | <head> | ||||||
|  |     <meta charset="UTF-8"> | ||||||
|  |     <title>getting-started - 1.0.0-SNAPSHOT</title> | ||||||
|  |     <style> | ||||||
|  |         h1, h2, h3, h4, h5, h6 { | ||||||
|  |             margin-bottom: 0.5rem; | ||||||
|  |             font-weight: 400; | ||||||
|  |             line-height: 1.5; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         h1 { | ||||||
|  |             font-size: 2.5rem; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         h2 { | ||||||
|  |             font-size: 2rem | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         h3 { | ||||||
|  |             font-size: 1.75rem | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         h4 { | ||||||
|  |             font-size: 1.5rem | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         h5 { | ||||||
|  |             font-size: 1.25rem | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         h6 { | ||||||
|  |             font-size: 1rem | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         .lead { | ||||||
|  |             font-weight: 300; | ||||||
|  |             font-size: 2rem; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         .banner { | ||||||
|  |             font-size: 2.7rem; | ||||||
|  |             margin: 0; | ||||||
|  |             padding: 2rem 1rem; | ||||||
|  |             background-color: #00A1E2; | ||||||
|  |             color: white; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         body { | ||||||
|  |             margin: 0; | ||||||
|  |             font-family: -apple-system, system-ui, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         code { | ||||||
|  |             font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; | ||||||
|  |             font-size: 87.5%; | ||||||
|  |             color: #e83e8c; | ||||||
|  |             word-break: break-word; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         .left-column { | ||||||
|  |             padding: .75rem; | ||||||
|  |             max-width: 75%; | ||||||
|  |             min-width: 55%; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         .right-column { | ||||||
|  |             padding: .75rem; | ||||||
|  |             max-width: 25%; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         .container { | ||||||
|  |             display: flex; | ||||||
|  |             width: 100%; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         li { | ||||||
|  |             margin: 0.75rem; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         .right-section { | ||||||
|  |             margin-left: 1rem; | ||||||
|  |             padding-left: 0.5rem; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         .right-section h3 { | ||||||
|  |             padding-top: 0; | ||||||
|  |             font-weight: 200; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         .right-section ul { | ||||||
|  |             border-left: 0.3rem solid #00A1E2; | ||||||
|  |             list-style-type: none; | ||||||
|  |             padding-left: 0; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     </style> | ||||||
|  | </head> | ||||||
|  | <body> | ||||||
|  | 
 | ||||||
|  | <div class="banner lead"> | ||||||
|  |     Your new Cloud-Native application is ready! | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | <div class="container"> | ||||||
|  |     <div class="left-column"> | ||||||
|  |         <p class="lead"> Congratulations, you have created a new Quarkus application.</p> | ||||||
|  | 
 | ||||||
|  |         <h2>Why do you see this?</h2> | ||||||
|  | 
 | ||||||
|  |         <p>This page is served by Quarkus. The source is in | ||||||
|  |             <code>src/main/resources/META-INF/resources/index.html</code>.</p> | ||||||
|  | 
 | ||||||
|  |         <h2>What can I do from here?</h2> | ||||||
|  | 
 | ||||||
|  |         <p>If not already done, run the application in <em>dev mode</em> using: <code>mvn quarkus:dev</code>. | ||||||
|  |         </p> | ||||||
|  |         <ul> | ||||||
|  |           <li>Add REST resources, Servlets, functions and other services in <code>src/main/java</code>.</li> | ||||||
|  |           <li>Your static assets are located in <code>src/main/resources/META-INF/resources</code>.</li> | ||||||
|  |           <li>Configure your application in <code>src/main/resources/application.properties</code>. | ||||||
|  |           </li> | ||||||
|  |         </ul> | ||||||
|  | 
 | ||||||
|  |         <h2>How do I get rid of this page?</h2> | ||||||
|  |         <p>Just delete the <code>src/main/resources/META-INF/resources/index.html</code> file.</p> | ||||||
|  |     </div> | ||||||
|  |     <div class="right-column"> | ||||||
|  |         <div class="right-section"> | ||||||
|  |             <h3>Application</h3> | ||||||
|  |             <ul> | ||||||
|  |                 <li>GroupId: org.acme</li> | ||||||
|  |                 <li>ArtifactId: getting-started</li> | ||||||
|  |                 <li>Version: 1.0.0-SNAPSHOT</li> | ||||||
|  |                 <li>Quarkus Version: 0.11.0</li> | ||||||
|  |             </ul> | ||||||
|  |         </div> | ||||||
|  |         <div class="right-section"> | ||||||
|  |             <h3>Next steps</h3> | ||||||
|  |             <ul> | ||||||
|  |                 <li><a href="https://quarkus.io/guides/maven-tooling.html">Setup your IDE</a></li> | ||||||
|  |                 <li><a href="https://quarkus.io/guides/getting-started-guide.html">Getting started</a></li> | ||||||
|  |                 <li><a href="https://quarkus.io">Quarkus Web Site</a></li> | ||||||
|  |             </ul> | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | </body> | ||||||
|  | </html> | ||||||
| @ -0,0 +1,11 @@ | |||||||
|  | quarkus.http.port=22800 | ||||||
|  | #quarkus.log.level=DEBUG | ||||||
|  | quarkus.log.file.encoding=UTF-8 | ||||||
|  | 
 | ||||||
|  | # 打包成jar时附带依赖 | ||||||
|  | quarkus.package.type=uber-jar | ||||||
|  | 
 | ||||||
|  | # 原生镜像编译附加参数,去掉后编译会失败 | ||||||
|  | # 但也只是能编译完成,目前的编译产物完全不可用,有非常多的严重bug | ||||||
|  | # 现阶段使用jar运行,启动效率虽不如原生程序,但速度尚可 | ||||||
|  | quarkus.native.additional-build-args="--initialize-at-run-time=cn.wustlinghang.mywust" | ||||||
| @ -1,59 +0,0 @@ | |||||||
| <?xml version="1.0" encoding="UTF-8"?> |  | ||||||
| <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" |  | ||||||
|     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> |  | ||||||
|   <modelVersion>4.0.0</modelVersion> |  | ||||||
|   <groupId>cn.wustlinghang.wusthelper</groupId> |  | ||||||
|   <artifactId>library</artifactId> |  | ||||||
|   <version>0.0.1-SNAPSHOT</version> |  | ||||||
|   <dependencies> |  | ||||||
|     <dependency> |  | ||||||
|       <groupId>cn.wustlinghang</groupId> |  | ||||||
|       <artifactId>mywust-core</artifactId> |  | ||||||
|       <version>0.0.2-SNAPSHOT</version> |  | ||||||
|       <scope>compile</scope> |  | ||||||
|     </dependency> |  | ||||||
|     <dependency> |  | ||||||
|       <groupId>cn.wustlinghang</groupId> |  | ||||||
|       <artifactId>mywust-network-okhttp</artifactId> |  | ||||||
|       <version>0.0.2-SNAPSHOT</version> |  | ||||||
|       <scope>compile</scope> |  | ||||||
|     </dependency> |  | ||||||
|     <dependency> |  | ||||||
|       <groupId>cn.wustlinghang.wusthelper</groupId> |  | ||||||
|       <artifactId>common</artifactId> |  | ||||||
|       <version>0.0.1-SNAPSHOT</version> |  | ||||||
|       <scope>compile</scope> |  | ||||||
|     </dependency> |  | ||||||
|     <dependency> |  | ||||||
|       <groupId>jakarta.annotation</groupId> |  | ||||||
|       <artifactId>jakarta.annotation-api</artifactId> |  | ||||||
|       <version>2.1.1</version> |  | ||||||
|       <scope>compile</scope> |  | ||||||
|     </dependency> |  | ||||||
|     <dependency> |  | ||||||
|       <groupId>javax.annotation</groupId> |  | ||||||
|       <artifactId>javax.annotation-api</artifactId> |  | ||||||
|       <version>1.3.2</version> |  | ||||||
|       <scope>compile</scope> |  | ||||||
|     </dependency> |  | ||||||
|     <dependency> |  | ||||||
|       <groupId>org.projectlombok</groupId> |  | ||||||
|       <artifactId>lombok</artifactId> |  | ||||||
|       <version>1.18.26</version> |  | ||||||
|       <scope>provided</scope> |  | ||||||
|     </dependency> |  | ||||||
|   </dependencies> |  | ||||||
|   <repositories> |  | ||||||
|     <repository> |  | ||||||
|       <id>central</id> |  | ||||||
|       <url>https://repo1.maven.org/maven2</url> |  | ||||||
|     </repository> |  | ||||||
|     <repository> |  | ||||||
|       <snapshots> |  | ||||||
|         <enabled>true</enabled> |  | ||||||
|       </snapshots> |  | ||||||
|       <id>github</id> |  | ||||||
|       <url>https://maven.pkg.github.com/LingHangStudio/mywust</url> |  | ||||||
|     </repository> |  | ||||||
|   </repositories> |  | ||||||
| </project> |  | ||||||
| @ -0,0 +1,54 @@ | |||||||
|  | #### | ||||||
|  | # This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode | ||||||
|  | # | ||||||
|  | # Before building the container image run: | ||||||
|  | # | ||||||
|  | # ./mvnw package | ||||||
|  | # | ||||||
|  | # Then, build the image with: | ||||||
|  | # | ||||||
|  | # docker build -f src/main/docker/Dockerfile.jvm -t quarkus/getting-started-jvm . | ||||||
|  | # | ||||||
|  | # Then run the container using: | ||||||
|  | # | ||||||
|  | # docker run -i --rm -p 8080:8080 quarkus/getting-started-jvm | ||||||
|  | # | ||||||
|  | # If you want to include the debug port into your docker image | ||||||
|  | # you will have to expose the debug port (default 5005) like this :  EXPOSE 8080 5050 | ||||||
|  | # | ||||||
|  | # Then run the container using : | ||||||
|  | # | ||||||
|  | # docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" quarkus/getting-started-jvm | ||||||
|  | # | ||||||
|  | ### | ||||||
|  | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.3  | ||||||
|  | 
 | ||||||
|  | ARG JAVA_PACKAGE=java-11-openjdk-headless | ||||||
|  | ARG RUN_JAVA_VERSION=1.3.8 | ||||||
|  | ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' | ||||||
|  | # Install java and the run-java script | ||||||
|  | # Also set up permissions for user `1001` | ||||||
|  | RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \ | ||||||
|  |     && microdnf update \ | ||||||
|  |     && microdnf clean all \ | ||||||
|  |     && mkdir /deployments \ | ||||||
|  |     && chown 1001 /deployments \ | ||||||
|  |     && chmod "g+rwX" /deployments \ | ||||||
|  |     && chown 1001:root /deployments \ | ||||||
|  |     && curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \ | ||||||
|  |     && chown 1001 /deployments/run-java.sh \ | ||||||
|  |     && chmod 540 /deployments/run-java.sh \ | ||||||
|  |     && echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/lib/security/java.security | ||||||
|  | 
 | ||||||
|  | # Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size. | ||||||
|  | ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" | ||||||
|  | # We make four distinct layers so if there are application changes the library layers can be re-used | ||||||
|  | COPY --chown=1001 target/quarkus-app/lib/ /deployments/lib/ | ||||||
|  | COPY --chown=1001 target/quarkus-app/*.jar /deployments/ | ||||||
|  | COPY --chown=1001 target/quarkus-app/app/ /deployments/app/ | ||||||
|  | COPY --chown=1001 target/quarkus-app/quarkus/ /deployments/quarkus/ | ||||||
|  | 
 | ||||||
|  | EXPOSE 8080 | ||||||
|  | USER 1001 | ||||||
|  | 
 | ||||||
|  | ENTRYPOINT [ "/deployments/run-java.sh" ] | ||||||
| @ -0,0 +1,51 @@ | |||||||
|  | #### | ||||||
|  | # This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode | ||||||
|  | # | ||||||
|  | # Before building the container image run: | ||||||
|  | # | ||||||
|  | # ./mvnw package -Dquarkus.package.type=legacy-jar | ||||||
|  | # | ||||||
|  | # Then, build the image with: | ||||||
|  | # | ||||||
|  | # docker build -f src/main/docker/Dockerfile.legacy-jar -t quarkus/getting-started-legacy-jar . | ||||||
|  | # | ||||||
|  | # Then run the container using: | ||||||
|  | # | ||||||
|  | # docker run -i --rm -p 8080:8080 quarkus/getting-started-legacy-jar | ||||||
|  | # | ||||||
|  | # If you want to include the debug port into your docker image | ||||||
|  | # you will have to expose the debug port (default 5005) like this :  EXPOSE 8080 5050 | ||||||
|  | # | ||||||
|  | # Then run the container using : | ||||||
|  | # | ||||||
|  | # docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" quarkus/getting-started-legacy-jar | ||||||
|  | # | ||||||
|  | ### | ||||||
|  | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.3  | ||||||
|  | 
 | ||||||
|  | ARG JAVA_PACKAGE=java-11-openjdk-headless | ||||||
|  | ARG RUN_JAVA_VERSION=1.3.8 | ||||||
|  | ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' | ||||||
|  | # Install java and the run-java script | ||||||
|  | # Also set up permissions for user `1001` | ||||||
|  | RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \ | ||||||
|  |     && microdnf update \ | ||||||
|  |     && microdnf clean all \ | ||||||
|  |     && mkdir /deployments \ | ||||||
|  |     && chown 1001 /deployments \ | ||||||
|  |     && chmod "g+rwX" /deployments \ | ||||||
|  |     && chown 1001:root /deployments \ | ||||||
|  |     && curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \ | ||||||
|  |     && chown 1001 /deployments/run-java.sh \ | ||||||
|  |     && chmod 540 /deployments/run-java.sh \ | ||||||
|  |     && echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/lib/security/java.security | ||||||
|  | 
 | ||||||
|  | # Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size. | ||||||
|  | ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" | ||||||
|  | COPY target/lib/* /deployments/lib/ | ||||||
|  | COPY target/*-runner.jar /deployments/app.jar | ||||||
|  | 
 | ||||||
|  | EXPOSE 8080 | ||||||
|  | USER 1001 | ||||||
|  | 
 | ||||||
|  | ENTRYPOINT [ "/deployments/run-java.sh" ] | ||||||
| @ -0,0 +1,27 @@ | |||||||
|  | #### | ||||||
|  | # This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode | ||||||
|  | # | ||||||
|  | # Before building the container image run: | ||||||
|  | # | ||||||
|  | # ./mvnw package -Pnative | ||||||
|  | # | ||||||
|  | # Then, build the image with: | ||||||
|  | # | ||||||
|  | # docker build -f src/main/docker/Dockerfile.native -t quarkus/getting-started . | ||||||
|  | # | ||||||
|  | # Then run the container using: | ||||||
|  | # | ||||||
|  | # docker run -i --rm -p 8080:8080 quarkus/getting-started | ||||||
|  | # | ||||||
|  | ### | ||||||
|  | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.3 | ||||||
|  | WORKDIR /work/ | ||||||
|  | RUN chown 1001 /work \ | ||||||
|  |     && chmod "g+rwX" /work \ | ||||||
|  |     && chown 1001:root /work | ||||||
|  | COPY --chown=1001:root target/*-runner /work/application | ||||||
|  | 
 | ||||||
|  | EXPOSE 8080 | ||||||
|  | USER 1001 | ||||||
|  | 
 | ||||||
|  | CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] | ||||||
| @ -0,0 +1,23 @@ | |||||||
|  | #### | ||||||
|  | # This Dockerfile is used in order to build a distroless container that runs the Quarkus application in native (no JVM) mode | ||||||
|  | # | ||||||
|  | # Before building the container image run: | ||||||
|  | # | ||||||
|  | # ./mvnw package -Pnative | ||||||
|  | # | ||||||
|  | # Then, build the image with: | ||||||
|  | # | ||||||
|  | # docker build -f src/main/docker/Dockerfile.native-micro -t quarkus/getting-started . | ||||||
|  | # | ||||||
|  | # Then run the container using: | ||||||
|  | # | ||||||
|  | # docker run -i --rm -p 8080:8080 quarkus/getting-started | ||||||
|  | # | ||||||
|  | ### | ||||||
|  | FROM quay.io/quarkus/quarkus-micro-image:1.0 | ||||||
|  | COPY target/*-runner /application | ||||||
|  | 
 | ||||||
|  | EXPOSE 8080 | ||||||
|  | USER 1001 | ||||||
|  | 
 | ||||||
|  | CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] | ||||||
| @ -1,7 +0,0 @@ | |||||||
| package cn.wustlinghang; |  | ||||||
| 
 |  | ||||||
| public class Main { |  | ||||||
|     public static void main(String[] args) { |  | ||||||
|         System.out.println("Hello world!"); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -0,0 +1,32 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.library.api.json; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.mywust.exception.ApiException; | ||||||
|  | import cn.wustlinghang.wusthelper.internal.library.services.LoginService; | ||||||
|  | import jakarta.validation.constraints.NotNull; | ||||||
|  | import jakarta.ws.rs.GET; | ||||||
|  | import jakarta.ws.rs.Path; | ||||||
|  | import jakarta.ws.rs.QueryParam; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | 
 | ||||||
|  | @Path("/cookie") | ||||||
|  | public class CookieApi { | ||||||
|  |     private final LoginService loginService; | ||||||
|  | 
 | ||||||
|  |     public CookieApi(LoginService loginService) { | ||||||
|  |         this.loginService = loginService; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @GET | ||||||
|  |     @Path("/") | ||||||
|  |     public String login(@QueryParam("username") @NotNull String username, | ||||||
|  |                         @QueryParam("password") @NotNull String password) throws IOException, ApiException { | ||||||
|  |         return loginService.login(username, password, false); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @GET | ||||||
|  |     @Path("/verify") | ||||||
|  |     public Boolean verify(@QueryParam("cookie") @NotNull String cookie) throws IOException { | ||||||
|  |         return loginService.verify(cookie); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,52 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.library.api.json; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.mywust.core.parser.undergraduate.UndergradCourseTableParser; | ||||||
|  | import cn.wustlinghang.mywust.core.request.service.undergraduate.UndergradCourseTableApiService; | ||||||
|  | import cn.wustlinghang.mywust.data.global.Course; | ||||||
|  | import cn.wustlinghang.mywust.data.global.StudentInfo; | ||||||
|  | import cn.wustlinghang.mywust.exception.ApiException; | ||||||
|  | import cn.wustlinghang.mywust.exception.ParseException; | ||||||
|  | import cn.wustlinghang.wusthelper.rpc.response.RpcResponse; | ||||||
|  | import jakarta.enterprise.context.ApplicationScoped; | ||||||
|  | import jakarta.validation.constraints.NotNull; | ||||||
|  | import jakarta.ws.rs.GET; | ||||||
|  | import jakarta.ws.rs.POST; | ||||||
|  | import jakarta.ws.rs.Path; | ||||||
|  | import jakarta.ws.rs.QueryParam; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | import java.util.List; | ||||||
|  | 
 | ||||||
|  | @Path("/course_table") | ||||||
|  | @ApplicationScoped | ||||||
|  | public class CourseTableApi { | ||||||
|  |     private final UndergradCourseTableApiService studentInfoApiService; | ||||||
|  |     private final UndergradCourseTableParser studentInfoPageParser; | ||||||
|  | 
 | ||||||
|  |     public CourseTableApi(UndergradCourseTableApiService studentInfoApiService, | ||||||
|  |                           UndergradCourseTableParser studentInfoPageParser) { | ||||||
|  |         this.studentInfoApiService = studentInfoApiService; | ||||||
|  |         this.studentInfoPageParser = studentInfoPageParser; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @GET | ||||||
|  |     @Path("/") | ||||||
|  |     public List<Course> get(@QueryParam("cookie") @NotNull String cookie, @QueryParam("term") String term) | ||||||
|  |             throws IOException, ApiException, ParseException { | ||||||
|  |         String html = studentInfoApiService.getPage(term, cookie); | ||||||
|  |         return this.parse(html); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @GET | ||||||
|  |     @Path("/agent") | ||||||
|  |     public String agent(@QueryParam("cookie") @NotNull String cookie, @QueryParam("term") String term) | ||||||
|  |             throws IOException, ApiException { | ||||||
|  |         return studentInfoApiService.getPage(term, cookie); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @POST | ||||||
|  |     @Path("/parse") | ||||||
|  |     public List<Course> parse(String html) throws ParseException { | ||||||
|  |         return studentInfoPageParser.parse(html); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,54 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.library.api.json; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.mywust.core.parser.undergraduate.UndergradCreditStatusParser; | ||||||
|  | import cn.wustlinghang.mywust.core.request.service.undergraduate.UndergradCreditStatusApiService; | ||||||
|  | import cn.wustlinghang.mywust.data.global.StudentInfo; | ||||||
|  | import cn.wustlinghang.mywust.exception.ApiException; | ||||||
|  | import cn.wustlinghang.mywust.exception.ParseException; | ||||||
|  | import cn.wustlinghang.mywust.network.RequestClientOption; | ||||||
|  | import cn.wustlinghang.wusthelper.rpc.response.RpcResponse; | ||||||
|  | import jakarta.enterprise.context.ApplicationScoped; | ||||||
|  | import jakarta.validation.constraints.NotNull; | ||||||
|  | import jakarta.ws.rs.GET; | ||||||
|  | import jakarta.ws.rs.POST; | ||||||
|  | import jakarta.ws.rs.Path; | ||||||
|  | import jakarta.ws.rs.QueryParam; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | 
 | ||||||
|  | @Path("/credit_status") | ||||||
|  | @ApplicationScoped | ||||||
|  | public class CreditStatusApi { | ||||||
|  |     private final UndergradCreditStatusApiService creditStatusApiService; | ||||||
|  |     private final UndergradCreditStatusParser creditStatusParser; | ||||||
|  | 
 | ||||||
|  |     private final RequestClientOption option; | ||||||
|  | 
 | ||||||
|  |     public CreditStatusApi(UndergradCreditStatusApiService creditStatusApiService, | ||||||
|  |                            UndergradCreditStatusParser creditStatusParser, | ||||||
|  |                            RequestClientOption option) { | ||||||
|  |         this.creditStatusApiService = creditStatusApiService; | ||||||
|  |         this.creditStatusParser = creditStatusParser; | ||||||
|  |         this.option = option; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @GET | ||||||
|  |     @Path("/") | ||||||
|  |     public String get(String cookie) throws IOException, ApiException, ParseException { | ||||||
|  |         String html =  creditStatusApiService.getPage(cookie, option, false); | ||||||
|  |         return this.parse(html); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @GET | ||||||
|  |     @Path("/agent") | ||||||
|  |     public String agent(@QueryParam("cookie") @NotNull String cookie) | ||||||
|  |             throws IOException, ApiException { | ||||||
|  |         return creditStatusApiService.getPage(cookie, option, false); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @POST | ||||||
|  |     @Path("/parse") | ||||||
|  |     public String parse(String html) throws ParseException { | ||||||
|  |         return creditStatusParser.parse(html); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,50 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.library.api.json; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.mywust.core.parser.undergraduate.UndergradScoreParser; | ||||||
|  | import cn.wustlinghang.mywust.core.request.service.undergraduate.UndergradScoreApiService; | ||||||
|  | import cn.wustlinghang.mywust.data.global.Score; | ||||||
|  | import cn.wustlinghang.mywust.data.global.StudentInfo; | ||||||
|  | import cn.wustlinghang.mywust.exception.ApiException; | ||||||
|  | import cn.wustlinghang.mywust.exception.ParseException; | ||||||
|  | import cn.wustlinghang.wusthelper.rpc.response.RpcResponse; | ||||||
|  | import jakarta.enterprise.context.ApplicationScoped; | ||||||
|  | import jakarta.validation.constraints.NotNull; | ||||||
|  | import jakarta.ws.rs.GET; | ||||||
|  | import jakarta.ws.rs.POST; | ||||||
|  | import jakarta.ws.rs.Path; | ||||||
|  | import jakarta.ws.rs.QueryParam; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | import java.util.List; | ||||||
|  | 
 | ||||||
|  | @Path("/score") | ||||||
|  | @ApplicationScoped | ||||||
|  | public class ScoreApi { | ||||||
|  |     private final UndergradScoreApiService scoreApiService; | ||||||
|  |     private final UndergradScoreParser scoreParser; | ||||||
|  | 
 | ||||||
|  |     public ScoreApi(UndergradScoreApiService scoreApiService, UndergradScoreParser scoreParser) { | ||||||
|  |         this.scoreApiService = scoreApiService; | ||||||
|  |         this.scoreParser = scoreParser; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @GET | ||||||
|  |     @Path("/") | ||||||
|  |     public List<Score> get(String cookie) throws IOException, ApiException, ParseException { | ||||||
|  |         String html =  scoreApiService.getPage(cookie); | ||||||
|  |         return this.parse(html); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @GET | ||||||
|  |     @Path("/agent") | ||||||
|  |     public String agent(@QueryParam("cookie") @NotNull String cookie) | ||||||
|  |             throws IOException, ApiException { | ||||||
|  |         return scoreApiService.getPage(cookie); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @POST | ||||||
|  |     @Path("/parse") | ||||||
|  |     public List<Score> parse(String html) throws ParseException { | ||||||
|  |         return scoreParser.parse(html); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,47 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.library.api.json; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.mywust.core.parser.undergraduate.UndergradStudentInfoPageParser; | ||||||
|  | import cn.wustlinghang.mywust.core.request.service.undergraduate.UndergradStudentInfoApiService; | ||||||
|  | import cn.wustlinghang.mywust.data.global.StudentInfo; | ||||||
|  | import cn.wustlinghang.mywust.exception.ApiException; | ||||||
|  | import cn.wustlinghang.mywust.exception.ParseException; | ||||||
|  | import jakarta.enterprise.context.ApplicationScoped; | ||||||
|  | import jakarta.validation.constraints.NotNull; | ||||||
|  | import jakarta.ws.rs.GET; | ||||||
|  | import jakarta.ws.rs.POST; | ||||||
|  | import jakarta.ws.rs.Path; | ||||||
|  | import jakarta.ws.rs.QueryParam; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | 
 | ||||||
|  | @Path("/student_info") | ||||||
|  | @ApplicationScoped | ||||||
|  | public class StudentInfoApi { | ||||||
|  |     private final UndergradStudentInfoApiService studentInfoApiService; | ||||||
|  |     private final UndergradStudentInfoPageParser studentInfoPageParser; | ||||||
|  | 
 | ||||||
|  |     public StudentInfoApi(UndergradStudentInfoApiService studentInfoApiService, | ||||||
|  |                           UndergradStudentInfoPageParser studentInfoPageParser) { | ||||||
|  |         this.studentInfoApiService = studentInfoApiService; | ||||||
|  |         this.studentInfoPageParser = studentInfoPageParser; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @GET | ||||||
|  |     @Path("/") | ||||||
|  |     public StudentInfo get(@QueryParam("cookie") @NotNull String cookie) throws IOException, ApiException, ParseException { | ||||||
|  |         return this.parse(this.agent(cookie)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @GET | ||||||
|  |     @Path("/agent") | ||||||
|  |     public String agent(@QueryParam("cookie") @NotNull String cookie) | ||||||
|  |             throws IOException, ApiException { | ||||||
|  |         return studentInfoApiService.getPage(cookie); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @POST | ||||||
|  |     @Path("/parse") | ||||||
|  |     public StudentInfo parse(String html) throws ParseException { | ||||||
|  |         return studentInfoPageParser.parse(html); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,47 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.library.api.json; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.mywust.core.parser.undergraduate.UndergradTrainingPlanPageParser; | ||||||
|  | import cn.wustlinghang.mywust.core.request.service.undergraduate.UndergradTrainingPlanApiService; | ||||||
|  | import cn.wustlinghang.mywust.exception.ApiException; | ||||||
|  | import cn.wustlinghang.mywust.exception.ParseException; | ||||||
|  | import jakarta.enterprise.context.ApplicationScoped; | ||||||
|  | import jakarta.validation.constraints.NotNull; | ||||||
|  | import jakarta.ws.rs.GET; | ||||||
|  | import jakarta.ws.rs.POST; | ||||||
|  | import jakarta.ws.rs.Path; | ||||||
|  | import jakarta.ws.rs.QueryParam; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | 
 | ||||||
|  | @Path("/training_plan") | ||||||
|  | @ApplicationScoped | ||||||
|  | public class TrainingPlanApi { | ||||||
|  |     private final UndergradTrainingPlanApiService trainingPlanApiService; | ||||||
|  |     private final UndergradTrainingPlanPageParser trainingPlanPageParser; | ||||||
|  | 
 | ||||||
|  |     public TrainingPlanApi(UndergradTrainingPlanApiService trainingPlanApiService, | ||||||
|  |                            UndergradTrainingPlanPageParser trainingPlanPageParser) { | ||||||
|  |         this.trainingPlanApiService = trainingPlanApiService; | ||||||
|  |         this.trainingPlanPageParser = trainingPlanPageParser; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @GET | ||||||
|  |     @Path("/") | ||||||
|  |     public String get(String cookie) throws IOException, ApiException, ParseException { | ||||||
|  |         String html =  trainingPlanApiService.getPage(cookie); | ||||||
|  |         return this.parse(html); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @GET | ||||||
|  |     @Path("/agent") | ||||||
|  |     public String agent(@QueryParam("cookie") @NotNull String cookie) | ||||||
|  |             throws IOException, ApiException { | ||||||
|  |         return trainingPlanApiService.getPage(cookie); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @POST | ||||||
|  |     @Path("/parse") | ||||||
|  |     public String parse(String html) throws ParseException { | ||||||
|  |         return trainingPlanPageParser.parse(html); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,14 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.library.api.json.handler; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.mywust.exception.ApiException; | ||||||
|  | import jakarta.ws.rs.core.Response; | ||||||
|  | import jakarta.ws.rs.ext.ExceptionMapper; | ||||||
|  | import jakarta.ws.rs.ext.Provider; | ||||||
|  | 
 | ||||||
|  | @Provider | ||||||
|  | public class ApiExceptionHandler extends ExceptionHandlerBase implements ExceptionMapper<ApiException> { | ||||||
|  |     @Override | ||||||
|  |     public Response toResponse(ApiException e) { | ||||||
|  |         return super.toResponse(e.getCodeValue(), e.toString(), "ApiExceptionHandler"); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,21 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.library.api.json.handler; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.wusthelper.rpc.response.ResponseCode; | ||||||
|  | import jakarta.ws.rs.core.Response; | ||||||
|  | import jakarta.ws.rs.ext.ExceptionMapper; | ||||||
|  | import jakarta.ws.rs.ext.Provider; | ||||||
|  | import lombok.extern.slf4j.Slf4j; | ||||||
|  | 
 | ||||||
|  | @Slf4j | ||||||
|  | @Provider | ||||||
|  | public class DefaultExceptionHandler extends ExceptionHandlerBase implements ExceptionMapper<Exception> { | ||||||
|  |     @Override | ||||||
|  |     public Response toResponse(Exception e) { | ||||||
|  |         log.error("未知异常:", e); | ||||||
|  |         return super.toResponse( | ||||||
|  |                 ResponseCode.SERVER_INTERNAL_ERROR, | ||||||
|  |                 e.toString(), | ||||||
|  |                 "DefaultExceptionHandler" | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,33 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.library.api.json.handler; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.wusthelper.rpc.response.ResponseCode; | ||||||
|  | import cn.wustlinghang.wusthelper.rpc.response.RpcResponse; | ||||||
|  | import com.fasterxml.jackson.core.JsonProcessingException; | ||||||
|  | import com.fasterxml.jackson.databind.ObjectMapper; | ||||||
|  | import jakarta.ws.rs.core.MediaType; | ||||||
|  | import jakarta.ws.rs.core.Response; | ||||||
|  | 
 | ||||||
|  | public abstract class ExceptionHandlerBase { | ||||||
|  |     public static final String EXCEPTION_HEADER_KEY = "X-exception-handler"; | ||||||
|  | 
 | ||||||
|  |     private static final ObjectMapper objectMapper = new ObjectMapper(); | ||||||
|  | 
 | ||||||
|  |     public Response toResponse(ResponseCode code, String msg, String handlerName) { | ||||||
|  |         return toResponse(code.getCode(), msg, handlerName); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Response toResponse(int code, String msg, String handlerName) { | ||||||
|  |         Object response; | ||||||
|  |         try { | ||||||
|  |             response = objectMapper.writeValueAsString(RpcResponse.error(code, msg)); | ||||||
|  |         } catch (JsonProcessingException e) { | ||||||
|  |             response = RpcResponse.error(ResponseCode.SERVER_INTERNAL_ERROR); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return Response.status(Response.Status.INTERNAL_SERVER_ERROR) | ||||||
|  |                 .entity(response) | ||||||
|  |                 .header(EXCEPTION_HEADER_KEY, handlerName) | ||||||
|  |                 .type(MediaType.APPLICATION_JSON) | ||||||
|  |                 .build(); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,23 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.library.api.json.handler; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.wusthelper.rpc.response.ResponseCode; | ||||||
|  | import jakarta.ws.rs.core.Response; | ||||||
|  | import jakarta.ws.rs.ext.ExceptionMapper; | ||||||
|  | import jakarta.ws.rs.ext.Provider; | ||||||
|  | import lombok.extern.slf4j.Slf4j; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | 
 | ||||||
|  | @Slf4j | ||||||
|  | @Provider | ||||||
|  | public class IOExceptionHandler extends ExceptionHandlerBase implements ExceptionMapper<IOException> { | ||||||
|  |     @Override | ||||||
|  |     public Response toResponse(IOException e) { | ||||||
|  |         log.error("IO异常:", e); | ||||||
|  |         return super.toResponse( | ||||||
|  |                 ResponseCode.SERVER_INTERNAL_ERROR, | ||||||
|  |                 e.toString(), | ||||||
|  |                 "IOExceptionHandler" | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,22 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.library.api.json.handler; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.mywust.exception.ParseException; | ||||||
|  | import cn.wustlinghang.wusthelper.rpc.response.ResponseCode; | ||||||
|  | import jakarta.ws.rs.core.Response; | ||||||
|  | import jakarta.ws.rs.ext.ExceptionMapper; | ||||||
|  | import jakarta.ws.rs.ext.Provider; | ||||||
|  | import lombok.extern.slf4j.Slf4j; | ||||||
|  | 
 | ||||||
|  | @Slf4j | ||||||
|  | @Provider | ||||||
|  | public class ParseExceptionHandler extends ExceptionHandlerBase implements ExceptionMapper<ParseException> { | ||||||
|  |     @Override | ||||||
|  |     public Response toResponse(ParseException e) { | ||||||
|  |         log.error("解析异常:", e); | ||||||
|  |         return super.toResponse( | ||||||
|  |                 ResponseCode.SERVER_INTERNAL_ERROR, | ||||||
|  |                 e.toString(), | ||||||
|  |                 "ParseExceptionHandler" | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,22 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.library.api.json.handler; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.wusthelper.rpc.response.ResponseCode; | ||||||
|  | import jakarta.validation.ValidationException; | ||||||
|  | import jakarta.ws.rs.core.Response; | ||||||
|  | import jakarta.ws.rs.ext.ExceptionMapper; | ||||||
|  | import jakarta.ws.rs.ext.Provider; | ||||||
|  | import lombok.extern.slf4j.Slf4j; | ||||||
|  | 
 | ||||||
|  | @Slf4j | ||||||
|  | @Provider | ||||||
|  | public class ValidationExceptionHandler extends ExceptionHandlerBase | ||||||
|  |         implements ExceptionMapper<ValidationException> { | ||||||
|  |     @Override | ||||||
|  |     public Response toResponse(ValidationException e) { | ||||||
|  |         return super.toResponse( | ||||||
|  |                 ResponseCode.PARAM_WRONG, | ||||||
|  |                 "参数错误:" + e.toString(), | ||||||
|  |                 "ValidationExceptionHandler" | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,36 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.library.api.json.interceptor; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.wusthelper.internal.library.api.json.handler.ExceptionHandlerBase; | ||||||
|  | import cn.wustlinghang.wusthelper.rpc.response.RpcResponse; | ||||||
|  | import com.fasterxml.jackson.databind.ObjectMapper; | ||||||
|  | import jakarta.ws.rs.WebApplicationException; | ||||||
|  | import jakarta.ws.rs.core.HttpHeaders; | ||||||
|  | import jakarta.ws.rs.core.MediaType; | ||||||
|  | import jakarta.ws.rs.ext.Provider; | ||||||
|  | import jakarta.ws.rs.ext.WriterInterceptor; | ||||||
|  | import jakarta.ws.rs.ext.WriterInterceptorContext; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | 
 | ||||||
|  | @Provider | ||||||
|  | public class ResponseWrapperInterceptor implements WriterInterceptor { | ||||||
|  |     private final ObjectMapper objectMapper; | ||||||
|  | 
 | ||||||
|  |     public ResponseWrapperInterceptor(ObjectMapper objectMapper) { | ||||||
|  |         this.objectMapper = objectMapper; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException { | ||||||
|  |         boolean hasException = context.getHeaders().get(ExceptionHandlerBase.EXCEPTION_HEADER_KEY) != null; | ||||||
|  |         if (!hasException) { | ||||||
|  |             Object data = context.getEntity(); | ||||||
|  |             RpcResponse<Object> wrappedResponse = RpcResponse.success(data); | ||||||
|  |             String json = objectMapper.writeValueAsString(wrappedResponse); | ||||||
|  |             context.getHeaders().putSingle(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON); | ||||||
|  |             context.setEntity(json); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         context.proceed(); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,12 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.library.bean; | ||||||
|  | 
 | ||||||
|  | import com.fasterxml.jackson.databind.ObjectMapper; | ||||||
|  | import jakarta.enterprise.context.ApplicationScoped; | ||||||
|  | import jakarta.inject.Singleton; | ||||||
|  | 
 | ||||||
|  | public class JacksonBean { | ||||||
|  |     @ApplicationScoped | ||||||
|  |     public ObjectMapper objectMapper() { | ||||||
|  |         return new ObjectMapper(); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,36 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.library.bean; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.mywust.core.parser.undergraduate.*; | ||||||
|  | import jakarta.enterprise.context.ApplicationScoped; | ||||||
|  | 
 | ||||||
|  | public class MywustParserBeans { | ||||||
|  |     @ApplicationScoped | ||||||
|  |     public UndergradCourseTableParser undergradCourseTableParser() { | ||||||
|  |         return new UndergradCourseTableParser(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @ApplicationScoped | ||||||
|  |     public UndergradScoreParser undergradScoreParser() { | ||||||
|  |         return new UndergradScoreParser(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @ApplicationScoped | ||||||
|  |     public UndergradStudentInfoPageParser undergradStudentInfoPageParser() { | ||||||
|  |         return new UndergradStudentInfoPageParser(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @ApplicationScoped | ||||||
|  |     public UndergradTrainingPlanPageParser undergradTrainingPlanPageParser() { | ||||||
|  |         return new UndergradTrainingPlanPageParser(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @ApplicationScoped | ||||||
|  |     public UndergradCreditStatusParser undergradCreditStatusParser() { | ||||||
|  |         return new UndergradCreditStatusParser(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @ApplicationScoped | ||||||
|  |     public UndergradExamDelayParser undergradExamDelayParser() { | ||||||
|  |         return new UndergradExamDelayParser(); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,63 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.library.bean; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.mywust.core.request.service.auth.UndergraduateLogin; | ||||||
|  | import cn.wustlinghang.mywust.core.request.service.undergraduate.*; | ||||||
|  | import cn.wustlinghang.mywust.network.RequestClientOption; | ||||||
|  | import cn.wustlinghang.mywust.network.Requester; | ||||||
|  | import cn.wustlinghang.mywust.network.okhttp.SimpleOkhttpRequester; | ||||||
|  | import jakarta.inject.Singleton; | ||||||
|  | 
 | ||||||
|  | public class MywustRequestAgentBeans { | ||||||
|  | 
 | ||||||
|  |     @Singleton | ||||||
|  |     public RequestClientOption requestClientOption() { | ||||||
|  |         RequestClientOption.Proxy proxy = RequestClientOption.Proxy.builder() | ||||||
|  |                 .address("127.0.0.1") | ||||||
|  |                 .port(8080) | ||||||
|  |                 .build(); | ||||||
|  |         RequestClientOption option = new RequestClientOption(); | ||||||
|  | //        option.setProxy(proxy);
 | ||||||
|  | 
 | ||||||
|  |         return option; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Singleton | ||||||
|  |     public Requester requester(RequestClientOption option) { | ||||||
|  |         return new SimpleOkhttpRequester(option, true); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Singleton | ||||||
|  |     public UndergraduateLogin undergraduateLogin(Requester requester) { | ||||||
|  |         return new UndergraduateLogin(requester); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Singleton | ||||||
|  |     public UndergradCourseTableApiService undergradCourseTableApiService(Requester requester) { | ||||||
|  |         return new UndergradCourseTableApiService(requester); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Singleton | ||||||
|  |     public UndergradScoreApiService undergradScoreApiService(Requester requester) { | ||||||
|  |         return new UndergradScoreApiService(requester); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Singleton | ||||||
|  |     public UndergradStudentInfoApiService undergradStudentInfoApiService(Requester requester) { | ||||||
|  |         return new UndergradStudentInfoApiService(requester); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Singleton | ||||||
|  |     public UndergradTrainingPlanApiService undergradTrainingPlanApiService(Requester requester) { | ||||||
|  |         return new UndergradTrainingPlanApiService(requester); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Singleton | ||||||
|  |     public UndergradCreditStatusApiService undergradCreditStatusApiService(Requester requester) { | ||||||
|  |         return new UndergradCreditStatusApiService(requester); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Singleton | ||||||
|  |     public UndergradExamDelayApiService undergradExamDelayApiService(Requester requester) { | ||||||
|  |         return new UndergradExamDelayApiService(requester); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,32 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.library.services; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.mywust.core.request.service.auth.UndergraduateLogin; | ||||||
|  | import cn.wustlinghang.mywust.exception.ApiException; | ||||||
|  | import cn.wustlinghang.mywust.network.RequestClientOption; | ||||||
|  | import jakarta.enterprise.context.ApplicationScoped; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | 
 | ||||||
|  | @ApplicationScoped | ||||||
|  | public class LoginService { | ||||||
|  |     private final RequestClientOption option; | ||||||
|  |     private final UndergraduateLogin undergraduateLogin; | ||||||
|  | 
 | ||||||
|  |     public LoginService(RequestClientOption option, | ||||||
|  |                         UndergraduateLogin undergraduateLogin) { | ||||||
|  |         this.option = option; | ||||||
|  |         this.undergraduateLogin = undergraduateLogin; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String login(String username, String password, boolean legacy) throws IOException, ApiException { | ||||||
|  |         if (legacy) { | ||||||
|  |             return undergraduateLogin.getLoginCookieLegacy(username, password, option); | ||||||
|  |         } else { | ||||||
|  |             return undergraduateLogin.getLoginCookie(username, password, option); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public boolean verify(String cookie) throws IOException { | ||||||
|  |         return !undergraduateLogin.checkCookiesFail(cookie); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,60 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.library.services; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.mywust.core.parser.undergraduate.*; | ||||||
|  | import cn.wustlinghang.mywust.data.global.Course; | ||||||
|  | import cn.wustlinghang.mywust.data.global.Score; | ||||||
|  | import cn.wustlinghang.mywust.data.global.StudentInfo; | ||||||
|  | import cn.wustlinghang.mywust.data.undergrad.ExamDelayApplication; | ||||||
|  | import cn.wustlinghang.mywust.exception.ParseException; | ||||||
|  | import jakarta.enterprise.context.ApplicationScoped; | ||||||
|  | 
 | ||||||
|  | import java.util.List; | ||||||
|  | 
 | ||||||
|  | @ApplicationScoped | ||||||
|  | public class ParseService { | ||||||
|  |     private final UndergradCourseTableParser courseTableParser; | ||||||
|  |     private final UndergradScoreParser scoreParser; | ||||||
|  |     private final UndergradStudentInfoPageParser studentInfoPageParser; | ||||||
|  |     private final UndergradTrainingPlanPageParser trainingPlanPageParser; | ||||||
|  |     private final UndergradCreditStatusParser creditStatusParser; | ||||||
|  |     private final UndergradExamDelayParser examDelayParser; | ||||||
|  | 
 | ||||||
|  |     public ParseService(UndergradCourseTableParser courseTableParser, | ||||||
|  |                         UndergradScoreParser scoreParser, | ||||||
|  |                         UndergradStudentInfoPageParser studentInfoPageParser, | ||||||
|  |                         UndergradTrainingPlanPageParser trainingPlanPageParser, | ||||||
|  |                         UndergradCreditStatusParser creditStatusParser, | ||||||
|  |                         UndergradExamDelayParser examDelayParser) { | ||||||
|  | 
 | ||||||
|  |         this.courseTableParser = courseTableParser; | ||||||
|  |         this.scoreParser = scoreParser; | ||||||
|  |         this.studentInfoPageParser = studentInfoPageParser; | ||||||
|  |         this.trainingPlanPageParser = trainingPlanPageParser; | ||||||
|  |         this.creditStatusParser = creditStatusParser; | ||||||
|  |         this.examDelayParser = examDelayParser; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public List<Course> parseCourseTable(String data) throws ParseException { | ||||||
|  |         return courseTableParser.parse(data); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public List<Score> parseScore(String data) throws ParseException { | ||||||
|  |         return scoreParser.parse(data); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public StudentInfo parseStudentInfo(String data) throws ParseException { | ||||||
|  |         return studentInfoPageParser.parse(data); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String parseTrainingPlan(String data) throws ParseException { | ||||||
|  |         return trainingPlanPageParser.parse(data); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String parseCreditStatus(String data) throws ParseException { | ||||||
|  |         return creditStatusParser.parse(data); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public List<ExamDelayApplication> parseExamDelayApplications(String data) throws ParseException { | ||||||
|  |         return examDelayParser.parse(data); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,62 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.library.services; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.mywust.core.request.service.undergraduate.*; | ||||||
|  | import cn.wustlinghang.mywust.exception.ApiException; | ||||||
|  | import jakarta.enterprise.context.ApplicationScoped; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | 
 | ||||||
|  | @ApplicationScoped | ||||||
|  | public class RequestAgentService { | ||||||
|  |     private final UndergradCourseTableApiService courseTableApiService; | ||||||
|  |     private final UndergradScoreApiService scoreApiService; | ||||||
|  |     private final UndergradStudentInfoApiService studentInfoApiService; | ||||||
|  |     private final UndergradTrainingPlanApiService trainingPlanApiService; | ||||||
|  |     private final UndergradCreditStatusApiService creditStatusApiService; | ||||||
|  |     private final UndergradExamDelayApiService examDelayApiService; | ||||||
|  | 
 | ||||||
|  |     public RequestAgentService(UndergradCourseTableApiService courseTableApiService, | ||||||
|  |                                UndergradScoreApiService scoreApiService, | ||||||
|  |                                UndergradStudentInfoApiService studentInfoApiService, | ||||||
|  |                                UndergradTrainingPlanApiService trainingPlanApiService, | ||||||
|  |                                UndergradCreditStatusApiService creditStatusApiService, | ||||||
|  |                                UndergradExamDelayApiService examDelayApiService) { | ||||||
|  | 
 | ||||||
|  |         this.courseTableApiService = courseTableApiService; | ||||||
|  |         this.scoreApiService = scoreApiService; | ||||||
|  |         this.studentInfoApiService = studentInfoApiService; | ||||||
|  |         this.trainingPlanApiService = trainingPlanApiService; | ||||||
|  |         this.creditStatusApiService = creditStatusApiService; | ||||||
|  |         this.examDelayApiService = examDelayApiService; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String getStudentInfoPage(String cookie) throws IOException, ApiException { | ||||||
|  |         return studentInfoApiService.getPage(cookie); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String getCourseTable(String cookie, String term) throws IOException, ApiException { | ||||||
|  |         return courseTableApiService.getPage(term, cookie); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String getScore(String cookie) throws IOException, ApiException { | ||||||
|  |         return scoreApiService.getPage(cookie); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String getTrainingPlan(String cookie) throws IOException, ApiException { | ||||||
|  |         return trainingPlanApiService.getPage(cookie); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String getCreditStatus(String cookie) throws IOException, ApiException { | ||||||
|  |         return creditStatusApiService.getPage(cookie, null, false); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public UndergradExamDelayApiService.ExamActivity[] getExamActivities(String cookie, String term) | ||||||
|  |             throws IOException, ApiException { | ||||||
|  |         return examDelayApiService.getActivities(term, cookie); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String getExamDelayApplications(String cookie, String term, String activityId) | ||||||
|  |             throws IOException, ApiException { | ||||||
|  |         return examDelayApiService.getPage(term, activityId, cookie); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,152 @@ | |||||||
|  | <!DOCTYPE html> | ||||||
|  | <html lang="en"> | ||||||
|  | <head> | ||||||
|  |     <meta charset="UTF-8"> | ||||||
|  |     <title>getting-started - 1.0.0-SNAPSHOT</title> | ||||||
|  |     <style> | ||||||
|  |         h1, h2, h3, h4, h5, h6 { | ||||||
|  |             margin-bottom: 0.5rem; | ||||||
|  |             font-weight: 400; | ||||||
|  |             line-height: 1.5; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         h1 { | ||||||
|  |             font-size: 2.5rem; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         h2 { | ||||||
|  |             font-size: 2rem | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         h3 { | ||||||
|  |             font-size: 1.75rem | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         h4 { | ||||||
|  |             font-size: 1.5rem | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         h5 { | ||||||
|  |             font-size: 1.25rem | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         h6 { | ||||||
|  |             font-size: 1rem | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         .lead { | ||||||
|  |             font-weight: 300; | ||||||
|  |             font-size: 2rem; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         .banner { | ||||||
|  |             font-size: 2.7rem; | ||||||
|  |             margin: 0; | ||||||
|  |             padding: 2rem 1rem; | ||||||
|  |             background-color: #00A1E2; | ||||||
|  |             color: white; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         body { | ||||||
|  |             margin: 0; | ||||||
|  |             font-family: -apple-system, system-ui, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         code { | ||||||
|  |             font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; | ||||||
|  |             font-size: 87.5%; | ||||||
|  |             color: #e83e8c; | ||||||
|  |             word-break: break-word; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         .left-column { | ||||||
|  |             padding: .75rem; | ||||||
|  |             max-width: 75%; | ||||||
|  |             min-width: 55%; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         .right-column { | ||||||
|  |             padding: .75rem; | ||||||
|  |             max-width: 25%; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         .container { | ||||||
|  |             display: flex; | ||||||
|  |             width: 100%; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         li { | ||||||
|  |             margin: 0.75rem; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         .right-section { | ||||||
|  |             margin-left: 1rem; | ||||||
|  |             padding-left: 0.5rem; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         .right-section h3 { | ||||||
|  |             padding-top: 0; | ||||||
|  |             font-weight: 200; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         .right-section ul { | ||||||
|  |             border-left: 0.3rem solid #00A1E2; | ||||||
|  |             list-style-type: none; | ||||||
|  |             padding-left: 0; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     </style> | ||||||
|  | </head> | ||||||
|  | <body> | ||||||
|  | 
 | ||||||
|  | <div class="banner lead"> | ||||||
|  |     Your new Cloud-Native application is ready! | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | <div class="container"> | ||||||
|  |     <div class="left-column"> | ||||||
|  |         <p class="lead"> Congratulations, you have created a new Quarkus application.</p> | ||||||
|  | 
 | ||||||
|  |         <h2>Why do you see this?</h2> | ||||||
|  | 
 | ||||||
|  |         <p>This page is served by Quarkus. The source is in | ||||||
|  |             <code>src/main/resources/META-INF/resources/index.html</code>.</p> | ||||||
|  | 
 | ||||||
|  |         <h2>What can I do from here?</h2> | ||||||
|  | 
 | ||||||
|  |         <p>If not already done, run the application in <em>dev mode</em> using: <code>mvn quarkus:dev</code>. | ||||||
|  |         </p> | ||||||
|  |         <ul> | ||||||
|  |           <li>Add REST resources, Servlets, functions and other services in <code>src/main/java</code>.</li> | ||||||
|  |           <li>Your static assets are located in <code>src/main/resources/META-INF/resources</code>.</li> | ||||||
|  |           <li>Configure your application in <code>src/main/resources/application.properties</code>. | ||||||
|  |           </li> | ||||||
|  |         </ul> | ||||||
|  | 
 | ||||||
|  |         <h2>How do I get rid of this page?</h2> | ||||||
|  |         <p>Just delete the <code>src/main/resources/META-INF/resources/index.html</code> file.</p> | ||||||
|  |     </div> | ||||||
|  |     <div class="right-column"> | ||||||
|  |         <div class="right-section"> | ||||||
|  |             <h3>Application</h3> | ||||||
|  |             <ul> | ||||||
|  |                 <li>GroupId: org.acme</li> | ||||||
|  |                 <li>ArtifactId: getting-started</li> | ||||||
|  |                 <li>Version: 1.0.0-SNAPSHOT</li> | ||||||
|  |                 <li>Quarkus Version: 0.11.0</li> | ||||||
|  |             </ul> | ||||||
|  |         </div> | ||||||
|  |         <div class="right-section"> | ||||||
|  |             <h3>Next steps</h3> | ||||||
|  |             <ul> | ||||||
|  |                 <li><a href="https://quarkus.io/guides/maven-tooling.html">Setup your IDE</a></li> | ||||||
|  |                 <li><a href="https://quarkus.io/guides/getting-started-guide.html">Getting started</a></li> | ||||||
|  |                 <li><a href="https://quarkus.io">Quarkus Web Site</a></li> | ||||||
|  |             </ul> | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | </body> | ||||||
|  | </html> | ||||||
| @ -0,0 +1,11 @@ | |||||||
|  | quarkus.http.port=22800 | ||||||
|  | #quarkus.log.level=DEBUG | ||||||
|  | quarkus.log.file.encoding=UTF-8 | ||||||
|  | 
 | ||||||
|  | # 打包成jar时附带依赖 | ||||||
|  | quarkus.package.type=uber-jar | ||||||
|  | 
 | ||||||
|  | # 原生镜像编译附加参数,去掉后编译会失败 | ||||||
|  | # 但也只是能编译完成,目前的编译产物完全不可用,有非常多的严重bug | ||||||
|  | # 现阶段使用jar运行,启动效率虽不如原生程序,但速度尚可 | ||||||
|  | quarkus.native.additional-build-args="--initialize-at-run-time=cn.wustlinghang.mywust" | ||||||
| @ -1,59 +0,0 @@ | |||||||
| <?xml version="1.0" encoding="UTF-8"?> |  | ||||||
| <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" |  | ||||||
|     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> |  | ||||||
|   <modelVersion>4.0.0</modelVersion> |  | ||||||
|   <groupId>cn.wustlinghang.wusthelper</groupId> |  | ||||||
|   <artifactId>physics</artifactId> |  | ||||||
|   <version>0.0.1-SNAPSHOT</version> |  | ||||||
|   <dependencies> |  | ||||||
|     <dependency> |  | ||||||
|       <groupId>cn.wustlinghang</groupId> |  | ||||||
|       <artifactId>mywust-core</artifactId> |  | ||||||
|       <version>0.0.2-SNAPSHOT</version> |  | ||||||
|       <scope>compile</scope> |  | ||||||
|     </dependency> |  | ||||||
|     <dependency> |  | ||||||
|       <groupId>cn.wustlinghang</groupId> |  | ||||||
|       <artifactId>mywust-network-okhttp</artifactId> |  | ||||||
|       <version>0.0.2-SNAPSHOT</version> |  | ||||||
|       <scope>compile</scope> |  | ||||||
|     </dependency> |  | ||||||
|     <dependency> |  | ||||||
|       <groupId>cn.wustlinghang.wusthelper</groupId> |  | ||||||
|       <artifactId>common</artifactId> |  | ||||||
|       <version>0.0.1-SNAPSHOT</version> |  | ||||||
|       <scope>compile</scope> |  | ||||||
|     </dependency> |  | ||||||
|     <dependency> |  | ||||||
|       <groupId>jakarta.annotation</groupId> |  | ||||||
|       <artifactId>jakarta.annotation-api</artifactId> |  | ||||||
|       <version>2.1.1</version> |  | ||||||
|       <scope>compile</scope> |  | ||||||
|     </dependency> |  | ||||||
|     <dependency> |  | ||||||
|       <groupId>javax.annotation</groupId> |  | ||||||
|       <artifactId>javax.annotation-api</artifactId> |  | ||||||
|       <version>1.3.2</version> |  | ||||||
|       <scope>compile</scope> |  | ||||||
|     </dependency> |  | ||||||
|     <dependency> |  | ||||||
|       <groupId>org.projectlombok</groupId> |  | ||||||
|       <artifactId>lombok</artifactId> |  | ||||||
|       <version>1.18.26</version> |  | ||||||
|       <scope>provided</scope> |  | ||||||
|     </dependency> |  | ||||||
|   </dependencies> |  | ||||||
|   <repositories> |  | ||||||
|     <repository> |  | ||||||
|       <id>central</id> |  | ||||||
|       <url>https://repo1.maven.org/maven2</url> |  | ||||||
|     </repository> |  | ||||||
|     <repository> |  | ||||||
|       <snapshots> |  | ||||||
|         <enabled>true</enabled> |  | ||||||
|       </snapshots> |  | ||||||
|       <id>github</id> |  | ||||||
|       <url>https://maven.pkg.github.com/LingHangStudio/mywust</url> |  | ||||||
|     </repository> |  | ||||||
|   </repositories> |  | ||||||
| </project> |  | ||||||
| @ -0,0 +1,54 @@ | |||||||
|  | #### | ||||||
|  | # This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode | ||||||
|  | # | ||||||
|  | # Before building the container image run: | ||||||
|  | # | ||||||
|  | # ./mvnw package | ||||||
|  | # | ||||||
|  | # Then, build the image with: | ||||||
|  | # | ||||||
|  | # docker build -f src/main/docker/Dockerfile.jvm -t quarkus/getting-started-jvm . | ||||||
|  | # | ||||||
|  | # Then run the container using: | ||||||
|  | # | ||||||
|  | # docker run -i --rm -p 8080:8080 quarkus/getting-started-jvm | ||||||
|  | # | ||||||
|  | # If you want to include the debug port into your docker image | ||||||
|  | # you will have to expose the debug port (default 5005) like this :  EXPOSE 8080 5050 | ||||||
|  | # | ||||||
|  | # Then run the container using : | ||||||
|  | # | ||||||
|  | # docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" quarkus/getting-started-jvm | ||||||
|  | # | ||||||
|  | ### | ||||||
|  | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.3  | ||||||
|  | 
 | ||||||
|  | ARG JAVA_PACKAGE=java-11-openjdk-headless | ||||||
|  | ARG RUN_JAVA_VERSION=1.3.8 | ||||||
|  | ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' | ||||||
|  | # Install java and the run-java script | ||||||
|  | # Also set up permissions for user `1001` | ||||||
|  | RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \ | ||||||
|  |     && microdnf update \ | ||||||
|  |     && microdnf clean all \ | ||||||
|  |     && mkdir /deployments \ | ||||||
|  |     && chown 1001 /deployments \ | ||||||
|  |     && chmod "g+rwX" /deployments \ | ||||||
|  |     && chown 1001:root /deployments \ | ||||||
|  |     && curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \ | ||||||
|  |     && chown 1001 /deployments/run-java.sh \ | ||||||
|  |     && chmod 540 /deployments/run-java.sh \ | ||||||
|  |     && echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/lib/security/java.security | ||||||
|  | 
 | ||||||
|  | # Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size. | ||||||
|  | ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" | ||||||
|  | # We make four distinct layers so if there are application changes the library layers can be re-used | ||||||
|  | COPY --chown=1001 target/quarkus-app/lib/ /deployments/lib/ | ||||||
|  | COPY --chown=1001 target/quarkus-app/*.jar /deployments/ | ||||||
|  | COPY --chown=1001 target/quarkus-app/app/ /deployments/app/ | ||||||
|  | COPY --chown=1001 target/quarkus-app/quarkus/ /deployments/quarkus/ | ||||||
|  | 
 | ||||||
|  | EXPOSE 8080 | ||||||
|  | USER 1001 | ||||||
|  | 
 | ||||||
|  | ENTRYPOINT [ "/deployments/run-java.sh" ] | ||||||
| @ -0,0 +1,51 @@ | |||||||
|  | #### | ||||||
|  | # This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode | ||||||
|  | # | ||||||
|  | # Before building the container image run: | ||||||
|  | # | ||||||
|  | # ./mvnw package -Dquarkus.package.type=legacy-jar | ||||||
|  | # | ||||||
|  | # Then, build the image with: | ||||||
|  | # | ||||||
|  | # docker build -f src/main/docker/Dockerfile.legacy-jar -t quarkus/getting-started-legacy-jar . | ||||||
|  | # | ||||||
|  | # Then run the container using: | ||||||
|  | # | ||||||
|  | # docker run -i --rm -p 8080:8080 quarkus/getting-started-legacy-jar | ||||||
|  | # | ||||||
|  | # If you want to include the debug port into your docker image | ||||||
|  | # you will have to expose the debug port (default 5005) like this :  EXPOSE 8080 5050 | ||||||
|  | # | ||||||
|  | # Then run the container using : | ||||||
|  | # | ||||||
|  | # docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" quarkus/getting-started-legacy-jar | ||||||
|  | # | ||||||
|  | ### | ||||||
|  | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.3  | ||||||
|  | 
 | ||||||
|  | ARG JAVA_PACKAGE=java-11-openjdk-headless | ||||||
|  | ARG RUN_JAVA_VERSION=1.3.8 | ||||||
|  | ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' | ||||||
|  | # Install java and the run-java script | ||||||
|  | # Also set up permissions for user `1001` | ||||||
|  | RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \ | ||||||
|  |     && microdnf update \ | ||||||
|  |     && microdnf clean all \ | ||||||
|  |     && mkdir /deployments \ | ||||||
|  |     && chown 1001 /deployments \ | ||||||
|  |     && chmod "g+rwX" /deployments \ | ||||||
|  |     && chown 1001:root /deployments \ | ||||||
|  |     && curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \ | ||||||
|  |     && chown 1001 /deployments/run-java.sh \ | ||||||
|  |     && chmod 540 /deployments/run-java.sh \ | ||||||
|  |     && echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/lib/security/java.security | ||||||
|  | 
 | ||||||
|  | # Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size. | ||||||
|  | ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" | ||||||
|  | COPY target/lib/* /deployments/lib/ | ||||||
|  | COPY target/*-runner.jar /deployments/app.jar | ||||||
|  | 
 | ||||||
|  | EXPOSE 8080 | ||||||
|  | USER 1001 | ||||||
|  | 
 | ||||||
|  | ENTRYPOINT [ "/deployments/run-java.sh" ] | ||||||
| @ -0,0 +1,27 @@ | |||||||
|  | #### | ||||||
|  | # This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode | ||||||
|  | # | ||||||
|  | # Before building the container image run: | ||||||
|  | # | ||||||
|  | # ./mvnw package -Pnative | ||||||
|  | # | ||||||
|  | # Then, build the image with: | ||||||
|  | # | ||||||
|  | # docker build -f src/main/docker/Dockerfile.native -t quarkus/getting-started . | ||||||
|  | # | ||||||
|  | # Then run the container using: | ||||||
|  | # | ||||||
|  | # docker run -i --rm -p 8080:8080 quarkus/getting-started | ||||||
|  | # | ||||||
|  | ### | ||||||
|  | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.3 | ||||||
|  | WORKDIR /work/ | ||||||
|  | RUN chown 1001 /work \ | ||||||
|  |     && chmod "g+rwX" /work \ | ||||||
|  |     && chown 1001:root /work | ||||||
|  | COPY --chown=1001:root target/*-runner /work/application | ||||||
|  | 
 | ||||||
|  | EXPOSE 8080 | ||||||
|  | USER 1001 | ||||||
|  | 
 | ||||||
|  | CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] | ||||||
| @ -0,0 +1,23 @@ | |||||||
|  | #### | ||||||
|  | # This Dockerfile is used in order to build a distroless container that runs the Quarkus application in native (no JVM) mode | ||||||
|  | # | ||||||
|  | # Before building the container image run: | ||||||
|  | # | ||||||
|  | # ./mvnw package -Pnative | ||||||
|  | # | ||||||
|  | # Then, build the image with: | ||||||
|  | # | ||||||
|  | # docker build -f src/main/docker/Dockerfile.native-micro -t quarkus/getting-started . | ||||||
|  | # | ||||||
|  | # Then run the container using: | ||||||
|  | # | ||||||
|  | # docker run -i --rm -p 8080:8080 quarkus/getting-started | ||||||
|  | # | ||||||
|  | ### | ||||||
|  | FROM quay.io/quarkus/quarkus-micro-image:1.0 | ||||||
|  | COPY target/*-runner /application | ||||||
|  | 
 | ||||||
|  | EXPOSE 8080 | ||||||
|  | USER 1001 | ||||||
|  | 
 | ||||||
|  | CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] | ||||||
| @ -1,7 +0,0 @@ | |||||||
| package cn.wustlinghang; |  | ||||||
| 
 |  | ||||||
| public class Main { |  | ||||||
|     public static void main(String[] args) { |  | ||||||
|         System.out.println("Hello world!"); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -0,0 +1,32 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.physics.api.json; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.mywust.exception.ApiException; | ||||||
|  | import cn.wustlinghang.wusthelper.internal.physics.services.LoginService; | ||||||
|  | import jakarta.validation.constraints.NotNull; | ||||||
|  | import jakarta.ws.rs.GET; | ||||||
|  | import jakarta.ws.rs.Path; | ||||||
|  | import jakarta.ws.rs.QueryParam; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | 
 | ||||||
|  | @Path("/cookie") | ||||||
|  | public class CookieApi { | ||||||
|  |     private final LoginService loginService; | ||||||
|  | 
 | ||||||
|  |     public CookieApi(LoginService loginService) { | ||||||
|  |         this.loginService = loginService; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @GET | ||||||
|  |     @Path("/") | ||||||
|  |     public String login(@QueryParam("username") @NotNull String username, | ||||||
|  |                         @QueryParam("password") @NotNull String password) throws IOException, ApiException { | ||||||
|  |         return loginService.login(username, password, false); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @GET | ||||||
|  |     @Path("/verify") | ||||||
|  |     public Boolean verify(@QueryParam("cookie") @NotNull String cookie) throws IOException { | ||||||
|  |         return loginService.verify(cookie); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,52 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.physics.api.json; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.mywust.core.parser.undergraduate.UndergradCourseTableParser; | ||||||
|  | import cn.wustlinghang.mywust.core.request.service.undergraduate.UndergradCourseTableApiService; | ||||||
|  | import cn.wustlinghang.mywust.data.global.Course; | ||||||
|  | import cn.wustlinghang.mywust.data.global.StudentInfo; | ||||||
|  | import cn.wustlinghang.mywust.exception.ApiException; | ||||||
|  | import cn.wustlinghang.mywust.exception.ParseException; | ||||||
|  | import cn.wustlinghang.wusthelper.rpc.response.RpcResponse; | ||||||
|  | import jakarta.enterprise.context.ApplicationScoped; | ||||||
|  | import jakarta.validation.constraints.NotNull; | ||||||
|  | import jakarta.ws.rs.GET; | ||||||
|  | import jakarta.ws.rs.POST; | ||||||
|  | import jakarta.ws.rs.Path; | ||||||
|  | import jakarta.ws.rs.QueryParam; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | import java.util.List; | ||||||
|  | 
 | ||||||
|  | @Path("/course_table") | ||||||
|  | @ApplicationScoped | ||||||
|  | public class CourseTableApi { | ||||||
|  |     private final UndergradCourseTableApiService studentInfoApiService; | ||||||
|  |     private final UndergradCourseTableParser studentInfoPageParser; | ||||||
|  | 
 | ||||||
|  |     public CourseTableApi(UndergradCourseTableApiService studentInfoApiService, | ||||||
|  |                           UndergradCourseTableParser studentInfoPageParser) { | ||||||
|  |         this.studentInfoApiService = studentInfoApiService; | ||||||
|  |         this.studentInfoPageParser = studentInfoPageParser; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @GET | ||||||
|  |     @Path("/") | ||||||
|  |     public List<Course> get(@QueryParam("cookie") @NotNull String cookie, @QueryParam("term") String term) | ||||||
|  |             throws IOException, ApiException, ParseException { | ||||||
|  |         String html = studentInfoApiService.getPage(term, cookie); | ||||||
|  |         return this.parse(html); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @GET | ||||||
|  |     @Path("/agent") | ||||||
|  |     public String agent(@QueryParam("cookie") @NotNull String cookie, @QueryParam("term") String term) | ||||||
|  |             throws IOException, ApiException { | ||||||
|  |         return studentInfoApiService.getPage(term, cookie); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @POST | ||||||
|  |     @Path("/parse") | ||||||
|  |     public List<Course> parse(String html) throws ParseException { | ||||||
|  |         return studentInfoPageParser.parse(html); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,54 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.physics.api.json; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.mywust.core.parser.undergraduate.UndergradCreditStatusParser; | ||||||
|  | import cn.wustlinghang.mywust.core.request.service.undergraduate.UndergradCreditStatusApiService; | ||||||
|  | import cn.wustlinghang.mywust.data.global.StudentInfo; | ||||||
|  | import cn.wustlinghang.mywust.exception.ApiException; | ||||||
|  | import cn.wustlinghang.mywust.exception.ParseException; | ||||||
|  | import cn.wustlinghang.mywust.network.RequestClientOption; | ||||||
|  | import cn.wustlinghang.wusthelper.rpc.response.RpcResponse; | ||||||
|  | import jakarta.enterprise.context.ApplicationScoped; | ||||||
|  | import jakarta.validation.constraints.NotNull; | ||||||
|  | import jakarta.ws.rs.GET; | ||||||
|  | import jakarta.ws.rs.POST; | ||||||
|  | import jakarta.ws.rs.Path; | ||||||
|  | import jakarta.ws.rs.QueryParam; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | 
 | ||||||
|  | @Path("/credit_status") | ||||||
|  | @ApplicationScoped | ||||||
|  | public class CreditStatusApi { | ||||||
|  |     private final UndergradCreditStatusApiService creditStatusApiService; | ||||||
|  |     private final UndergradCreditStatusParser creditStatusParser; | ||||||
|  | 
 | ||||||
|  |     private final RequestClientOption option; | ||||||
|  | 
 | ||||||
|  |     public CreditStatusApi(UndergradCreditStatusApiService creditStatusApiService, | ||||||
|  |                            UndergradCreditStatusParser creditStatusParser, | ||||||
|  |                            RequestClientOption option) { | ||||||
|  |         this.creditStatusApiService = creditStatusApiService; | ||||||
|  |         this.creditStatusParser = creditStatusParser; | ||||||
|  |         this.option = option; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @GET | ||||||
|  |     @Path("/") | ||||||
|  |     public String get(String cookie) throws IOException, ApiException, ParseException { | ||||||
|  |         String html =  creditStatusApiService.getPage(cookie, option, false); | ||||||
|  |         return this.parse(html); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @GET | ||||||
|  |     @Path("/agent") | ||||||
|  |     public String agent(@QueryParam("cookie") @NotNull String cookie) | ||||||
|  |             throws IOException, ApiException { | ||||||
|  |         return creditStatusApiService.getPage(cookie, option, false); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @POST | ||||||
|  |     @Path("/parse") | ||||||
|  |     public String parse(String html) throws ParseException { | ||||||
|  |         return creditStatusParser.parse(html); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,50 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.physics.api.json; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.mywust.core.parser.undergraduate.UndergradScoreParser; | ||||||
|  | import cn.wustlinghang.mywust.core.request.service.undergraduate.UndergradScoreApiService; | ||||||
|  | import cn.wustlinghang.mywust.data.global.Score; | ||||||
|  | import cn.wustlinghang.mywust.data.global.StudentInfo; | ||||||
|  | import cn.wustlinghang.mywust.exception.ApiException; | ||||||
|  | import cn.wustlinghang.mywust.exception.ParseException; | ||||||
|  | import cn.wustlinghang.wusthelper.rpc.response.RpcResponse; | ||||||
|  | import jakarta.enterprise.context.ApplicationScoped; | ||||||
|  | import jakarta.validation.constraints.NotNull; | ||||||
|  | import jakarta.ws.rs.GET; | ||||||
|  | import jakarta.ws.rs.POST; | ||||||
|  | import jakarta.ws.rs.Path; | ||||||
|  | import jakarta.ws.rs.QueryParam; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | import java.util.List; | ||||||
|  | 
 | ||||||
|  | @Path("/score") | ||||||
|  | @ApplicationScoped | ||||||
|  | public class ScoreApi { | ||||||
|  |     private final UndergradScoreApiService scoreApiService; | ||||||
|  |     private final UndergradScoreParser scoreParser; | ||||||
|  | 
 | ||||||
|  |     public ScoreApi(UndergradScoreApiService scoreApiService, UndergradScoreParser scoreParser) { | ||||||
|  |         this.scoreApiService = scoreApiService; | ||||||
|  |         this.scoreParser = scoreParser; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @GET | ||||||
|  |     @Path("/") | ||||||
|  |     public List<Score> get(String cookie) throws IOException, ApiException, ParseException { | ||||||
|  |         String html =  scoreApiService.getPage(cookie); | ||||||
|  |         return this.parse(html); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @GET | ||||||
|  |     @Path("/agent") | ||||||
|  |     public String agent(@QueryParam("cookie") @NotNull String cookie) | ||||||
|  |             throws IOException, ApiException { | ||||||
|  |         return scoreApiService.getPage(cookie); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @POST | ||||||
|  |     @Path("/parse") | ||||||
|  |     public List<Score> parse(String html) throws ParseException { | ||||||
|  |         return scoreParser.parse(html); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,47 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.physics.api.json; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.mywust.core.parser.undergraduate.UndergradStudentInfoPageParser; | ||||||
|  | import cn.wustlinghang.mywust.core.request.service.undergraduate.UndergradStudentInfoApiService; | ||||||
|  | import cn.wustlinghang.mywust.data.global.StudentInfo; | ||||||
|  | import cn.wustlinghang.mywust.exception.ApiException; | ||||||
|  | import cn.wustlinghang.mywust.exception.ParseException; | ||||||
|  | import jakarta.enterprise.context.ApplicationScoped; | ||||||
|  | import jakarta.validation.constraints.NotNull; | ||||||
|  | import jakarta.ws.rs.GET; | ||||||
|  | import jakarta.ws.rs.POST; | ||||||
|  | import jakarta.ws.rs.Path; | ||||||
|  | import jakarta.ws.rs.QueryParam; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | 
 | ||||||
|  | @Path("/student_info") | ||||||
|  | @ApplicationScoped | ||||||
|  | public class StudentInfoApi { | ||||||
|  |     private final UndergradStudentInfoApiService studentInfoApiService; | ||||||
|  |     private final UndergradStudentInfoPageParser studentInfoPageParser; | ||||||
|  | 
 | ||||||
|  |     public StudentInfoApi(UndergradStudentInfoApiService studentInfoApiService, | ||||||
|  |                           UndergradStudentInfoPageParser studentInfoPageParser) { | ||||||
|  |         this.studentInfoApiService = studentInfoApiService; | ||||||
|  |         this.studentInfoPageParser = studentInfoPageParser; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @GET | ||||||
|  |     @Path("/") | ||||||
|  |     public StudentInfo get(@QueryParam("cookie") @NotNull String cookie) throws IOException, ApiException, ParseException { | ||||||
|  |         return this.parse(this.agent(cookie)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @GET | ||||||
|  |     @Path("/agent") | ||||||
|  |     public String agent(@QueryParam("cookie") @NotNull String cookie) | ||||||
|  |             throws IOException, ApiException { | ||||||
|  |         return studentInfoApiService.getPage(cookie); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @POST | ||||||
|  |     @Path("/parse") | ||||||
|  |     public StudentInfo parse(String html) throws ParseException { | ||||||
|  |         return studentInfoPageParser.parse(html); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,47 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.physics.api.json; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.mywust.core.parser.undergraduate.UndergradTrainingPlanPageParser; | ||||||
|  | import cn.wustlinghang.mywust.core.request.service.undergraduate.UndergradTrainingPlanApiService; | ||||||
|  | import cn.wustlinghang.mywust.exception.ApiException; | ||||||
|  | import cn.wustlinghang.mywust.exception.ParseException; | ||||||
|  | import jakarta.enterprise.context.ApplicationScoped; | ||||||
|  | import jakarta.validation.constraints.NotNull; | ||||||
|  | import jakarta.ws.rs.GET; | ||||||
|  | import jakarta.ws.rs.POST; | ||||||
|  | import jakarta.ws.rs.Path; | ||||||
|  | import jakarta.ws.rs.QueryParam; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | 
 | ||||||
|  | @Path("/training_plan") | ||||||
|  | @ApplicationScoped | ||||||
|  | public class TrainingPlanApi { | ||||||
|  |     private final UndergradTrainingPlanApiService trainingPlanApiService; | ||||||
|  |     private final UndergradTrainingPlanPageParser trainingPlanPageParser; | ||||||
|  | 
 | ||||||
|  |     public TrainingPlanApi(UndergradTrainingPlanApiService trainingPlanApiService, | ||||||
|  |                            UndergradTrainingPlanPageParser trainingPlanPageParser) { | ||||||
|  |         this.trainingPlanApiService = trainingPlanApiService; | ||||||
|  |         this.trainingPlanPageParser = trainingPlanPageParser; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @GET | ||||||
|  |     @Path("/") | ||||||
|  |     public String get(String cookie) throws IOException, ApiException, ParseException { | ||||||
|  |         String html =  trainingPlanApiService.getPage(cookie); | ||||||
|  |         return this.parse(html); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @GET | ||||||
|  |     @Path("/agent") | ||||||
|  |     public String agent(@QueryParam("cookie") @NotNull String cookie) | ||||||
|  |             throws IOException, ApiException { | ||||||
|  |         return trainingPlanApiService.getPage(cookie); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @POST | ||||||
|  |     @Path("/parse") | ||||||
|  |     public String parse(String html) throws ParseException { | ||||||
|  |         return trainingPlanPageParser.parse(html); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,14 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.physics.api.json.handler; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.mywust.exception.ApiException; | ||||||
|  | import jakarta.ws.rs.core.Response; | ||||||
|  | import jakarta.ws.rs.ext.ExceptionMapper; | ||||||
|  | import jakarta.ws.rs.ext.Provider; | ||||||
|  | 
 | ||||||
|  | @Provider | ||||||
|  | public class ApiExceptionHandler extends ExceptionHandlerBase implements ExceptionMapper<ApiException> { | ||||||
|  |     @Override | ||||||
|  |     public Response toResponse(ApiException e) { | ||||||
|  |         return super.toResponse(e.getCodeValue(), e.toString(), "ApiExceptionHandler"); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,21 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.physics.api.json.handler; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.wusthelper.rpc.response.ResponseCode; | ||||||
|  | import jakarta.ws.rs.core.Response; | ||||||
|  | import jakarta.ws.rs.ext.ExceptionMapper; | ||||||
|  | import jakarta.ws.rs.ext.Provider; | ||||||
|  | import lombok.extern.slf4j.Slf4j; | ||||||
|  | 
 | ||||||
|  | @Slf4j | ||||||
|  | @Provider | ||||||
|  | public class DefaultExceptionHandler extends ExceptionHandlerBase implements ExceptionMapper<Exception> { | ||||||
|  |     @Override | ||||||
|  |     public Response toResponse(Exception e) { | ||||||
|  |         log.error("未知异常:", e); | ||||||
|  |         return super.toResponse( | ||||||
|  |                 ResponseCode.SERVER_INTERNAL_ERROR, | ||||||
|  |                 e.toString(), | ||||||
|  |                 "DefaultExceptionHandler" | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,33 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.physics.api.json.handler; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.wusthelper.rpc.response.ResponseCode; | ||||||
|  | import cn.wustlinghang.wusthelper.rpc.response.RpcResponse; | ||||||
|  | import com.fasterxml.jackson.core.JsonProcessingException; | ||||||
|  | import com.fasterxml.jackson.databind.ObjectMapper; | ||||||
|  | import jakarta.ws.rs.core.MediaType; | ||||||
|  | import jakarta.ws.rs.core.Response; | ||||||
|  | 
 | ||||||
|  | public abstract class ExceptionHandlerBase { | ||||||
|  |     public static final String EXCEPTION_HEADER_KEY = "X-exception-handler"; | ||||||
|  | 
 | ||||||
|  |     private static final ObjectMapper objectMapper = new ObjectMapper(); | ||||||
|  | 
 | ||||||
|  |     public Response toResponse(ResponseCode code, String msg, String handlerName) { | ||||||
|  |         return toResponse(code.getCode(), msg, handlerName); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Response toResponse(int code, String msg, String handlerName) { | ||||||
|  |         Object response; | ||||||
|  |         try { | ||||||
|  |             response = objectMapper.writeValueAsString(RpcResponse.error(code, msg)); | ||||||
|  |         } catch (JsonProcessingException e) { | ||||||
|  |             response = RpcResponse.error(ResponseCode.SERVER_INTERNAL_ERROR); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return Response.status(Response.Status.INTERNAL_SERVER_ERROR) | ||||||
|  |                 .entity(response) | ||||||
|  |                 .header(EXCEPTION_HEADER_KEY, handlerName) | ||||||
|  |                 .type(MediaType.APPLICATION_JSON) | ||||||
|  |                 .build(); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,23 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.physics.api.json.handler; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.wusthelper.rpc.response.ResponseCode; | ||||||
|  | import jakarta.ws.rs.core.Response; | ||||||
|  | import jakarta.ws.rs.ext.ExceptionMapper; | ||||||
|  | import jakarta.ws.rs.ext.Provider; | ||||||
|  | import lombok.extern.slf4j.Slf4j; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | 
 | ||||||
|  | @Slf4j | ||||||
|  | @Provider | ||||||
|  | public class IOExceptionHandler extends ExceptionHandlerBase implements ExceptionMapper<IOException> { | ||||||
|  |     @Override | ||||||
|  |     public Response toResponse(IOException e) { | ||||||
|  |         log.error("IO异常:", e); | ||||||
|  |         return super.toResponse( | ||||||
|  |                 ResponseCode.SERVER_INTERNAL_ERROR, | ||||||
|  |                 e.toString(), | ||||||
|  |                 "IOExceptionHandler" | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,22 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.physics.api.json.handler; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.mywust.exception.ParseException; | ||||||
|  | import cn.wustlinghang.wusthelper.rpc.response.ResponseCode; | ||||||
|  | import jakarta.ws.rs.core.Response; | ||||||
|  | import jakarta.ws.rs.ext.ExceptionMapper; | ||||||
|  | import jakarta.ws.rs.ext.Provider; | ||||||
|  | import lombok.extern.slf4j.Slf4j; | ||||||
|  | 
 | ||||||
|  | @Slf4j | ||||||
|  | @Provider | ||||||
|  | public class ParseExceptionHandler extends ExceptionHandlerBase implements ExceptionMapper<ParseException> { | ||||||
|  |     @Override | ||||||
|  |     public Response toResponse(ParseException e) { | ||||||
|  |         log.error("解析异常:", e); | ||||||
|  |         return super.toResponse( | ||||||
|  |                 ResponseCode.SERVER_INTERNAL_ERROR, | ||||||
|  |                 e.toString(), | ||||||
|  |                 "ParseExceptionHandler" | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,22 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.physics.api.json.handler; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.wusthelper.rpc.response.ResponseCode; | ||||||
|  | import jakarta.validation.ValidationException; | ||||||
|  | import jakarta.ws.rs.core.Response; | ||||||
|  | import jakarta.ws.rs.ext.ExceptionMapper; | ||||||
|  | import jakarta.ws.rs.ext.Provider; | ||||||
|  | import lombok.extern.slf4j.Slf4j; | ||||||
|  | 
 | ||||||
|  | @Slf4j | ||||||
|  | @Provider | ||||||
|  | public class ValidationExceptionHandler extends ExceptionHandlerBase | ||||||
|  |         implements ExceptionMapper<ValidationException> { | ||||||
|  |     @Override | ||||||
|  |     public Response toResponse(ValidationException e) { | ||||||
|  |         return super.toResponse( | ||||||
|  |                 ResponseCode.PARAM_WRONG, | ||||||
|  |                 "参数错误:" + e.toString(), | ||||||
|  |                 "ValidationExceptionHandler" | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,36 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.physics.api.json.interceptor; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.wusthelper.internal.physics.api.json.handler.ExceptionHandlerBase; | ||||||
|  | import cn.wustlinghang.wusthelper.rpc.response.RpcResponse; | ||||||
|  | import com.fasterxml.jackson.databind.ObjectMapper; | ||||||
|  | import jakarta.ws.rs.WebApplicationException; | ||||||
|  | import jakarta.ws.rs.core.HttpHeaders; | ||||||
|  | import jakarta.ws.rs.core.MediaType; | ||||||
|  | import jakarta.ws.rs.ext.Provider; | ||||||
|  | import jakarta.ws.rs.ext.WriterInterceptor; | ||||||
|  | import jakarta.ws.rs.ext.WriterInterceptorContext; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | 
 | ||||||
|  | @Provider | ||||||
|  | public class ResponseWrapperInterceptor implements WriterInterceptor { | ||||||
|  |     private final ObjectMapper objectMapper; | ||||||
|  | 
 | ||||||
|  |     public ResponseWrapperInterceptor(ObjectMapper objectMapper) { | ||||||
|  |         this.objectMapper = objectMapper; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException { | ||||||
|  |         boolean hasException = context.getHeaders().get(ExceptionHandlerBase.EXCEPTION_HEADER_KEY) != null; | ||||||
|  |         if (!hasException) { | ||||||
|  |             Object data = context.getEntity(); | ||||||
|  |             RpcResponse<Object> wrappedResponse = RpcResponse.success(data); | ||||||
|  |             String json = objectMapper.writeValueAsString(wrappedResponse); | ||||||
|  |             context.getHeaders().putSingle(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON); | ||||||
|  |             context.setEntity(json); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         context.proceed(); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,12 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.physics.bean; | ||||||
|  | 
 | ||||||
|  | import com.fasterxml.jackson.databind.ObjectMapper; | ||||||
|  | import jakarta.enterprise.context.ApplicationScoped; | ||||||
|  | import jakarta.inject.Singleton; | ||||||
|  | 
 | ||||||
|  | public class JacksonBean { | ||||||
|  |     @ApplicationScoped | ||||||
|  |     public ObjectMapper objectMapper() { | ||||||
|  |         return new ObjectMapper(); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,36 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.physics.bean; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.mywust.core.parser.undergraduate.*; | ||||||
|  | import jakarta.enterprise.context.ApplicationScoped; | ||||||
|  | 
 | ||||||
|  | public class MywustParserBeans { | ||||||
|  |     @ApplicationScoped | ||||||
|  |     public UndergradCourseTableParser undergradCourseTableParser() { | ||||||
|  |         return new UndergradCourseTableParser(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @ApplicationScoped | ||||||
|  |     public UndergradScoreParser undergradScoreParser() { | ||||||
|  |         return new UndergradScoreParser(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @ApplicationScoped | ||||||
|  |     public UndergradStudentInfoPageParser undergradStudentInfoPageParser() { | ||||||
|  |         return new UndergradStudentInfoPageParser(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @ApplicationScoped | ||||||
|  |     public UndergradTrainingPlanPageParser undergradTrainingPlanPageParser() { | ||||||
|  |         return new UndergradTrainingPlanPageParser(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @ApplicationScoped | ||||||
|  |     public UndergradCreditStatusParser undergradCreditStatusParser() { | ||||||
|  |         return new UndergradCreditStatusParser(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @ApplicationScoped | ||||||
|  |     public UndergradExamDelayParser undergradExamDelayParser() { | ||||||
|  |         return new UndergradExamDelayParser(); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,63 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.physics.bean; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.mywust.core.request.service.auth.UndergraduateLogin; | ||||||
|  | import cn.wustlinghang.mywust.core.request.service.undergraduate.*; | ||||||
|  | import cn.wustlinghang.mywust.network.RequestClientOption; | ||||||
|  | import cn.wustlinghang.mywust.network.Requester; | ||||||
|  | import cn.wustlinghang.mywust.network.okhttp.SimpleOkhttpRequester; | ||||||
|  | import jakarta.inject.Singleton; | ||||||
|  | 
 | ||||||
|  | public class MywustRequestAgentBeans { | ||||||
|  | 
 | ||||||
|  |     @Singleton | ||||||
|  |     public RequestClientOption requestClientOption() { | ||||||
|  |         RequestClientOption.Proxy proxy = RequestClientOption.Proxy.builder() | ||||||
|  |                 .address("127.0.0.1") | ||||||
|  |                 .port(8080) | ||||||
|  |                 .build(); | ||||||
|  |         RequestClientOption option = new RequestClientOption(); | ||||||
|  | //        option.setProxy(proxy);
 | ||||||
|  | 
 | ||||||
|  |         return option; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Singleton | ||||||
|  |     public Requester requester(RequestClientOption option) { | ||||||
|  |         return new SimpleOkhttpRequester(option, true); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Singleton | ||||||
|  |     public UndergraduateLogin undergraduateLogin(Requester requester) { | ||||||
|  |         return new UndergraduateLogin(requester); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Singleton | ||||||
|  |     public UndergradCourseTableApiService undergradCourseTableApiService(Requester requester) { | ||||||
|  |         return new UndergradCourseTableApiService(requester); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Singleton | ||||||
|  |     public UndergradScoreApiService undergradScoreApiService(Requester requester) { | ||||||
|  |         return new UndergradScoreApiService(requester); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Singleton | ||||||
|  |     public UndergradStudentInfoApiService undergradStudentInfoApiService(Requester requester) { | ||||||
|  |         return new UndergradStudentInfoApiService(requester); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Singleton | ||||||
|  |     public UndergradTrainingPlanApiService undergradTrainingPlanApiService(Requester requester) { | ||||||
|  |         return new UndergradTrainingPlanApiService(requester); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Singleton | ||||||
|  |     public UndergradCreditStatusApiService undergradCreditStatusApiService(Requester requester) { | ||||||
|  |         return new UndergradCreditStatusApiService(requester); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Singleton | ||||||
|  |     public UndergradExamDelayApiService undergradExamDelayApiService(Requester requester) { | ||||||
|  |         return new UndergradExamDelayApiService(requester); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,32 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.physics.services; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.mywust.core.request.service.auth.UndergraduateLogin; | ||||||
|  | import cn.wustlinghang.mywust.exception.ApiException; | ||||||
|  | import cn.wustlinghang.mywust.network.RequestClientOption; | ||||||
|  | import jakarta.enterprise.context.ApplicationScoped; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | 
 | ||||||
|  | @ApplicationScoped | ||||||
|  | public class LoginService { | ||||||
|  |     private final RequestClientOption option; | ||||||
|  |     private final UndergraduateLogin undergraduateLogin; | ||||||
|  | 
 | ||||||
|  |     public LoginService(RequestClientOption option, | ||||||
|  |                         UndergraduateLogin undergraduateLogin) { | ||||||
|  |         this.option = option; | ||||||
|  |         this.undergraduateLogin = undergraduateLogin; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String login(String username, String password, boolean legacy) throws IOException, ApiException { | ||||||
|  |         if (legacy) { | ||||||
|  |             return undergraduateLogin.getLoginCookieLegacy(username, password, option); | ||||||
|  |         } else { | ||||||
|  |             return undergraduateLogin.getLoginCookie(username, password, option); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public boolean verify(String cookie) throws IOException { | ||||||
|  |         return !undergraduateLogin.checkCookiesFail(cookie); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,60 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.physics.services; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.mywust.core.parser.undergraduate.*; | ||||||
|  | import cn.wustlinghang.mywust.data.global.Course; | ||||||
|  | import cn.wustlinghang.mywust.data.global.Score; | ||||||
|  | import cn.wustlinghang.mywust.data.global.StudentInfo; | ||||||
|  | import cn.wustlinghang.mywust.data.undergrad.ExamDelayApplication; | ||||||
|  | import cn.wustlinghang.mywust.exception.ParseException; | ||||||
|  | import jakarta.enterprise.context.ApplicationScoped; | ||||||
|  | 
 | ||||||
|  | import java.util.List; | ||||||
|  | 
 | ||||||
|  | @ApplicationScoped | ||||||
|  | public class ParseService { | ||||||
|  |     private final UndergradCourseTableParser courseTableParser; | ||||||
|  |     private final UndergradScoreParser scoreParser; | ||||||
|  |     private final UndergradStudentInfoPageParser studentInfoPageParser; | ||||||
|  |     private final UndergradTrainingPlanPageParser trainingPlanPageParser; | ||||||
|  |     private final UndergradCreditStatusParser creditStatusParser; | ||||||
|  |     private final UndergradExamDelayParser examDelayParser; | ||||||
|  | 
 | ||||||
|  |     public ParseService(UndergradCourseTableParser courseTableParser, | ||||||
|  |                         UndergradScoreParser scoreParser, | ||||||
|  |                         UndergradStudentInfoPageParser studentInfoPageParser, | ||||||
|  |                         UndergradTrainingPlanPageParser trainingPlanPageParser, | ||||||
|  |                         UndergradCreditStatusParser creditStatusParser, | ||||||
|  |                         UndergradExamDelayParser examDelayParser) { | ||||||
|  | 
 | ||||||
|  |         this.courseTableParser = courseTableParser; | ||||||
|  |         this.scoreParser = scoreParser; | ||||||
|  |         this.studentInfoPageParser = studentInfoPageParser; | ||||||
|  |         this.trainingPlanPageParser = trainingPlanPageParser; | ||||||
|  |         this.creditStatusParser = creditStatusParser; | ||||||
|  |         this.examDelayParser = examDelayParser; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public List<Course> parseCourseTable(String data) throws ParseException { | ||||||
|  |         return courseTableParser.parse(data); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public List<Score> parseScore(String data) throws ParseException { | ||||||
|  |         return scoreParser.parse(data); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public StudentInfo parseStudentInfo(String data) throws ParseException { | ||||||
|  |         return studentInfoPageParser.parse(data); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String parseTrainingPlan(String data) throws ParseException { | ||||||
|  |         return trainingPlanPageParser.parse(data); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String parseCreditStatus(String data) throws ParseException { | ||||||
|  |         return creditStatusParser.parse(data); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public List<ExamDelayApplication> parseExamDelayApplications(String data) throws ParseException { | ||||||
|  |         return examDelayParser.parse(data); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,62 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.physics.services; | ||||||
|  | 
 | ||||||
|  | import cn.wustlinghang.mywust.core.request.service.undergraduate.*; | ||||||
|  | import cn.wustlinghang.mywust.exception.ApiException; | ||||||
|  | import jakarta.enterprise.context.ApplicationScoped; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | 
 | ||||||
|  | @ApplicationScoped | ||||||
|  | public class RequestAgentService { | ||||||
|  |     private final UndergradCourseTableApiService courseTableApiService; | ||||||
|  |     private final UndergradScoreApiService scoreApiService; | ||||||
|  |     private final UndergradStudentInfoApiService studentInfoApiService; | ||||||
|  |     private final UndergradTrainingPlanApiService trainingPlanApiService; | ||||||
|  |     private final UndergradCreditStatusApiService creditStatusApiService; | ||||||
|  |     private final UndergradExamDelayApiService examDelayApiService; | ||||||
|  | 
 | ||||||
|  |     public RequestAgentService(UndergradCourseTableApiService courseTableApiService, | ||||||
|  |                                UndergradScoreApiService scoreApiService, | ||||||
|  |                                UndergradStudentInfoApiService studentInfoApiService, | ||||||
|  |                                UndergradTrainingPlanApiService trainingPlanApiService, | ||||||
|  |                                UndergradCreditStatusApiService creditStatusApiService, | ||||||
|  |                                UndergradExamDelayApiService examDelayApiService) { | ||||||
|  | 
 | ||||||
|  |         this.courseTableApiService = courseTableApiService; | ||||||
|  |         this.scoreApiService = scoreApiService; | ||||||
|  |         this.studentInfoApiService = studentInfoApiService; | ||||||
|  |         this.trainingPlanApiService = trainingPlanApiService; | ||||||
|  |         this.creditStatusApiService = creditStatusApiService; | ||||||
|  |         this.examDelayApiService = examDelayApiService; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String getStudentInfoPage(String cookie) throws IOException, ApiException { | ||||||
|  |         return studentInfoApiService.getPage(cookie); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String getCourseTable(String cookie, String term) throws IOException, ApiException { | ||||||
|  |         return courseTableApiService.getPage(term, cookie); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String getScore(String cookie) throws IOException, ApiException { | ||||||
|  |         return scoreApiService.getPage(cookie); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String getTrainingPlan(String cookie) throws IOException, ApiException { | ||||||
|  |         return trainingPlanApiService.getPage(cookie); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String getCreditStatus(String cookie) throws IOException, ApiException { | ||||||
|  |         return creditStatusApiService.getPage(cookie, null, false); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public UndergradExamDelayApiService.ExamActivity[] getExamActivities(String cookie, String term) | ||||||
|  |             throws IOException, ApiException { | ||||||
|  |         return examDelayApiService.getActivities(term, cookie); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String getExamDelayApplications(String cookie, String term, String activityId) | ||||||
|  |             throws IOException, ApiException { | ||||||
|  |         return examDelayApiService.getPage(term, activityId, cookie); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,152 @@ | |||||||
|  | <!DOCTYPE html> | ||||||
|  | <html lang="en"> | ||||||
|  | <head> | ||||||
|  |     <meta charset="UTF-8"> | ||||||
|  |     <title>getting-started - 1.0.0-SNAPSHOT</title> | ||||||
|  |     <style> | ||||||
|  |         h1, h2, h3, h4, h5, h6 { | ||||||
|  |             margin-bottom: 0.5rem; | ||||||
|  |             font-weight: 400; | ||||||
|  |             line-height: 1.5; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         h1 { | ||||||
|  |             font-size: 2.5rem; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         h2 { | ||||||
|  |             font-size: 2rem | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         h3 { | ||||||
|  |             font-size: 1.75rem | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         h4 { | ||||||
|  |             font-size: 1.5rem | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         h5 { | ||||||
|  |             font-size: 1.25rem | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         h6 { | ||||||
|  |             font-size: 1rem | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         .lead { | ||||||
|  |             font-weight: 300; | ||||||
|  |             font-size: 2rem; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         .banner { | ||||||
|  |             font-size: 2.7rem; | ||||||
|  |             margin: 0; | ||||||
|  |             padding: 2rem 1rem; | ||||||
|  |             background-color: #00A1E2; | ||||||
|  |             color: white; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         body { | ||||||
|  |             margin: 0; | ||||||
|  |             font-family: -apple-system, system-ui, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         code { | ||||||
|  |             font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; | ||||||
|  |             font-size: 87.5%; | ||||||
|  |             color: #e83e8c; | ||||||
|  |             word-break: break-word; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         .left-column { | ||||||
|  |             padding: .75rem; | ||||||
|  |             max-width: 75%; | ||||||
|  |             min-width: 55%; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         .right-column { | ||||||
|  |             padding: .75rem; | ||||||
|  |             max-width: 25%; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         .container { | ||||||
|  |             display: flex; | ||||||
|  |             width: 100%; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         li { | ||||||
|  |             margin: 0.75rem; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         .right-section { | ||||||
|  |             margin-left: 1rem; | ||||||
|  |             padding-left: 0.5rem; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         .right-section h3 { | ||||||
|  |             padding-top: 0; | ||||||
|  |             font-weight: 200; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         .right-section ul { | ||||||
|  |             border-left: 0.3rem solid #00A1E2; | ||||||
|  |             list-style-type: none; | ||||||
|  |             padding-left: 0; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     </style> | ||||||
|  | </head> | ||||||
|  | <body> | ||||||
|  | 
 | ||||||
|  | <div class="banner lead"> | ||||||
|  |     Your new Cloud-Native application is ready! | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | <div class="container"> | ||||||
|  |     <div class="left-column"> | ||||||
|  |         <p class="lead"> Congratulations, you have created a new Quarkus application.</p> | ||||||
|  | 
 | ||||||
|  |         <h2>Why do you see this?</h2> | ||||||
|  | 
 | ||||||
|  |         <p>This page is served by Quarkus. The source is in | ||||||
|  |             <code>src/main/resources/META-INF/resources/index.html</code>.</p> | ||||||
|  | 
 | ||||||
|  |         <h2>What can I do from here?</h2> | ||||||
|  | 
 | ||||||
|  |         <p>If not already done, run the application in <em>dev mode</em> using: <code>mvn quarkus:dev</code>. | ||||||
|  |         </p> | ||||||
|  |         <ul> | ||||||
|  |           <li>Add REST resources, Servlets, functions and other services in <code>src/main/java</code>.</li> | ||||||
|  |           <li>Your static assets are located in <code>src/main/resources/META-INF/resources</code>.</li> | ||||||
|  |           <li>Configure your application in <code>src/main/resources/application.properties</code>. | ||||||
|  |           </li> | ||||||
|  |         </ul> | ||||||
|  | 
 | ||||||
|  |         <h2>How do I get rid of this page?</h2> | ||||||
|  |         <p>Just delete the <code>src/main/resources/META-INF/resources/index.html</code> file.</p> | ||||||
|  |     </div> | ||||||
|  |     <div class="right-column"> | ||||||
|  |         <div class="right-section"> | ||||||
|  |             <h3>Application</h3> | ||||||
|  |             <ul> | ||||||
|  |                 <li>GroupId: org.acme</li> | ||||||
|  |                 <li>ArtifactId: getting-started</li> | ||||||
|  |                 <li>Version: 1.0.0-SNAPSHOT</li> | ||||||
|  |                 <li>Quarkus Version: 0.11.0</li> | ||||||
|  |             </ul> | ||||||
|  |         </div> | ||||||
|  |         <div class="right-section"> | ||||||
|  |             <h3>Next steps</h3> | ||||||
|  |             <ul> | ||||||
|  |                 <li><a href="https://quarkus.io/guides/maven-tooling.html">Setup your IDE</a></li> | ||||||
|  |                 <li><a href="https://quarkus.io/guides/getting-started-guide.html">Getting started</a></li> | ||||||
|  |                 <li><a href="https://quarkus.io">Quarkus Web Site</a></li> | ||||||
|  |             </ul> | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | </body> | ||||||
|  | </html> | ||||||
| @ -0,0 +1,11 @@ | |||||||
|  | quarkus.http.port=22800 | ||||||
|  | #quarkus.log.level=DEBUG | ||||||
|  | quarkus.log.file.encoding=UTF-8 | ||||||
|  | 
 | ||||||
|  | # 打包成jar时附带依赖 | ||||||
|  | quarkus.package.type=uber-jar | ||||||
|  | 
 | ||||||
|  | # 原生镜像编译附加参数,去掉后编译会失败 | ||||||
|  | # 但也只是能编译完成,目前的编译产物完全不可用,有非常多的严重bug | ||||||
|  | # 现阶段使用jar运行,启动效率虽不如原生程序,但速度尚可 | ||||||
|  | quarkus.native.additional-build-args="--initialize-at-run-time=cn.wustlinghang.mywust" | ||||||
| @ -0,0 +1,16 @@ | |||||||
|  | package cn.wustlinghang.wusthelper.internal.undergrad; | ||||||
|  | 
 | ||||||
|  | import io.quarkus.runtime.Startup; | ||||||
|  | import jakarta.annotation.PostConstruct; | ||||||
|  | import jakarta.inject.Singleton; | ||||||
|  | import lombok.extern.slf4j.Slf4j; | ||||||
|  | 
 | ||||||
|  | @Slf4j | ||||||
|  | @Startup | ||||||
|  | @Singleton | ||||||
|  | public class Main { | ||||||
|  |     @PostConstruct | ||||||
|  |     public void run() { | ||||||
|  |         log.info("Undergrad service started."); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -1,4 +0,0 @@ | |||||||
| package cn.wustlinghang.wusthelper.internal.undergrad.exception; |  | ||||||
| 
 |  | ||||||
| public class InternalException extends Exception { |  | ||||||
| } |  | ||||||
					Loading…
					
					
				
		Reference in new issue