app.sunstreak.yourpisd.net.Parser.java Source code

Java tutorial

Introduction

Here is the source code for app.sunstreak.yourpisd.net.Parser.java

Source

/**
 * This file is part of yourPISD.
 *
 *  yourPISD is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  yourPISD is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with yourPISD.  If not, see <http://www.gnu.org/licenses/>.
 */

package app.sunstreak.yourpisd.net;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

public class Parser {

    public static final String LOGIN_FAILURE_TITLE = "myPISD - Login";
    public static final String GRADEBOOK_BAD_USERNAME = "NotSet";

    // Cannot be instantiated.
    private Parser() {
    }

    /**
     * returns value of pageUniqueId from html
     * String must contain the following block:
     * <input type="hidden" name="PageUniqueId" id="PageUniqueId" value="8bdc977f-ccaf-4a18-b4dd-20d1406fad6a" />
     */
    public static String pageUniqueId(String html) {
        return pageUniqueId(Jsoup.parse(html));
    }

    /**
     * returns value of pageUniqueId from html
     * String must contain the following block:
     * <input type="hidden" name="PageUniqueId" id="PageUniqueId" value="8bdc977f-ccaf-4a18-b4dd-20d1406fad6a" />
     */
    public static String pageUniqueId(Element doc) {
        Elements inputElements = doc.getElementsByTag("input");

        for (Element e : inputElements)
            if (e.attr("name").equals("PageUniqueId"))
                return e.attr("value");

        return null;
    }

    /*
     * must take in html for [Domain].loginAddress
     */
    public static boolean accessGrantedEditure(String html) {
        Element doc = Jsoup.parse(html);
        String title = doc.getElementsByTag("title").text();
        return !title.equals(LOGIN_FAILURE_TITLE) ? true : false;
    }

    /*
     * must take in html for "https://parentviewer.pisd.edu/EP/PIV_Passthrough.aspx?action=trans&uT=" + userType + "&uID=" + uID
     */
    public static boolean accessGrantedGradebook(String[] gradebookCredentials) {
        System.out.println(Arrays.deepToString(gradebookCredentials));
        return !(gradebookCredentials[0].equals(GRADEBOOK_BAD_USERNAME));
    }

    public static String[] getGradebookCredentials(String html) {
        Element doc = Jsoup.parse(html);
        Elements userIdElements = doc.getElementsByAttributeValue("name", "userId");
        Elements passwords = doc.getElementsByAttributeValue("name", "password");
        String userId = userIdElements.attr("value");
        String password = passwords.attr("value");
        return new String[] { userId, password };
    }

    /**
     * must take html from [Domain].portalAddress or [Domain].portalAddress/myclasses
     */
    public static String[] passthroughCredentials(String html) {
        Element doc = Jsoup.parse(html);
        String uT = doc.getElementsByAttributeValue("name", "uT").attr("value");
        String uID = doc.getElementsByAttributeValue("name", "uID").attr("value");
        return new String[] { uT, uID };
    }

    public static int studentIdPinnacle(ArrayList<String> cookies) {
        //      System.out.println("Cookies size = " + cookies.size());
        for (String c : cookies)
            if (c.substring(0, c.indexOf('=')).equals("PinnacleWeb.StudentId"))
                return Integer.parseInt(c.substring(c.indexOf('=') + 1));
        throw new RuntimeException("Student ID not found. Cookies: " + cookies.toString());
    }

