From 5f817f3dfcdc877c2af956ceee7427803e344006 Mon Sep 17 00:00:00 2001 From: Thastertyn Date: Tue, 23 May 2023 21:14:48 +0200 Subject: [PATCH] Renamed and comment a lot of stuff, fixed a bunch of bugs --- .../thastertyn/Login/CredentialsInput.java | 16 +- .../thastertyn/Login/LocalCredentials.java | 65 +++++--- src/main/java/xyz/thastertyn/Login/Login.java | 154 +++++++++--------- .../xyz/thastertyn/Login/LoginController.java | 68 +++++--- .../xyz/thastertyn/Scrape/AbsenceList.java | 123 ++++++++++++++ .../Scrape/{Jidelna.java => Canteen.java} | 2 +- .../xyz/thastertyn/Scrape/Downloader.java | 38 ++++- .../xyz/thastertyn/Scrape/JecnaScrape.java | 19 +++ .../java/xyz/thastertyn/Scrape/Marks.java | 129 +++++++++++++++ .../xyz/thastertyn/Scrape/OmluvnyList.java | 118 -------------- .../Scrape/{Sdeleni.java => Reports.java} | 18 +- .../Scrape/{Rozvrh.java => Timetable.java} | 47 ++---- .../java/xyz/thastertyn/Scrape/Znamky.java | 130 --------------- src/main/java/xyz/thastertyn/Tuples/Pair.java | 54 ------ .../java/xyz/thastertyn/Tuples/Triplet.java | 66 -------- .../xyz/thastertyn/Types/AbsenceList.java | 31 ++++ .../java/xyz/thastertyn/Types/Choice.java | 3 + .../xyz/thastertyn/Types/Credentials.java | 23 +++ .../xyz/thastertyn/Types/DayOfTimetable.java | 3 + .../java/xyz/thastertyn/Types/FinalMark.java | 5 + .../thastertyn/Types/InputtedCredentials.java | 30 ++++ src/main/java/xyz/thastertyn/Types/Mark.java | 34 ++++ .../xyz/thastertyn/Types/OmluvnyList.java | 33 ---- .../java/xyz/thastertyn/Types/Option.java | 10 +- .../java/xyz/thastertyn/Types/Options.java | 3 + .../java/xyz/thastertyn/Types/Predmet.java | 67 -------- .../Types/{Sdeleni.java => Reports.java} | 7 +- .../java/xyz/thastertyn/Types/Subject.java | 80 +++++++++ .../java/xyz/thastertyn/Types/Timetable.java | 3 + .../java/xyz/thastertyn/Types/Znamka.java | 30 ---- .../{OmluvnyList.java => AbsenceList.java} | 12 +- .../Content/{Jidelna.java => Canteen.java} | 2 +- .../UserInterface/Content/JecnaContent.java | 35 +++- .../Content/{Znamky.java => Marks.java} | 52 +++--- .../Content/{Sdeleni.java => Reports.java} | 33 ++-- .../Content/{Rozvrh.java => Timetable.java} | 9 +- .../UserInterface/Dialogs/EscapeDialog.java | 2 +- .../Listeners/ContentResetListener.java | 3 + .../Listeners/WindowSwitchListener.java | 61 ++++--- .../thastertyn/UserInterface/MainWindow.java | 17 +- src/test/java/xyz/thastertyn/AppTest.java | 82 +++++++--- 41 files changed, 935 insertions(+), 782 deletions(-) create mode 100644 src/main/java/xyz/thastertyn/Scrape/AbsenceList.java rename src/main/java/xyz/thastertyn/Scrape/{Jidelna.java => Canteen.java} (96%) create mode 100644 src/main/java/xyz/thastertyn/Scrape/Marks.java delete mode 100644 src/main/java/xyz/thastertyn/Scrape/OmluvnyList.java rename src/main/java/xyz/thastertyn/Scrape/{Sdeleni.java => Reports.java} (58%) rename src/main/java/xyz/thastertyn/Scrape/{Rozvrh.java => Timetable.java} (63%) delete mode 100644 src/main/java/xyz/thastertyn/Scrape/Znamky.java delete mode 100644 src/main/java/xyz/thastertyn/Tuples/Pair.java delete mode 100644 src/main/java/xyz/thastertyn/Tuples/Triplet.java create mode 100644 src/main/java/xyz/thastertyn/Types/AbsenceList.java create mode 100644 src/main/java/xyz/thastertyn/Types/Credentials.java create mode 100644 src/main/java/xyz/thastertyn/Types/InputtedCredentials.java create mode 100644 src/main/java/xyz/thastertyn/Types/Mark.java delete mode 100644 src/main/java/xyz/thastertyn/Types/OmluvnyList.java delete mode 100644 src/main/java/xyz/thastertyn/Types/Predmet.java rename src/main/java/xyz/thastertyn/Types/{Sdeleni.java => Reports.java} (57%) create mode 100644 src/main/java/xyz/thastertyn/Types/Subject.java delete mode 100644 src/main/java/xyz/thastertyn/Types/Znamka.java rename src/main/java/xyz/thastertyn/UserInterface/Content/{OmluvnyList.java => AbsenceList.java} (65%) rename src/main/java/xyz/thastertyn/UserInterface/Content/{Jidelna.java => Canteen.java} (68%) rename src/main/java/xyz/thastertyn/UserInterface/Content/{Znamky.java => Marks.java} (70%) rename src/main/java/xyz/thastertyn/UserInterface/Content/{Sdeleni.java => Reports.java} (55%) rename src/main/java/xyz/thastertyn/UserInterface/Content/{Rozvrh.java => Timetable.java} (84%) diff --git a/src/main/java/xyz/thastertyn/Login/CredentialsInput.java b/src/main/java/xyz/thastertyn/Login/CredentialsInput.java index a70ff32..f038b01 100644 --- a/src/main/java/xyz/thastertyn/Login/CredentialsInput.java +++ b/src/main/java/xyz/thastertyn/Login/CredentialsInput.java @@ -18,8 +18,11 @@ import com.googlecode.lanterna.gui2.dialogs.DialogWindow; import com.googlecode.lanterna.gui2.dialogs.MessageDialog; import com.googlecode.lanterna.gui2.dialogs.MessageDialogButton; -import xyz.thastertyn.Tuples.Triplet; +import xyz.thastertyn.Types.InputtedCredentials; +/** + * A Dialog window for inputing username and password. + */ public class CredentialsInput extends DialogWindow { private TextBox username; @@ -129,6 +132,9 @@ public class CredentialsInput extends DialogWindow { setComponent(mainPanel); } + /** + * User pressed ok, check if anything is actually typed and if so, pack and return it + */ public void onOK() { this.user = username.getText(); @@ -148,9 +154,13 @@ public class CredentialsInput extends DialogWindow { close(); } + /** + * returns the inputted username, password and if user chose to keep credentials stored + * @return {@link InputtedCredentials} with username first, password second and whether to store the credentials third + */ @Override - public Triplet showDialog(WindowBasedTextGUI textGUI) { + public InputtedCredentials showDialog(WindowBasedTextGUI textGUI) { super.showDialog(textGUI); - return new Triplet(user, pass, remember.isChecked()); + return new InputtedCredentials(user, pass, remember.isChecked()); } } diff --git a/src/main/java/xyz/thastertyn/Login/LocalCredentials.java b/src/main/java/xyz/thastertyn/Login/LocalCredentials.java index a8ed630..a05cb51 100644 --- a/src/main/java/xyz/thastertyn/Login/LocalCredentials.java +++ b/src/main/java/xyz/thastertyn/Login/LocalCredentials.java @@ -7,15 +7,9 @@ import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; -public class LocalCredentials { +import xyz.thastertyn.Types.Credentials; - /** - * Checks for already saved credentials, at least if its file exists - * @return
    - *
  • {@code true} a file exists
  • - *
  • {@code false} doesn't exist
  • - *
- */ +public class LocalCredentials { private static LocalCredentials localCredentials = new LocalCredentials(); @@ -24,6 +18,16 @@ public class LocalCredentials { private File credentialsFile; private File credentialsPath; + /** + * Checks for already saved credentials, at least if its file exists
+ * for Windows it checks {@code AppData\Roaming\jecnak\credemtials.txt}
+ * for Linux it checks {@code ~/.local/share/jecnak/credentials.txt}
+ * @return + *
    + *
  • {@code true} a file exists
  • + *
  • {@code false} doesn't exist
  • + *
+ */ public boolean checkForExistingCredentials() { if(System.getProperty("os.name").equals("Linux")) @@ -49,10 +53,17 @@ public class LocalCredentials { return true; } - public String[] getCredentialsFile() + /** + * Try reading the credentails from a local file + * @return String[] with username on index 0, and password on index 1,
+ * can also return null if credentials are corrupted, inaccessible, etc. + */ + public Credentials getCredentialsFile() { // TODO Use hashmap instead of array - String[] result = new String[2]; + String user = null; + String pass = null; + if(credentialsFile == null) { return null; @@ -68,27 +79,33 @@ public class LocalCredentials { if(currentValue[0].equals("user")) { - result[0] = currentValue[1]; + user = currentValue[1]; }else if(currentValue[0].equals("pass")) { - result[1] = currentValue[1]; + pass = currentValue[1]; } } reader.close(); } catch (IOException e) { e.printStackTrace(); + return null; } - if(result[0] == null || result[1] == null) + if(user == null || pass == null) { return null; } - return result; + return new Credentials(user, pass); } - public boolean saveCredentials(String[] credentials) + /** + * appends the current credentials to the file + * @param credentials the array containing username and password. Username is on index 0, password on index 1 + * @return + */ + public boolean saveCredentials(Credentials credentials) { if(credentialsFile == null) { @@ -108,10 +125,10 @@ public class LocalCredentials { try { BufferedWriter writer = new BufferedWriter(new FileWriter(credentialsFile)); - writer.append("user=" + credentials[0]); - writer.append("\n"); - writer.append("pass=" + credentials[1]); - writer.append("\n"); + writer.append(String.format( + "user=%s\npass=%s\n", + credentials.getUsername(), + credentials.getPassword())); writer.close(); } catch (IOException e) { @@ -122,14 +139,20 @@ public class LocalCredentials { return true; } + /** + * Deletes the credentials file + * @return + */ public boolean deleteCredentials() { credentialsFile.delete(); return true; } - private LocalCredentials() {} - + /** + * Returns a single instance to prevent creating and loading the files all over again when not much has changed + * @return {@link LocalCredentials} instance + */ public static LocalCredentials getInstance() { return localCredentials; diff --git a/src/main/java/xyz/thastertyn/Login/Login.java b/src/main/java/xyz/thastertyn/Login/Login.java index c9ad0e5..66cd334 100644 --- a/src/main/java/xyz/thastertyn/Login/Login.java +++ b/src/main/java/xyz/thastertyn/Login/Login.java @@ -12,101 +12,103 @@ import org.jsoup.Connection.Method; import org.jsoup.nodes.Document; import xyz.thastertyn.Scrape.Downloader; +import xyz.thastertyn.Types.Credentials; public class Login { private String Jsessionid = null; - // Check for session expiration - private long start; - private long lastCheck; - - public void loginJecna(String user, String pass) throws UnknownHostException, IOException, CredentialException, TimeoutException + /** + * Tries logging into SPSE Jecna. If it succeeds it also saves the JSessionId into {@link Downloader} for ease of use. If it fails to login, the program is as good as not running at all + * @param credentials {@link Credentials} for username anas password + * @throws UnknownHostException Most likely no internet connection, spsejecna.cz could not be recognised as a host + * @throws IOException by Jsoup + * @throws CredentialException The username or password is incorrect + * @throws TimeoutException Connection timed out, most likely a very slow internet + */ + public void loginJecna(Credentials credentials) throws UnknownHostException, IOException, CredentialException, TimeoutException { - //#region JSESSIONID - Connection.Response response = Jsoup.connect("https://www.spsejecna.cz") - .header("Connection", "keep-alive") - .method(Method.HEAD) - .execute(); + //#region JSESSIONID + Connection.Response response = Jsoup.connect("https://www.spsejecna.cz") + .header("Connection", "keep-alive") + .method(Method.HEAD) + .execute(); - Jsessionid = response.cookie("JSESSIONID"); - Downloader.setJSessionId(Jsessionid); - //#endregion + Jsessionid = response.cookie("JSESSIONID"); + Downloader.setJSessionId(Jsessionid); + //#endregion - //#region Token3 - String token3 = Downloader.download("https://www.spsejecna.cz/user/role?role=student") - .get() - .select("input[name=token3]") - .attr("value"); - //#endregion + //#region Token3 + String token3 = Downloader.getConnection("https://www.spsejecna.cz/user/role?role=student") + .get() + .select("input[name=token3]") + .attr("value"); + //#endregion - //#region Login - Downloader.download("https://www.spsejecna.cz/user/login") - .method(Connection.Method.POST) - .header("Content-Type", "application/x-www-form-urlencoded") - .header("Origin", "https://www.spsejecna.cz") - .data("token3", token3) - .data("user", user) - .data("pass", pass) - .data("submit", "P%C5%99ihl%C3%A1sit+se") - .followRedirects(true) - .execute(); - //#endregion + //#region Login + Downloader.getConnection("https://www.spsejecna.cz/user/login") + .method(Connection.Method.POST) + .header("Content-Type", "application/x-www-form-urlencoded") + .header("Origin", "https://www.spsejecna.cz") + .data("token3", token3) + .data("user", credentials.getUsername()) + .data("pass", credentials.getPassword()) + .data("submit", "P%C5%99ihl%C3%A1sit+se") + .followRedirects(true) + .execute(); + //#endregion - Document test = Downloader.download("https://www.spsejecna.cz/score/student") - .get(); + Document test = Downloader.getConnection("https://www.spsejecna.cz/score/student") + .get(); - if(test.toString().contains("Pro pokračování se přihlaste do systému")) - { - throw new CredentialException("Incorrect username or password"); - } - - start = System.currentTimeMillis() / 1000L; - lastCheck = start; + if(test.toString().contains("Pro pokračování se přihlaste do systému")) + { + throw new CredentialException("Incorrect username or password"); + } } public void loginJidelna(String user, String pass) throws UnknownHostException, IOException { - //#region JSESSIONID - Connection.Response jidelna = Jsoup.connect("https://objednavky.jidelnasokolska.cz/") - .header("Connection", "keep-alive") - .method(Method.HEAD) - .execute(); + //#region JSESSIONID + Connection.Response jidelna = Jsoup.connect("https://objednavky.jidelnasokolska.cz/") + .header("Connection", "keep-alive") + .method(Method.HEAD) + .execute(); - String jidelnaJSESSIONID = jidelna.cookie("JSESSIONID"); - String XSRF_TOKEN = jidelna.cookie("XSRF-TOKEN"); - //#endregion + String jidelnaJSESSIONID = jidelna.cookie("JSESSIONID"); + String XSRF_TOKEN = jidelna.cookie("XSRF-TOKEN"); + //#endregion - //#region CSRF - String csrf = Jsoup.connect("https://objednavky.jidelnasokolska.cz/faces/login.jsp") - .header("Connection", "keep-alive") - .cookie("XSRF-TOKEN", XSRF_TOKEN) - .cookie("JSESSIONID", jidelnaJSESSIONID) - .get() - .select("input[name=_csrf]") - .attr("value"); + //#region CSRF + String csrf = Jsoup.connect("https://objednavky.jidelnasokolska.cz/faces/login.jsp") + .header("Connection", "keep-alive") + .cookie("XSRF-TOKEN", XSRF_TOKEN) + .cookie("JSESSIONID", jidelnaJSESSIONID) + .get() + .select("input[name=_csrf]") + .attr("value"); - if(!XSRF_TOKEN.equals(csrf)) - { - throw new SecurityException("CSRF tokens do not match, something is up"); - } - //#endregion + if(!XSRF_TOKEN.equals(csrf)) + { + throw new SecurityException("CSRF tokens do not match, something is up"); + } + //#endregion - //#region Login - Jsoup.connect("https://objednavky.jidelnasokolska.cz/j_spring_security_check") - .header("Connection", "keep-alive") - .header("Content-Type", "application/x-www-form-urlencoded") - .cookie("XSRF-TOKEN", XSRF_TOKEN) - .cookie("JSESSIONID", jidelnaJSESSIONID) - .data("j_username", user) - .data("j_password", pass) - .data("terminal", "false") - .data("type", "web") - .data("_csrf", XSRF_TOKEN) - .data("targetUrl", "/faces/secured/main.jsp?terminal=false&status=true&printer=false&keyboard=false") - .method(Method.POST) - .execute(); - //#endregion + //#region Login + Jsoup.connect("https://objednavky.jidelnasokolska.cz/j_spring_security_check") + .header("Connection", "keep-alive") + .header("Content-Type", "application/x-www-form-urlencoded") + .cookie("XSRF-TOKEN", XSRF_TOKEN) + .cookie("JSESSIONID", jidelnaJSESSIONID) + .data("j_username", user) + .data("j_password", pass) + .data("terminal", "false") + .data("type", "web") + .data("_csrf", XSRF_TOKEN) + .data("targetUrl", "/faces/secured/main.jsp?terminal=false&status=true&printer=false&keyboard=false") + .method(Method.POST) + .execute(); + //#endregion } } diff --git a/src/main/java/xyz/thastertyn/Login/LoginController.java b/src/main/java/xyz/thastertyn/Login/LoginController.java index 4a45ad7..c05a15e 100644 --- a/src/main/java/xyz/thastertyn/Login/LoginController.java +++ b/src/main/java/xyz/thastertyn/Login/LoginController.java @@ -10,8 +10,12 @@ import com.googlecode.lanterna.gui2.WindowBasedTextGUI; import com.googlecode.lanterna.gui2.dialogs.MessageDialog; import com.googlecode.lanterna.gui2.dialogs.MessageDialogButton; -import xyz.thastertyn.Tuples.Triplet; +import xyz.thastertyn.Types.Credentials; +import xyz.thastertyn.Types.InputtedCredentials; +/** + * Merges the functionality of {@link LocalCredentials}, {@link CredentialsInput}, and {@link Login} + */ public class LoginController { private WindowBasedTextGUI textGUI; @@ -24,58 +28,72 @@ public class LoginController { this.textGUI = textGUI; } - public void login() + /** + * Picks appropriate method for logging in + *
    + *
  • Locally stored credentials exist, then try using them. If they arent in good shape, use GUI + *
  • Use GUI and ask the user for credentials + *
+ */ + public void login(boolean forceGUI) { - String[] credentials; + Credentials credentials; - if(localCredentials.checkForExistingCredentials()) // Credentials exist + if(!forceGUI && localCredentials.checkForExistingCredentials()) { credentials = localCredentials.getCredentialsFile(); }else{ - Triplet data = loginUsingGui(); // Failed to get credentials to log in, get them from user - credentials = new String[] {data.getValue0(), data.getValue1()}; - - if(data.getValue2()) - { - localCredentials.saveCredentials(credentials); - } + credentials = loginUsingGui(); } - - loginUsingCredentials(credentials); + + useCredentials(credentials); } - public Triplet loginUsingGui() + public Credentials loginUsingGui() { dialog = new CredentialsInput(); - - return dialog.showDialog(textGUI); // Failed to get credentials to log in, get them from user + + InputtedCredentials credentials = dialog.showDialog(textGUI); + + if(credentials.save()) + { + localCredentials.saveCredentials(credentials.getCredentials()); + } + + return credentials.getCredentials(); } - private void loginUsingCredentials(String[] credentials) + /** + * Credentials were successfully obtained and are used for logging in, although a lot can go wrong + * @param credentials + */ + private void useCredentials(Credentials credentials) { try { - login.loginJecna(credentials[0], credentials[1]); + login.loginJecna(credentials); }catch (TimeoutException e) { - MessageDialog.showMessageDialog(textGUI, "Timeout", "The attempt to connect took too long.", MessageDialogButton.Retry, - MessageDialogButton.Abort); + MessageDialog.showMessageDialog(textGUI, "Timeout", "The attempt to connect took too long. The app will quit", MessageDialogButton.OK); + System.exit(0); } catch (UnknownHostException e) { - MessageDialog.showMessageDialog(textGUI, "No Internet connection", + MessageDialog.showMessageDialog(textGUI, "No Internet connection. The app will quit", e.getMessage(), MessageDialogButton.OK); - login(); + System.exit(0); } catch (CredentialException e) { MessageDialog.showMessageDialog(textGUI, "Incorrect username or password", e.getMessage(), MessageDialogButton.OK); - login(); + // The credentials were most likely tampered with after save, just get rid of them and save them another time + LocalCredentials.getInstance().deleteCredentials(); + login(true); } catch (IOException e) { - MessageDialog.showMessageDialog(textGUI, "There was an error", + MessageDialog.showMessageDialog(textGUI, "There was an error. The app will quit", e.getMessage(), MessageDialogButton.Retry); - login(); + System.exit(0); } } } diff --git a/src/main/java/xyz/thastertyn/Scrape/AbsenceList.java b/src/main/java/xyz/thastertyn/Scrape/AbsenceList.java new file mode 100644 index 0000000..31d643b --- /dev/null +++ b/src/main/java/xyz/thastertyn/Scrape/AbsenceList.java @@ -0,0 +1,123 @@ +package xyz.thastertyn.Scrape; + +import java.io.IOException; +import java.time.LocalDate; +import java.time.Month; +import java.util.ArrayList; +import java.util.Arrays; + +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.select.Elements; + +import xyz.thastertyn.Types.Choice; +import xyz.thastertyn.Types.Option; +import xyz.thastertyn.Types.Options; + +public class AbsenceList extends JecnaScrape { + + private ArrayList data; + private Choice currentChoice; + + private Options schoolYearOptions; + + @Override + public void download() throws IOException + { + parse("https://www.spsejecna.cz/absence/student"); + } + + @Override + public void download(Choice choice) throws IOException { + + currentChoice = choice; + + parse(String.format( + "https://www.spsejecna.cz/absence/student?schoolYearId=%s", + choice.getChoices().get(0))); + } + + private void parse(String url) throws IOException + { + data = new ArrayList<>(); + schoolYearOptions = new Options("Skolni R."); + Document absenceListHTMLDocument = Downloader.download(url); + + Elements absenceLists = absenceListHTMLDocument.select("table.absence-list").select("tbody").select("tr"); + + for(Element e : absenceLists) + { + String date = e.child(0).text(); + + + String text = e.child(1).text(); + + data.add( + new xyz.thastertyn.Types.AbsenceList( + date, text)); + } + + Elements options = absenceListHTMLDocument.select("form.listConfigure").select("select[id=schoolYearId]").select("option"); + + for(Element e : options) + { + boolean isDefault = e.hasAttr("selected"); + schoolYearOptions.addOption(new Option(e.text(), e.attr("value"), isDefault)); + } + + currentChoice = new Choice(Arrays.asList(schoolYearOptions.getOptions().get(0).getValue())); + } + + /** + * Convert text to a {@link LocalDate} and try to guess the year + * @param text to be parsed + * @return {@link LocalDate} parsed + */ + // private LocalDate parseDate(String text) + // { + // int year = 0, month = 0, day = 0; + // String[] split = text.split("\\."); + + // day = Integer.parseInt(split[0]); + // month = Integer.parseInt(split[1]); + + // if(currentChoice == null) + // { + // // Pick the current year + // int currYear = LocalDate.now().getYear(); + // int currMonth = LocalDate.now().getMonthValue(); + + // if(month > currMonth && currMonth < 8) + // { + // year = currYear; + // }else if(month < currMonth && currMonth > 8) + // { + // year = currYear + 1; + // }else if(month < currMonth && currMonth < 8) + // { + // year = currYear; + // } + // }else{ + // year = Integer.parseInt(currentChoice.getChoices().get(0)); + // } + + // return LocalDate.of(year, Month.of(month), day); + // } + + @Override + public Options[] getOptions() { + return new Options[] {schoolYearOptions}; + } + + public ArrayList getData() + { + return data; + } + + @Override + public String toString() + { + return (!data.isEmpty()) ? data.toString() : null; + } + +} diff --git a/src/main/java/xyz/thastertyn/Scrape/Jidelna.java b/src/main/java/xyz/thastertyn/Scrape/Canteen.java similarity index 96% rename from src/main/java/xyz/thastertyn/Scrape/Jidelna.java rename to src/main/java/xyz/thastertyn/Scrape/Canteen.java index 505d8d0..0f3674a 100644 --- a/src/main/java/xyz/thastertyn/Scrape/Jidelna.java +++ b/src/main/java/xyz/thastertyn/Scrape/Canteen.java @@ -5,7 +5,7 @@ import java.io.IOException; import xyz.thastertyn.Types.Choice; import xyz.thastertyn.Types.Options; -public class Jidelna extends JecnaScrape { +public class Canteen extends JecnaScrape { //public void foo() //{ diff --git a/src/main/java/xyz/thastertyn/Scrape/Downloader.java b/src/main/java/xyz/thastertyn/Scrape/Downloader.java index ed3316c..edf3759 100644 --- a/src/main/java/xyz/thastertyn/Scrape/Downloader.java +++ b/src/main/java/xyz/thastertyn/Scrape/Downloader.java @@ -1,24 +1,50 @@ package xyz.thastertyn.Scrape; +import java.io.IOException; + import org.jsoup.Connection; import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; public class Downloader { private static String JsessionId; - public static Connection download(String url) + /** + * Provide a general Jsoup Connection for simplicity with some predefined values and JSessionId already set + * @param url + * @return HTML Document downloaded. If it fails, null + */ + public static Document download(String url) throws IOException { - Connection c = Jsoup.connect(url) + return Jsoup.connect(url) .header("Connection", "keep-alive") .cookie("role", "student") .cookie("JSESSIONID", JsessionId) - .timeout(10000); - return c; + .timeout(10000) + .get(); } - public static void setJSessionId(String JsId) + /** + * Returns a basic {@link Connection} with some predefined headers + * @param url + * @return {@link Connection} with timeout for 10s, and headers needed for downloading from spsejecna.cz + */ + public static Connection getConnection(String url) { - JsessionId = JsId; + return Jsoup.connect(url) + .header("Connection", "keep-alive") + .cookie("role", "student") + .cookie("JSESSIONID", JsessionId) + .timeout(10000); + } + + /** + * Sets JsessionId + * @param newJsessionId JsessionId + */ + public static void setJSessionId(String newJsessionId) + { + JsessionId = newJsessionId; } } diff --git a/src/main/java/xyz/thastertyn/Scrape/JecnaScrape.java b/src/main/java/xyz/thastertyn/Scrape/JecnaScrape.java index 637536b..045a85f 100644 --- a/src/main/java/xyz/thastertyn/Scrape/JecnaScrape.java +++ b/src/main/java/xyz/thastertyn/Scrape/JecnaScrape.java @@ -5,9 +5,28 @@ import java.io.IOException; import xyz.thastertyn.Types.Choice; import xyz.thastertyn.Types.Options; +/** + * Abstract class to wrap around everything that scrapes some data. Most of them also have getData or something similiar, + * but the data types are just so vastly different, they couldnt be wrapped as abstract method and abstract class + */ public abstract class JecnaScrape { + /** + * returns possible options, like school year or half year + * @return {@link Options} array, for when there are more options available + */ public abstract Options[] getOptions(); + + /** + * Downloads the chosen url, given the {@link Choice} which includes all the needed data + * @param choice of any possible data like school year or half year + * @throws IOException like any other download method, in case no internet, timeout, etc. + */ public abstract void download(Choice choice) throws IOException; + + /** + * Downloads the default url, without any parameters + * @throws IOException in case of timeout, no internet, etc. + */ public abstract void download() throws IOException; } diff --git a/src/main/java/xyz/thastertyn/Scrape/Marks.java b/src/main/java/xyz/thastertyn/Scrape/Marks.java new file mode 100644 index 0000000..574f3fb --- /dev/null +++ b/src/main/java/xyz/thastertyn/Scrape/Marks.java @@ -0,0 +1,129 @@ +package xyz.thastertyn.Scrape; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.regex.Pattern; + +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.select.Elements; + +import xyz.thastertyn.Types.Choice; +import xyz.thastertyn.Types.FinalMark; +import xyz.thastertyn.Types.Option; +import xyz.thastertyn.Types.Options; +import xyz.thastertyn.Types.Subject; +import xyz.thastertyn.Types.Mark; + +public class Marks extends JecnaScrape { + + // schoolYear, schoolYearId + private ArrayList subjects; + + // int znaci id roku, boolean jestli je jen prvni nebo i druhe pololeti + private Options schoolYearOptions; + private Options schoolHalfYearOptions; + + public void download() throws IOException + { + download("https://www.spsejecna.cz/score/student"); + } + + @Override + public void download(Choice choice) throws IOException + { + download(String.format( + "https://www.spsejecna.cz/score/student?schoolYearId=%s&schoolYearHalfId=%s", + choice.getChoices().get(0), + choice.getChoices().get(1))); + } + + private void download(String url) throws IOException + { + schoolHalfYearOptions = new Options("Pololeti"); + schoolYearOptions = new Options("Skolni R."); + + subjects = new ArrayList<>(); + Document marksHTMLDocument = Downloader.download(url); + + // Subjects stored as + Elements[] subjectRowsHTML = marksHTMLDocument + .select("table.score") + .select("tr") + .stream() + .map(Element::children) + .toArray(Elements[]::new); + + int subjectIndex = 0; + + for(int i = 1; i < subjectRowsHTML.length; i++) + { + String fullSubjectName = subjectRowsHTML[i].get(0).text(); + + // Attempt to shorten the subject name to the string in brackets + String shortSubjectName = Pattern + .compile("\\((.*?)\\)") + .matcher(fullSubjectName) + .results() + .findFirst() + .map(m -> m.group(1)) + .orElse(fullSubjectName); + + if(subjectRowsHTML[i].get(2).childrenSize() == 0) // Subject doesn't have final mark yet + { + subjects.add(new Subject(shortSubjectName)); + }else{ + String finalMark = subjectRowsHTML[i].get(2).select("a.scoreFinal").text(); + subjects.add(new Subject(shortSubjectName, FinalMark.fromValue(finalMark))); + } + + for(Element znamkaElement : subjectRowsHTML[i].get(1).select("a.score")) + { + int mark; + boolean isSmall = false; + + String markText = znamkaElement.select("span.value").text(); + + mark = markText.matches("\\d") ? + Integer.parseInt(markText) + : + -1; // Most likely N (Nehodnocen) + + // Small mark will be counted with smaller weight, compared to normal one + isSmall = znamkaElement.hasClass("scoreSmall"); + + subjects.get(subjectIndex).addMark(new Mark(mark, isSmall, markText)); + } + + subjectIndex++; + } + + Element optionsPanel = marksHTMLDocument.selectFirst("form.listConfigure"); + + Elements schoolYears = optionsPanel.select("select[id=schoolYearId]").select("option"); + Elements halfYears = optionsPanel.select("select[id=schoolYearHalfId]").select("option"); + + + for(Element e : schoolYears) + { + boolean isDefault = e.hasAttr("selected"); + schoolYearOptions.addOption(new Option(e.text(), e.attr("value"), isDefault)); + } + + for(Element e : halfYears) + { + boolean isDefault = e.hasAttr("selected"); + schoolHalfYearOptions.addOption(new Option(e.text(), e.attr("value"), isDefault)); + } + } + + public ArrayList getSubjects() + { + return subjects; + } + + public Options[] getOptions() + { + return new Options[] {schoolYearOptions, schoolHalfYearOptions}; + } +} \ No newline at end of file diff --git a/src/main/java/xyz/thastertyn/Scrape/OmluvnyList.java b/src/main/java/xyz/thastertyn/Scrape/OmluvnyList.java deleted file mode 100644 index b89de51..0000000 --- a/src/main/java/xyz/thastertyn/Scrape/OmluvnyList.java +++ /dev/null @@ -1,118 +0,0 @@ -package xyz.thastertyn.Scrape; - -import java.io.IOException; -import java.time.LocalDate; -import java.time.Month; -import java.util.ArrayList; -import java.util.Arrays; - -import org.jsoup.nodes.Document; -import org.jsoup.nodes.Element; -import org.jsoup.select.Elements; - -import xyz.thastertyn.Types.Choice; -import xyz.thastertyn.Types.Option; -import xyz.thastertyn.Types.Options; - -public class OmluvnyList extends JecnaScrape { - - private ArrayList data; - private Choice currentChoice; - - private Options schoolYearOptions; - - @Override - public void download() throws IOException - { - download("https://www.spsejecna.cz/absence/student"); - } - - @Override - public void download(Choice choice) throws IOException { - - currentChoice = choice; - - download(String.format( - "https://www.spsejecna.cz/absence/student?schoolYearId=%s", - choice.getChoices().get(0))); - } - - private void download(String url) throws IOException - { - data = new ArrayList<>(); - schoolYearOptions = new Options("Skolni R."); - Document omluvnyListDokumentHTML = Downloader.download(url).get(); - - Elements omluvneListy = omluvnyListDokumentHTML.select("table.absence-list").select("tbody").select("tr"); - - for(Element e : omluvneListy) - { - String date = e.child(0).text(); - - - String text = e.child(1).text(); - - data.add( - new xyz.thastertyn.Types.OmluvnyList( - parseDate(date), text)); - } - - Elements options = omluvnyListDokumentHTML.select("form.listConfigure").select("select[id=schoolYearId]").select("option"); - - for(Element e : options) - { - boolean isDefault = e.hasAttr("selected"); - schoolYearOptions.addOption(new Option(e.text(), e.attr("value"), isDefault)); - } - - currentChoice = new Choice(Arrays.asList(schoolYearOptions.getOptions().get(0).getValue())); - } - - private LocalDate parseDate(String text) - { - int year = 0, month = 0, day = 0; - String[] split = text.split("\\."); - - month = Integer.parseInt(split[0]); - day = Integer.parseInt(split[1]); - - if(currentChoice == null) - { - // Pick the current year - int currYear = LocalDate.now().getYear(); - int currMonth = LocalDate.now().getMonthValue(); - - if(month > currMonth && currMonth < 8) - { - year = currYear; - }else if(month < currMonth && currMonth > 8) - { - year = currYear + 1; - }else if(month < currMonth && currMonth < 8) - { - year = currYear; - } - }else{ - year = Integer.parseInt(currentChoice.getChoices().get(0)); - } - - return LocalDate.of(year, Month.of(month), day); - } - - @Override - public Options[] getOptions() { - return new Options[] {schoolYearOptions}; - } - - public ArrayList getData() - { - return data; - } - - @Override - public String toString() - { - return (!data.isEmpty()) ? data.toString() : null; - } - -} diff --git a/src/main/java/xyz/thastertyn/Scrape/Sdeleni.java b/src/main/java/xyz/thastertyn/Scrape/Reports.java similarity index 58% rename from src/main/java/xyz/thastertyn/Scrape/Sdeleni.java rename to src/main/java/xyz/thastertyn/Scrape/Reports.java index 6f4c9d9..ff4ac37 100644 --- a/src/main/java/xyz/thastertyn/Scrape/Sdeleni.java +++ b/src/main/java/xyz/thastertyn/Scrape/Reports.java @@ -11,17 +11,17 @@ import org.jsoup.select.Elements; import xyz.thastertyn.Types.Choice; import xyz.thastertyn.Types.Options; -public class Sdeleni extends JecnaScrape { +public class Reports extends JecnaScrape { - ArrayList sdeleniList = new ArrayList<>(); + ArrayList reportList = new ArrayList<>(); public void download() throws UnknownHostException, IOException { - Document sdeleniDoc = Downloader.download("https://www.spsejecna.cz/user-student/record-list").get(); + Document reportDoc = Downloader.download("https://www.spsejecna.cz/user-student/record-list"); - Elements sdeleni = sdeleniDoc.select("ul.list li"); + Elements report = reportDoc.select("ul.list li"); - for(Element e : sdeleni) + for(Element e : report) { boolean isPositive = false; String label = ""; @@ -29,15 +29,15 @@ public class Sdeleni extends JecnaScrape { Elements spans = e.select("li").select("a.item").select("span"); isPositive = spans.get(0).hasClass("sprite-icon-tick-16"); - label = spans.get(1).text(); + label = spans.get(1).select("span.label").text(); - sdeleniList.add(new xyz.thastertyn.Types.Sdeleni(label, isPositive)); + reportList.add(new xyz.thastertyn.Types.Reports(label, isPositive)); } } - public ArrayList getSdeleni() + public ArrayList getSdeleni() { - return sdeleniList; + return reportList; } @Override diff --git a/src/main/java/xyz/thastertyn/Scrape/Rozvrh.java b/src/main/java/xyz/thastertyn/Scrape/Timetable.java similarity index 63% rename from src/main/java/xyz/thastertyn/Scrape/Rozvrh.java rename to src/main/java/xyz/thastertyn/Scrape/Timetable.java index 9478de8..24b631d 100644 --- a/src/main/java/xyz/thastertyn/Scrape/Rozvrh.java +++ b/src/main/java/xyz/thastertyn/Scrape/Timetable.java @@ -1,7 +1,6 @@ package xyz.thastertyn.Scrape; import java.io.IOException; -import java.net.UnknownHostException; import java.util.Arrays; import java.util.HashSet; import java.util.regex.Pattern; @@ -13,25 +12,14 @@ import org.jsoup.select.Elements; import xyz.thastertyn.Types.Choice; import xyz.thastertyn.Types.Option; import xyz.thastertyn.Types.Options; -import xyz.thastertyn.Types.Timetable; -/** - * Jeden radek v rozvrhu - */ -public class Rozvrh extends JecnaScrape { +public class Timetable extends JecnaScrape { - private Timetable timetable; + private xyz.thastertyn.Types.Timetable timetable; private Options schoolYearOptions; private Options timetableOptions; - /** - * Stahne rozvrh z www.spsejecna.cz a dale ho zpracuje do formy - * se kterou da pracovat - * @param Jsessionid ze stranek - * @throws UnknownHostException kdyz neni pripojeni k internetu - * @throws IOException ostatni exceptiony nejsou dulezite, tak jsou zahrnuty v jednom - */ @Override public void download() throws IOException { @@ -51,32 +39,32 @@ public class Rozvrh extends JecnaScrape { schoolYearOptions = new Options("Skolni R."); timetableOptions = new Options("Obdobi"); - timetable = new Timetable(); - Document rozvrhDokumentHTML = Downloader.download(url).get(); + timetable = new xyz.thastertyn.Types.Timetable(); + Document timetableHTMLDocument = Downloader.download(url); - Elements[] radkyRozvrhuHTML = rozvrhDokumentHTML + Elements[] timetableHTMLRow = timetableHTMLDocument .select("table.timetable") .select("tr") .stream() .map(Element::children) .toArray(Elements[]::new); - for(int i = 0; i < 5; i++) + for(int i = 0; i < 5; i++) // Days { - for(int j = 0; j < 10; j++) + for(int j = 0; j < 10; j++) // Individual hours { - String predmet = radkyRozvrhuHTML[i+1].get(j+1).select("span.subject").text(); + String subject = timetableHTMLRow[i+1].get(j+1).select("span.subject").text(); // Subjects like CEL are thrice, even though everyone has them, make it single - String[] split = predmet.split(" "); + String[] split = subject.split(" "); HashSet set = new HashSet<>(Arrays.asList(split)); - String pr = String.join("/", set); + String subj = String.join("/", set); - timetable.get(i).set(j, pr); + timetable.get(i).set(j, subj); } } - Element optionsPanel = rozvrhDokumentHTML.selectFirst("form.listConfigure"); + Element optionsPanel = timetableHTMLDocument.selectFirst("form.listConfigure"); Elements schoolYear = optionsPanel.select("select[id=schoolYearId]").select("option"); Elements timetableId = optionsPanel.select("select[id=timetableId]").select("option"); @@ -89,20 +77,21 @@ public class Rozvrh extends JecnaScrape { for(Element e : timetableId) { - String text = Pattern + // Try to extract the precise school years to make the text shorter + String optionDisplayText = Pattern .compile("(Od .* do .*)") .matcher(e.text()) .results() .findFirst() .map(m -> m.group(1)) - .orElse(e.text()); + .orElse(e.text()); // Just use the whole thing if it doesn't follow the pattern - boolean isDefault = e.hasAttr("selected"); - timetableOptions.addOption(new Option(text, e.attr("value"), isDefault)); + boolean isDefault = e.hasAttr("selected"); // To prevent the last option added be picked as default always + timetableOptions.addOption(new Option(optionDisplayText, e.attr("value"), isDefault)); } } - public Timetable getRozvrh() + public xyz.thastertyn.Types.Timetable getRozvrh() { return timetable; } diff --git a/src/main/java/xyz/thastertyn/Scrape/Znamky.java b/src/main/java/xyz/thastertyn/Scrape/Znamky.java deleted file mode 100644 index bf153b0..0000000 --- a/src/main/java/xyz/thastertyn/Scrape/Znamky.java +++ /dev/null @@ -1,130 +0,0 @@ -package xyz.thastertyn.Scrape; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.regex.Pattern; - -import org.jsoup.nodes.Document; -import org.jsoup.nodes.Element; -import org.jsoup.select.Elements; - -import xyz.thastertyn.Types.Choice; -import xyz.thastertyn.Types.FinalMark; -import xyz.thastertyn.Types.Option; -import xyz.thastertyn.Types.Options; -import xyz.thastertyn.Types.Predmet; -import xyz.thastertyn.Types.Znamka; - -public class Znamky extends JecnaScrape { - - // schoolYear, schoolYearId - private ArrayList predmety; - - // int znaci id roku, boolean jestli je jen prvni nebo i druhe pololeti - private Options schoolYearOptions; - private Options schoolHalfYearOptions; - - public void download() throws IOException - { - download("https://www.spsejecna.cz/score/student"); - } - - @Override - public void download(Choice choice) throws IOException - { - download(String.format( - "https://www.spsejecna.cz/score/student?schoolYearId=%s&schoolYearHalfId=%s", - choice.getChoices().get(0), - choice.getChoices().get(1))); - } - - private void download(String url) throws IOException - { - schoolHalfYearOptions = new Options("Pololeti"); - schoolYearOptions = new Options("Skolni R."); - - predmety = new ArrayList<>(); - Document znamkyDokumentHTML = Downloader.download(url).get(); - - // Predmety ulozene v - Elements[] radkyPredmetuHTML = znamkyDokumentHTML - .select("table.score") - .select("tr") - .stream() - .map(Element::children) - .toArray(Elements[]::new); - - int subjectIndex = 0; - - for(int i = 1; i < radkyPredmetuHTML.length; i++) - { - String plnyNazevPredmetu = radkyPredmetuHTML[i].get(0).text(); - - String jmenoPredmetu = Pattern - .compile("\\((.*?)\\)") - .matcher(plnyNazevPredmetu) - .results() - .findFirst() - .map(m -> m.group(1)) - .orElse(plnyNazevPredmetu); - - if(radkyPredmetuHTML[i].get(2).childrenSize() == 0) // Predmet jeste nema vyslednou znamku - { - predmety.add(new Predmet(jmenoPredmetu)); - }else{ - String vyslednaZnamka = radkyPredmetuHTML[i].get(2).select("a.scoreFinal").text(); - predmety.add(new Predmet(jmenoPredmetu, FinalMark.fromValue(vyslednaZnamka))); - } - - for(Element znamkaElement : radkyPredmetuHTML[i].get(1).select("a.score")) - { - int znamka; - boolean jeMala = false; - - String textZnamky = znamkaElement.select("span.value").text(); - - znamka = textZnamky.matches("\\d") ? - Integer.parseInt(textZnamky) - : - -1; // Nejspis se jedna o N (Nehodnocen) - - // Mala znamka se bude pocitat jako polovicni vaha - jeMala = znamkaElement.hasClass("scoreSmall"); - - predmety.get(subjectIndex).addZnamka(new Znamka(znamka, jeMala, textZnamky)); - } - - predmety.get(subjectIndex).calculateFinalMark(); - - subjectIndex++; - } - - Element optionsPanel = znamkyDokumentHTML.selectFirst("form.listConfigure"); - - Elements skolniRoky = optionsPanel.select("select[id=schoolYearId]").select("option"); - Elements pololeti = optionsPanel.select("select[id=schoolYearHalfId]").select("option"); - - - for(Element e : skolniRoky) - { - boolean isDefault = e.hasAttr("selected"); - schoolYearOptions.addOption(new Option(e.text(), e.attr("value"), isDefault)); - } - - for(Element e : pololeti) - { - boolean isDefault = e.hasAttr("selected"); - schoolHalfYearOptions.addOption(new Option(e.text(), e.attr("value"), isDefault)); - } - } - - public ArrayList getPredmety() - { - return predmety; - } - - public Options[] getOptions() - { - return new Options[] {schoolYearOptions, schoolHalfYearOptions}; - } -} \ No newline at end of file diff --git a/src/main/java/xyz/thastertyn/Tuples/Pair.java b/src/main/java/xyz/thastertyn/Tuples/Pair.java deleted file mode 100644 index e836568..0000000 --- a/src/main/java/xyz/thastertyn/Tuples/Pair.java +++ /dev/null @@ -1,54 +0,0 @@ -package xyz.thastertyn.Tuples; - -/** - * Ekvitalent Tuplu, ktery neni zabudovan v jave - */ -public class Pair { - - - private T1 value0; - private T2 value1; - - public Pair(T1 value0, T2 value1) - { - this.value0 = value0; - this.value1 = value1; - } - - public Pair() - { - - } - - public void put(T1 value0, T2 value1) - { - this.value0 = value0; - this.value1 = value1; - } - - public T1 getValue0() - { - return value0; - } - - public T2 getValue1() - { - return value1; - } - - public void setValue0(T1 value0) - { - this.value0 = value0; - } - - public void setValue1(T2 value1) - { - this.value1 = value1; - } - - @Override - public String toString() - { - return "[" + value0 + ", " + value1 + "]"; - } -} diff --git a/src/main/java/xyz/thastertyn/Tuples/Triplet.java b/src/main/java/xyz/thastertyn/Tuples/Triplet.java deleted file mode 100644 index 7814728..0000000 --- a/src/main/java/xyz/thastertyn/Tuples/Triplet.java +++ /dev/null @@ -1,66 +0,0 @@ -package xyz.thastertyn.Tuples; - -/** - * Ekvitalent Tuplu, ktery neni zabudovan v jave - */ -public class Triplet { - - private T1 value0; - private T2 value1; - private T3 value2; - - public Triplet(T1 value0, T2 value1, T3 value2) - { - this.value0 = value0; - this.value1 = value1; - this.value2 = value2; - } - - public Triplet() - { - - } - - public void put(T1 value0, T2 value1, T3 value2) - { - this.value0 = value0; - this.value1 = value1; - this.value2 = value2; - } - - public T1 getValue0() - { - return value0; - } - - public T2 getValue1() - { - return value1; - } - - public T3 getValue2() - { - return value2; - } - - public void setValue0(T1 value0) - { - this.value0 = value0; - } - - public void setValue1(T2 value1) - { - this.value1 = value1; - } - - public void setValue2(T3 value2) - { - this.value2 = value2; - } - - @Override - public String toString() - { - return "[" + value0 + ", " + value1 + "," + value2 + "]"; - } -} diff --git a/src/main/java/xyz/thastertyn/Types/AbsenceList.java b/src/main/java/xyz/thastertyn/Types/AbsenceList.java new file mode 100644 index 0000000..2b28459 --- /dev/null +++ b/src/main/java/xyz/thastertyn/Types/AbsenceList.java @@ -0,0 +1,31 @@ +package xyz.thastertyn.Types; + +public class AbsenceList { + + private String date; + private String description; + + public AbsenceList(String date, String description) + { + this.date = date; + this.description = description; + } + + public String getDate() { + return date; + } + + public void setDate(String datum) { + this.date = datum; + } + + public String getDescription() { + return description; + } + + public void setDescription(String popis) { + this.description = popis; + } + + +} diff --git a/src/main/java/xyz/thastertyn/Types/Choice.java b/src/main/java/xyz/thastertyn/Types/Choice.java index 8135705..5bf742a 100644 --- a/src/main/java/xyz/thastertyn/Types/Choice.java +++ b/src/main/java/xyz/thastertyn/Types/Choice.java @@ -2,6 +2,9 @@ package xyz.thastertyn.Types; import java.util.List; +/** + * A choice parsed from dropdowns on the site. Usually contains something like school year or half year id + */ public class Choice { private List choices; diff --git a/src/main/java/xyz/thastertyn/Types/Credentials.java b/src/main/java/xyz/thastertyn/Types/Credentials.java new file mode 100644 index 0000000..797ceae --- /dev/null +++ b/src/main/java/xyz/thastertyn/Types/Credentials.java @@ -0,0 +1,23 @@ +package xyz.thastertyn.Types; + +/** + * Stores username and password + */ +public class Credentials { + + private String username; + private String password; + + public Credentials(String username, String password) { + this.username = username; + this.password = password; + } + + public String getUsername() { + return username; + } + + public String getPassword() { + return password; + } +} diff --git a/src/main/java/xyz/thastertyn/Types/DayOfTimetable.java b/src/main/java/xyz/thastertyn/Types/DayOfTimetable.java index 60ac174..35391e9 100644 --- a/src/main/java/xyz/thastertyn/Types/DayOfTimetable.java +++ b/src/main/java/xyz/thastertyn/Types/DayOfTimetable.java @@ -1,5 +1,8 @@ package xyz.thastertyn.Types; +/** + * Stores a single day from the timetable as an array of strings + */ public class DayOfTimetable { private String[] subjects = new String[10]; diff --git a/src/main/java/xyz/thastertyn/Types/FinalMark.java b/src/main/java/xyz/thastertyn/Types/FinalMark.java index 2c0d2a2..2e4cbb0 100644 --- a/src/main/java/xyz/thastertyn/Types/FinalMark.java +++ b/src/main/java/xyz/thastertyn/Types/FinalMark.java @@ -1,5 +1,8 @@ package xyz.thastertyn.Types; +/** + * Stores the final mark from a subject + */ public class FinalMark{ public static final FinalMark VYBORNY = new FinalMark(1, "1"); public static final FinalMark CHVALITEBNY = new FinalMark(2, "2"); @@ -7,6 +10,8 @@ public class FinalMark{ public static final FinalMark DOSTATECNY = new FinalMark(4, "4"); public static final FinalMark NEDOSTATECNY = new FinalMark(5, "5"); + public static final FinalMark NOTHING = new FinalMark(0, ""); + public static final FinalMark NEHODNOCEN = new FinalMark(-1, "N"); public static final FinalMark NAPOMENUT_ZA_NEKLASIFIKACI = new FinalMark(-2, "N?"); diff --git a/src/main/java/xyz/thastertyn/Types/InputtedCredentials.java b/src/main/java/xyz/thastertyn/Types/InputtedCredentials.java new file mode 100644 index 0000000..1982ceb --- /dev/null +++ b/src/main/java/xyz/thastertyn/Types/InputtedCredentials.java @@ -0,0 +1,30 @@ +package xyz.thastertyn.Types; + +/** + * Wrapper around credentials with the change of having a boolean for whether the user wants to save the credentials or not + */ +public class InputtedCredentials extends Credentials { + + private boolean save; + + public InputtedCredentials(String username, String password, boolean save) + { + super(username, password); + this.save = save; + } + + public InputtedCredentials(Credentials credentials, boolean save) + { + super(credentials.getUsername(), credentials.getPassword()); + this.save = save; + } + + public Credentials getCredentials() + { + return new Credentials(getUsername(), getPassword()); + } + + public boolean save() { + return save; + } +} diff --git a/src/main/java/xyz/thastertyn/Types/Mark.java b/src/main/java/xyz/thastertyn/Types/Mark.java new file mode 100644 index 0000000..b92c5ac --- /dev/null +++ b/src/main/java/xyz/thastertyn/Types/Mark.java @@ -0,0 +1,34 @@ +package xyz.thastertyn.Types; + +/** + * A single mark. holds numeric value, weight - small = 1, normal 2 + */ +public class Mark { + + private int mark; + private String markAsText; + private int weight; + + public Mark(int mark, boolean isSmall, String markAsText) + { + this.mark = mark; + this.weight = (isSmall) ? 1 : 2; + this.markAsText = markAsText; + } + + public int getMark() + { + return mark; + } + + public int getWeight() + { + return weight; + } + + @Override + public String toString() + { + return markAsText; + } +} \ No newline at end of file diff --git a/src/main/java/xyz/thastertyn/Types/OmluvnyList.java b/src/main/java/xyz/thastertyn/Types/OmluvnyList.java deleted file mode 100644 index 5b17ea7..0000000 --- a/src/main/java/xyz/thastertyn/Types/OmluvnyList.java +++ /dev/null @@ -1,33 +0,0 @@ -package xyz.thastertyn.Types; - -import java.time.LocalDate; - -public class OmluvnyList { - - private LocalDate datum; - private String popis; - - public OmluvnyList(LocalDate datum, String popis) - { - this.datum = datum; - this.popis = popis; - } - - public LocalDate getDatum() { - return datum; - } - - public void setDatum(LocalDate datum) { - this.datum = datum; - } - - public String getPopis() { - return popis; - } - - public void setPopis(String popis) { - this.popis = popis; - } - - -} diff --git a/src/main/java/xyz/thastertyn/Types/Option.java b/src/main/java/xyz/thastertyn/Types/Option.java index 90360b6..0c3800b 100644 --- a/src/main/java/xyz/thastertyn/Types/Option.java +++ b/src/main/java/xyz/thastertyn/Types/Option.java @@ -1,12 +1,16 @@ package xyz.thastertyn.Types; +/** + * A single option. Holds a text description, the thing displayed and a string value, the one used in url + */ public class Option { - private String text; + private String displayText; private String value; private boolean isDefault; + public Option(String text, String value, boolean isDefault) { - this.text = text; + this.displayText = text; this.value = value; this.isDefault = isDefault; } @@ -18,6 +22,6 @@ public class Option { } @Override public String toString() { - return text; + return displayText; } } diff --git a/src/main/java/xyz/thastertyn/Types/Options.java b/src/main/java/xyz/thastertyn/Types/Options.java index daaa765..cdc355b 100644 --- a/src/main/java/xyz/thastertyn/Types/Options.java +++ b/src/main/java/xyz/thastertyn/Types/Options.java @@ -2,6 +2,9 @@ package xyz.thastertyn.Types; import java.util.ArrayList; +/** + * Holds all possible a single dropdown on the website can have. + */ public class Options { private ArrayList