    public static JSONArray detailedReport(String html) throws JSONException {
        Element doc = Jsoup.parse(html);
        //      System.out.println(html);
        Element assignments = doc.getElementsByAttributeValue("id", "Assignments").get(0);
        Elements tableRows = assignments.getElementsByTag("tbody").get(0).getElementsByTag("tr");

        JSONArray grades = new JSONArray();

        for (Element tr : tableRows) {
            JSONObject assignment = new JSONObject();

            Elements columns = tr.getElementsByTag("td");

            for (int i = 0; i < columns.size(); i++) {
                String value = columns.get(i).text();
                // do not store empty values!
                if (value.equals(""))
                    continue;
                // first try to cast as int.
                try {
                    assignment.putOpt(assignmentTableHeader(i), Integer.parseInt(value));
                    // if not int, try double
                } catch (NumberFormatException e) {
                    try {
                        assignment.putOpt(assignmentTableHeader(i), Double.parseDouble(value));
                        // if not double, use string
                    } catch (NumberFormatException f) {
                        assignment.putOpt(assignmentTableHeader(i), value);
                    }
                }
            }

            String assignmentDetailLink = tr.getElementsByTag("a").get(0).attr("href");
            Matcher matcher = Pattern.compile(".+" + "assignmentId=(\\d+)" + "&H=S" + "&GradebookId=(\\d+)"
                    + "&TermId=\\d+" + "&StudentId=\\d+&").matcher(assignmentDetailLink);
            matcher.find();
            int assignmentId = Integer.parseInt(matcher.group(1));
            int gradebookId = Integer.parseInt(matcher.group(2));
            assignment.put("assignmentId", assignmentId);
            assignment.put("gradebookId", gradebookId);
            grades.put(assignment);
        }
        //      System.out.println((grades));
        return grades;
    }

    /**
     * Reads assignment view page and returns teacher name.
     * 
     * Parses from this table:
     * 
     * <table id='classStandardInfo'> <tbody> <tr>  
     * <td>       <div class='classInfoHeader'>Kapur, Sidharth (226344)</div>2013-08-29   <td>    
     * <table>    
     *       <tr>      <th style='width:1%'>Course:</th>      <td><a href='javascript:ClassDetails.getClassDetails(2976981);' id='ClassTitle'>CHEM  AP(00)</a></td></tr>    
     *       <tr>      <th>Term:</th>      <td>1st Six Weeks</td>     </tr>
     *       <tr>      <th>Teacher:</th>      <td><a href="mailto:Nicole.Lyssy@pisd.edu" title="Nicole.Lyssy@pisd.edu">Lyssy, Carol</a></td>     </tr>
     * </table>
     * <td>  </tr> </tbody></table>
     */
    public static String[] teacher(String html) {
        Element doc = Jsoup.parse(html);
        Element classStandardInfo = doc.getElementById("classStandardInfo");
        // teacher is the third row in this table
        Element teacher = classStandardInfo.getElementsByTag("table").get(0).getElementsByTag("tr").get(3)
                .getElementsByTag("td").get(0);
        //      System.out.println(teacher);
        String email = "";
        try {
            email = teacher.getElementsByTag("a").get(0).attr("title");
        } catch (IndexOutOfBoundsException e) {
            // Senior release teacher have NO email. The <a> tag does not exist.
        }
        String teacherName = teacher.text();
        return new String[] { teacherName, email };
    }

    public static Object[] termCategoryGrades(String html) throws JSONException {
        JSONArray termCategoryGrades = new JSONArray();

        Element doc = Jsoup.parse(html);
        Element categoryTable = doc.getElementById("Category");
        Elements rows = categoryTable.getElementsByTag("tbody").get(0).getElementsByTag("tr");

        for (Element row : rows) {
            JSONObject category = new JSONObject();
            Elements columns = row.getElementsByTag("td");
            for (int i = 0; i < columns.size(); i++) {

                String value = columns.get(i).text();
                // do not store empty values!
                if (value.equals(""))
                    continue;
                // first try to cast as int.
                try {
                    category.putOpt(categoryTableHeader(i), Integer.parseInt(value));
                    // if not int, try double
                } catch (NumberFormatException e) {
                    try {
                        category.putOpt(categoryTableHeader(i), Double.parseDouble(value));
                        // if not double, use string
                    } catch (NumberFormatException f) {
                        category.putOpt(categoryTableHeader(i), value);
                    }
                }
            }
            termCategoryGrades.put(category);

        }

        // The average for the six weeks is 
        int average = -1;
        try {
            Element finalGrade = doc.getElementById("finalGrade");
            average = Integer.parseInt(finalGrade.getElementsByTag("td").get(3).text());
        } catch (NullPointerException e) {
            // Let average be -1
        }

        return new Object[] { termCategoryGrades, average };
    }

    /*
     * We should probably replace this with an Enum
     */
    public static String assignmentTableHeader(int column) {
        // starts at one (because Number is a th, not a td)
        switch (column + 1) {
        // if we return null, the machine won't put it
        case 0:
            return null;
        //return "Number";
        case 1:
            return "Description";
        case 2:
            return "Due Date";
        case 3:
            return "Category";
        case 4:
            return "Grade";
        case 5:
            return "Max";
        case 6:
            return "Letter";
        case 7:
            return "Comments";
        default:
            return null;
        }
    }

    public static String categoryTableHeader(int column) {
        switch (column) {
        case 0:
            return "Category";
        case 1:
            return "Weight";
        case 2:
            return "Points / Max pts.";
        case 3:
            return "Percent";
        case 4:
            return "Letter";
        default:
            return null;
        }
    }

    /** Parses average of each term from GradeSummary.aspx.
     * NOTICE: Does not work for second semester classes in which the second semester schedule
     *  is different from the first semester schedule.
     * 
     * @param html source of GradeSummary.aspx
     * @param classList classList as returned by Init.aspx
     * @throws org.json.JSONException
     * @return     [
     *       [classId, avg0, avg1, ...],
     *       [classId, avg0, avg1, ...],
     * ]
     */
    public static int[][] gradeSummary(String html, JSONArray classList) {
        Element doc = Jsoup.parse(html);
        return gradeSummary(doc, classList);
    }

    /** Parses average of each term from GradeSummary.aspx.
     * NOTICE: Does not work for second semester classes in which the second semester schedule
     *  is different from the first semester schedule.
     * 
     * @param doc the Jsoup element of GradeSummary.aspx
     * @param classList classList as returned by Init.aspx
     * @throws org.json.JSONException
     * @return     [
     *       [classId, avg0, avg1, ...],
     *       [classId, avg0, avg1, ...],
     * ]
     */
    public static int[][] gradeSummary(Element doc, JSONArray classList) {

        List<int[]> gradeSummary = new ArrayList<int[]>();

        Element reportTable = doc.getElementsByClass("reportTable").get(0).getElementsByTag("tbody").get(0);
        Elements rows = reportTable.getElementsByTag("tr");
        int rowIndex = 0;

        while (rowIndex < rows.size()) {

            int[] classAverages = new int[11];
            Arrays.fill(classAverages, -3);

            Element row = rows.get(rowIndex);
            Elements columns = row.getElementsByTag("td");

            classAverages[0] = getClassId(row);

            for (int col = 0; col < 10; col++) {
                Element column = columns.get(col);
                String text = column.text();

                // -2 for disabled class
                if (column.attr("class").equals("disabledCell"))
                    text = "-2";
                classAverages[col + 1] = text.equals("") ? -1 : Integer.parseInt(text);
            }
            gradeSummary.add(classAverages);
            rowIndex++;
        }

        /*
         * [
         *       [classId, avg0, avg1, ...],
         *       [classId, avg0, avg1, ...],
         * ]
         */
        int[][] result = new int[gradeSummary.size()][];
        for (int i = 0; i < result.length; i++) {
            result[i] = new int[gradeSummary.get(i).length];
            for (int j = 0; j < result[i].length; j++)
                result[i][j] = gradeSummary.get(i)[j];
        }
        return result;
    }

    /**
     * 
     * @return
     */
    public static int getClassId(Element row) {
        Elements th = row.getElementsByTag("th");
        String href = th.get(0).getElementsByTag("a").get(0).attr("href");
        // href="javascript:ClassDetails.getClassDetails(2976981);"
        return Integer.parseInt(href.substring(40, 47));
    }

    /**
     * @param html Source code of any Gradebook page.
     * @return the full name (Last, First) of the student and ID number.
     */
    public static String studentName(String html) {
        return studentName(Jsoup.parse(html));
    }

    /**
     * @param doc The Jsoup element from any Gradebook page.
     * @return the full name (Last, First) of the student and ID number.
     */
    public static String studentName(Element doc) {
        Element studentName = doc.getElementById("ctl00_ctl00_ContentPlaceHolder_uxMultiple");
        return studentName.text();
    }

    /**
     * 
     * @param html html source code of https://sso.portal.mypisd.net/cas/login?service=http%3A%2F%2Fportal.mypisd.net%2Fc%2Fportal%2Flogin
     * @return the value embedded in the <input type="hidden" name="lt" value=""> block
     */
    public static String portalLt(String html) {
        Element doc = Jsoup.parse(html);
        Elements inputTags = doc.getElementsByTag("input");
        //Shortcut
        //      if (inputTags.get(4).attr("name").equals("lt"))
        //         return inputTags.get(4).attr("value");
        //      else {
        for (Element tag : inputTags) {
            if (tag.attr("name").equals("lt"))
                return tag.attr("value");
        }
        //      }
        return null;
    }

    /**
     * 
     * @param html the source code for ANY page in Gradebook (usually Default.aspx)
     * @return
     */
    public static List<String[]> parseStudents(String html) {
        List<String[]> list = new ArrayList<String[]>();

        Element doc = Jsoup.parse(html);
        Element studentList = doc.getElementById("ctl00_ctl00_ContentPlaceHolder_uxStudentlist");

        // Only one student
        if (studentList.text().isEmpty()) {
            // {studentId, studentName}
            list.add(new String[] { doc.getElementById("ctl00_ctl00_ContentPlaceHolder_uxStudentId").attr("value"),
                    doc.getElementById("ctl00_ctl00_ContentPlaceHolder_uxMultiple").text() });
            return list;
        }
        // Multiple students
        else {
            for (Element a : studentList.getElementsByTag("a")) {
                String name = a.text();
                String onClick = a.attr("onClick");
                String studentId = onClick.substring(onClick.indexOf('\'') + 1, onClick.lastIndexOf('\''));
                list.add(new String[] { studentId, name });
            }
            return list;
        }
    }

    public static String[] parseAssignment(String html) throws JSONException {
        //Debug code
        /*
        Element doc = Jsoup.parse(html);
        System.out.println(doc);
        Element assignment = doc.getElementById("Assignment");
        System.out.println(assignment);
        Elements tds = assignment.getElementsByTag("td");
        System.out.println(tds);
         */
        Elements tds = Jsoup.parse(html).getElementById("Assignment").getElementsByTag("td");
        //      JSONObject ass = new JSONObject();
        //      ass.put("assignedDate", tds.get(3).text());
        //      ass.put("dueDate", tds.get(5).text());
        //      ass.put("weight", tds.get(9).text());
        //   {assignedDate, dueDate, weight}
        return new String[] { tds.get(3).text(), tds.get(5).text(), tds.get(9).text() };
    }

    public static String toTitleCase(String str) {
        StringBuilder sb = new StringBuilder(str.length());
        boolean capitalize = false;
        for (int charNum = 0; charNum < str.length(); charNum++) {

            capitalize = (charNum == 0 || !Character.isLetter(str.charAt(charNum - 1))
                    || (str.substring(charNum - 1, charNum + 1).equals("AP")
                            || str.substring(charNum - 1, charNum + 1).equals("IB")
                            || str.substring(charNum - 1, charNum + 1).equals("IH"))
                            && (charNum + 2 >= str.length() || !Character.isLetter(str.charAt(charNum + 1))));

            if (capitalize)
                sb.append(Character.toUpperCase(str.charAt(charNum)));
            else
                sb.append(Character.toLowerCase(str.charAt(charNum)));
        }
        return sb.toString();
    }

}