Rambou/icarus-sef-parser

View on GitHub
lib/index.js

Summary

Maintainability
F
1 wk
Test Coverage
// import dependencies
var request = require('request'),
    charsetParser = require('charset-parser'),
    iconv = require('iconv-lite'),
    jsdom = require("jsdom");

const {JSDOM} = jsdom;

// skip iconv warnings
// TODO: Fix this issue with the buffer
iconv.skipDecodeWarning = true;

var DEPART = {
    MPES: {
        url: 'https://icarus-icsd.aegean.gr',
        main_url: 'student_main.php',
        request_url: 'student_aitisi.php',
        name: "Μηχανικών Πληροφοριακών και Επικοινωνιακών συστημάτων"
    },
    MATH: {url: 'https://sef.samos.aegean.gr/', main_url: 'main.php', request_url: 'request.php', name: "Μαθηματικό"},
    SAXM: {url: 'https://sef.samos.aegean.gr/', main_url: 'main.php', request_url: 'request.php', name: "Στατιστική"}
};
var self;

// Constructor
function Parser(username, password) {
    // always initialize all instance properties
    this.username = username;
    this.password = password;
    this.cookie = null;

    // check department and website
    if (username.indexOf('icsd') > -1) {
        this.department = DEPART.MPES;
    } else if (username.indexOf('math') > -1) {
        this.department = DEPART.MATH;
    } else if (username.indexOf('sas') > -1) {
        this.department = DEPART.SAXM;
    } else {
        throw new Error("Not a valid user!");
    }

    // initiate self for access inside callbacks
    self = this;
}

// class methods
Parser.prototype.printStudent = function () {
    console.log("Όνομα χρήστη: " + this.username + ", Τμήμα: " + this.department.name + ", URL συστήματος: " + this.department.url)
};

Parser.prototype.getDepartmentName = function () {
    return this.department.name;
};

Parser.prototype.getAnalyticGrades = function (document, callback) {
    var courses = [];

    try {
        if (this.department === DEPART.MPES) {
            document.window.document.querySelectorAll('#analytic_grades tbody tr').forEach(function (tr) {
                var td = tr.querySelectorAll('td');
                var ID = td[1].innerHTML;
                var Title = td[2].innerHTML;
                var Mark = td[3].innerHTML;
                var Cemester = td[4].innerHTML;
                var ApplyDate = td[5].innerHTML;
                var ExamDate = td[6].innerHTML;
                var Status = td[7].innerHTML;

                //console.log("ID: " + ID + ", Title:" + Title + ", Cemester:" + Cemester + ", Mark: " + Mark + ", ApplyDate:" + ApplyDate + ", ExamDate:" + ExamDate + ", Status: " + Status)
                courses.push({
                    id: ID,
                    title: Title,
                    cemester: Cemester,
                    applyDate: ApplyDate,
                    examDate: ExamDate,
                    mark: Mark,
                    status: Status
                });
            });
        } else {
            document.window.document.querySelectorAll('#tab_1 tbody tr').forEach(function (tr) {
                var td = tr.querySelectorAll('td');
                var ID = td[0].innerHTML;
                var Title = td[1].innerHTML;
                var ApplyDate = td[2].querySelector('span').innerHTML;
                var ExamDate = td[3].querySelector('span').innerHTML;
                var Mark = td[4].innerHTML;
                var Status = td[5].innerHTML;

                //console.log("ID: " + ID + ", Title:" + Title + ", ApplyDate:" + ApplyDate + ((ExamDate.trim()) ? ", ExamDate: " + ExamDate : "") + ((Mark) ? ", Mark:" + Mark : "") + ", Status:" + Status)
                courses.push({
                    id: ID,
                    title: Title,
                    applyDate: ApplyDate,
                    examDate: ExamDate,
                    mark: Mark,
                    status: Status
                });
            });
        }

        return callback(null, courses)
    } catch (err) {
        return callback(err, null)
    }
}

Parser.prototype.getSucceededGrades = function (document, callback) {
    var courses = [];

    try {
        if (this.department === DEPART.MPES) {
            document.window.document.querySelectorAll('#succeeded_grades tbody tr').forEach(function (tr) {
                var td = tr.querySelectorAll('td');
                var ID = td[1].innerHTML;
                var Title = td[2].innerHTML;
                var Mark = td[3].innerHTML;
                var Cemester = td[4].innerHTML;
                var ApplyDate = td[5].innerHTML;
                var ExamDate = td[6].innerHTML;
                var Status = td[7].innerHTML;

                //console.log("ID: " + ID + ", Title:" + Title + ", Cemester:" + Cemester + ", Mark: " + Mark + ", ApplyDate:" + ApplyDate + ", ExamDate:" + ExamDate + ", Status: " + Status)
                courses.push({
                    id: ID,
                    title: Title,
                    cemester: Cemester,
                    applyDate: ApplyDate,
                    examDate: ExamDate,
                    mark: Mark,
                    status: Status
                });
            });
        } else {
            document.window.document.querySelectorAll('#example3 tbody tr').forEach(function (tr) {
                var td = tr.querySelectorAll('td');
                var ID = td[0].innerHTML;
                var Title = td[1].innerHTML;
                var ECTS = td[3].innerHTML;
                var Certificate = td[5].innerHTML;
                var ApplyDate = td[6].innerHTML;
                var ExamDate = td[7].innerHTML;
                var Mark = td[8].innerHTML;
                var Status = td[9].innerHTML;

                /*console.log("ID: " + ID + ", Title:" + Title +
                 ((ECTS) ? ", ECTS:" + ECTS : "") +
                 ((Certificate) ? ", Certificate:" + Certificate : "") +
                 ", ApplyDate:" + ApplyDate +
                 ((ExamDate.trim()) ? ", ExamDate: " + ExamDate : "") +
                 ", Mark:" + Mark + ", Status:" + Status)*/
                courses.push({
                    id: ID,
                    title: Title,
                    ects: ECTS,
                    certificate: Certificate,
                    applyDate: ApplyDate,
                    examDate: ExamDate,
                    mark: Mark,
                    status: Status
                });
            });
        }

        return callback(null, courses)
    } catch (err) {
        return callback(err, null)
    }
};

Parser.prototype.getExamGrades = function (document, callback) {
    var courses = [];

    try {
        if (this.department === DEPART.MPES) {
            document.window.document.querySelectorAll('#exetastiki_grades tbody tr').forEach(function (tr) {

                var td = tr.querySelectorAll('td');
                var ID = td[1].innerHTML;
                var Title = td[2].innerHTML;
                var Mark = td[3].innerHTML;
                var Cemester = td[4].innerHTML;
                var ApplyDate = td[5].innerHTML;
                var ExamDate = td[6].innerHTML;
                var Status = td[7].innerHTML;

                // console.log("ID: " + ID + ", Title:" + Title + ", Cemester:" + Cemester + ((Mark.trim()) ? ", Mark: " + Mark : "") + ", ApplyDate:" + ApplyDate + ((ExamDate.trim()) ? ", ExamDate: " + ExamDate : "") + ", Status: " + Status)
                courses.push({
                    id: ID,
                    title: Title,
                    cemester: Cemester,
                    applyDate: ApplyDate,
                    examDate: ExamDate,
                    mark: Mark,
                    status: Status
                });
            });
        }
    } catch (err) {
        return callback(err, null)
    }

};

Parser.prototype.getIntercalaryExamGrades = function (document, callback) {
    var courses = [];

    try {
        if (this.department === DEPART.MPES) {
            document.window.document.querySelectorAll('#exetastiki_grades_emvolimi tbody tr').forEach(function (tr) {

                var td = tr.querySelectorAll('td');
                var ID = td[1].innerHTML;
                var Title = td[2].innerHTML;
                var Mark = td[3].innerHTML;
                var Cemester = td[4].innerHTML;
                var ApplyDate = td[5].innerHTML;
                var ExamDate = td[6].innerHTML;
                var Status = td[7].innerHTML;

                // console.log("ID: " + ID + ", Title:" + Title + ", Cemester:" + Cemester + ((Mark.trim()) ? ", Mark: " + Mark : "") + ", ApplyDate:" + ApplyDate + ((ExamDate.trim()) ? ", ExamDate: " + ExamDate : "") + ", Status: " + Status)
                courses.push({
                    id: ID,
                    title: Title,
                    cemester: Cemester,
                    applyDate: ApplyDate,
                    examDate: ExamDate,
                    mark: Mark,
                    status: Status
                });
            });
        }
    } catch (err) {
        return callback(err, null)
    }

};

Parser.prototype.getUserDetails = function (document, cookie, callback) {
    if (this.department === DEPART.MPES) {
        try {
            var student_name = document.window.document.querySelector('#header_login u').innerHTML;
            var student_id = document.window.document.querySelector('#tabs-1 h2').innerHTML.replace('Μητρώο φοιτητή: ', '').replace(/ -.*/i, '').trim();
            var status = document.window.document.querySelector('#tabs-1 h2').innerHTML.replace(/.*Κατάσταση:/ig, '').trim();

            //console.log('AM: ' + student_id + ', Name: ' + student_name + ", Κατάσταση: " + status);
            return callback(null, {id: student_id, name: student_name, status: status});
        } catch (err) {
            err.message = 'Probably unauthenticated or icarus page changed.';
            return callback(err)
        }
    } else {
        request({
            url: this.department.url + '/request.php',
            method: 'GET',
            headers: {'Cookie': cookie}
        }, function (error, response, body) {
            if (error) {
                console.log('error:', error); // Print the error if one occurred
                return callback(error)
            }

            // parse html
            var doc = new JSDOM(body);

            try {
                var student_id = doc.window.document.querySelector('input[name="am"]').value;
                var student_name = doc.window.document.querySelector('input[name="fname"]').value + " " + doc.window.document.querySelector('input[name="sname"]').value;
                var fathername = doc.window.document.querySelector('input[name="father"]').value;
                var address = doc.window.document.querySelector('input[name="address"]').value;
                var phone = doc.window.document.querySelector('input[name="emergency"]').value;

                //console.log('AM: ' + student_id + ', Name: ' + student_name + ", Father: " + fathername + ", address: " + address + ", phone: " + phone);
                return callback(null, {
                    id: student_id,
                    name: student_name,
                    father: fathername,
                    address: address,
                    phone: phone
                });
            } catch (err) {
                err.message = 'Probably unauthenticated or icarus page changed.';
                return callback(err)
            }
        });
    }
};

Parser.prototype.getCookie = function (callback) {
    request({
        url: this.department.url + '/authentication.php',
        form: JSON.parse('{ "username": "' + this.username + '", "' + ((this.department === DEPART.MPES) ? "pwd" : "password") + '": "' + this.password + '" }'),
        headers: {Referer: 'https://icarus-icsd.aegean.gr/'},
        method: 'POST'
    }, function (error, response) {
        if (error) {
            console.log('error:', error); // Print the error if one occurred
            return callback(error, null);
        }

        // get the session cookie
        var cookie = response.headers['set-cookie'];
        // set cookie in class
        this.cookie = cookie;

        return callback(null, cookie);
    })
};

Parser.prototype.authenticate = function (callback) {
    this.getCookie(function (error, cookie) {
        if (error)
            return callback(error, null);

        // check if logged in
        request({
            url: self.department.url + '/' + self.department.main_url,
            method: 'GET',
            headers: {'Cookie': cookie},
            encoding: 'binary',
            body: 'buffer'
        }, function (error, response, body) {
            if (error) {
                console.log('error:', error); // Print the error if one occurred
                return callback(error, null);
            }

            // parse charset
            var charset = charsetParser(body);

            // decode binary with charset
            var decodedBody = iconv.decode(body, charset);

            //remove comments correct & symbol (encoding issues)
            decodedBody = decodedBody.replace(/<!--[\s\S]/g, '').replace(/&/g, 'και');

            // parse html
            var document = new JSDOM(decodedBody);

            var status;

            // check which department are we looking for
            if (self.department === DEPART.MPES) {
                var student_name = document.window.document.querySelector('#header_login u').innerHTML;

                // check if student name exists, that indicates if user is loggedin.
                status = (student_name.trim()) ? true : false;
            } else {
                var loginbox = document.window.document.querySelector('.login-box');

                // check to see if login-box exists else user is logged in
                status = (loginbox) ? false : true;
            }

            return callback(null, {authenticated: status, document: document, cookie: cookie});
        });

    });
};

Parser.prototype.getSessionInfo = function () {
    return {username: this.username, department: this.department};
};

Parser.prototype.getCurriculumToDeclare = function (cookie, callback) {

    request({
        url: this.department.url + '/student_dilosi.php', method: 'GET',
        headers: {'Cookie': cookie},
        encoding: 'binary'
    }, function (error, response, body) {
        if (error) {
            console.log('error:', error); // Print the error if one occurred
            return callback(error, null);
        }

        if (self.department !== DEPART.MPES) {
            return callback(new Error('getCurriculumToDeclare() Only works with ' + DEPART.MPES.name), null)
        }

        // parse charset
        var charset = charsetParser(body);

        // decode binary with charset
        var decodedBody = iconv.decode(body, charset);

        //remove comments correct & symbol (encoding issues)
        decodedBody = decodedBody.replace(/&/g, 'και');

        // parse html
        var document = new JSDOM(decodedBody);

        var courses = [];

        document.window.document.querySelectorAll('table tr').forEach(function (tr) {

            var td = tr.querySelectorAll('td');

            // check if something is undefined and continue to next iteration
            if (td[2] || td[3] || td[4] || td[5] || td[6]) {

                // parse data
                var ID = td[2].innerHTML;
                var Title = td[3].innerHTML;
                var Cycle;
                switch (parseInt(td[4].innerHTML.trim(), 10)) {
                    case 1:
                        Cycle = 'Ασφάλεια Πληροφοριακών και Επικοινωνιακών Συστημάτων και Ιδιωτικότητα';
                        break;
                    case 2:
                        Cycle = 'Πληροφοριακά Συστήματα και Επιχειρηματικότητα';
                        break;
                    case 3:
                        Cycle = 'Τεχνολογίες Υπολογιστών και Τηλεπικοινωνιών';
                        break;
                    case 4:
                        Cycle = 'Επικοινωνιακά Συστήματα και Δίκτυα';
                        break;
                    case 5:
                        Cycle = 'Διαχείριση Πληροφορίας και Ευφυή Συστήματα';
                        break;
                    case 6:
                        Cycle = 'Θεμελιώσεις της Επιστήμης των Υπολογιστών';
                        break;
                    default:
                        break;
                }
                var Type = td[5].innerHTML;
                var ECTS = td[6].innerHTML;

                courses.push(JSON.parse('{ "id": "' + ID + '", "' +
                    'title": "' + Title + '", "' +
                    ((Cycle) ? 'cycle": "' + Cycle + '", "' : "") +
                    'type": "' + Type + '", "' +
                    'ects": "' + ECTS + '"}'));
            }
        });

        return callback(null, courses)
    })
};

Parser.prototype.postCurriculumToDeclare = function (courses, cookie, callback) {
    var formData = {};

    if (this.department === DEPART.MPES) {
        formData.count_lessons_etous = "1";
        formData.continue = "1";
        for (var i in courses) {
            if (courses.hasOwnProperty(i)) {
                formData["new_lesson_ids[" + i + "]"] = courses[i];
            }
        }

        request({
            url: this.department.url + '/student_dilosi.php',
            formData: formData,
            method: 'POST',
            headers: {'Cookie': cookie},
            encoding: 'binary'
        }, function (error, response, body) {
            if (error) {
                console.log('error:', error); // Print the error if one occurred
                return callback(error, null);
            }

            if (self.department !== DEPART.MPES) {
                return callback(new Error('postCurriculumToDeclare() Only works with ' + DEPART.MPES.name), null);
            }

            // parse charset
            var charset = charsetParser(body);

            // decode binary with charset
            var decodedBody = iconv.decode(body, charset);

            // parse html
            var document = new JSDOM(decodedBody);

            return callback(null, decodedBody);
        });
    }

};

Parser.prototype.postRequestToDepartment = function (data, cookie, callback) {
    var formData = {};

    if (this.department === DEPART.MPES) {

        // check data
        if (data.id === null || data.surname === null ||
            data.name === null || data.father === null ||
            data.semester === null || data.address === null ||
            data.phone === null || data.method === null ||
            data.sent_address === null || data.requests === null)
            return callback(new Error("JSON data is in wrong format."), null);

        // prepare request
        formData["aitisi_student_id"] = data.id;
        formData["aitisi_surname"] = data.surname;
        formData["aitisi_name"] = data.name;
        formData["aitisi_father"] = data.father;
        formData["aitisi_semester"] = data.semester;
        formData["aitisi_address"] = data.address;
        formData["aitisi_phone"] = data.phone;
        formData["aitisi_send_method"] = data.method;
        formData["aitisi_send_address"] = data.sent_address;
        // initialize first so order may not change in JSON
        for (var i = 0; i < 11; i++) {
            formData["prints_no[" + i + "]"] = '0';
        }

        for (i in data.requests) {
            if (data.requests.hasOwnProperty(i)) {
                switch (data.requests[i].name) {
                    case 'Βεβαίωση Σπουδών':
                        formData["prints_no[0]"] = data.requests[i].amount;
                        break;
                    case 'Πιστοποιητικό Αναλυτικής Βαθμολογίας':
                        formData["prints_no[1]"] = data.requests[i].amount;
                        break;
                    case 'Πιστοποιητικό Αναλυτικής Βαθμολογίας Πτυχιούχου, με Βαθμό Πτυχίου':
                        formData["prints_no[2]"] = data.requests[i].amount;
                        break;
                    case 'Πιστοποιητικό Αναλυτικής Βαθμολογίας Πτυχιούχου, χωρίς Βαθμό Πτυχίου':
                        formData["prints_no[3]"] = data.requests[i].amount;
                        break;
                    case 'Βεβαίωση για την στρατολογία':
                        formData["prints_no[4]"] = data.requests[i].amount;
                        break;
                    case 'Βεβαίωση Διαγραφής':
                        formData["prints_no[5]"] = data.requests[i].amount;
                        break;
                    case 'Επικυρωμένο Αντίγραφο Πτυχίου':
                        formData["prints_no[6]"] = data.requests[i].amount;
                        break;
                    case 'Βεβαίωση ότι πληρώ προϋποθέσεις απόκτησης πτυχίου':
                        formData["prints_no[7]"] = data.requests[i].amount;
                        break;
                    case 'Βεβαίωση ότι συμμετείχα στο μάθημα : Πρακτική Ασκηση':
                        formData["prints_no[8]"] = data.requests[i].amount;
                        break;
                    case 'Πιστοποιητικό στεγαστικού επιδόματος':
                        formData["prints_no[9]"] = data.requests[i].amount;
                        break;
                    case 'Αλλο':
                        formData["prints_no[10]"] = data.requests[i].amount;
                        formData.aitisi_allo = data.requests[i].what;
                        break;
                    default:
                        break;
                }
            }
        }
        formData["send"] = 'send';
    } else {
        // check data
        if (data.requests === null || data.address === null ||
            data.address2 === null || data.id === null || data.emergency === null ||
            data.father === null || data.name === null || data.other === null ||
            data.surname === null)
            return callback(new Error("JSON data is in wrong format."), null);

        // prepare request
        formData = {
            am: data.id,
            sname: data.surname,
            fname: data.name,
            father: data.father,
            address: data.address,
            emergency: data.phone,
            address2: data.address2,
            other: data.method,
            otherTxt: '',
            sendMail: "sendMail"
        };

        for (var i in data.requests) {
            if (data.requests.hasOwnProperty(i)) {
                switch (data.requests[i].name) {
                    case 'Βεβαίωση Σπουδών':
                        formData.Analytiki = data.requests[i].amount;
                        break;
                    case 'Πιστοποιητικό Αναλυτικής Βαθμολογίας':
                        formData.Vevaiosi = data.requests[i].amount;
                        break;
                    case 'Βεβαίωση για την στρατολογία':
                        formData.VevaiosiArmy = data.requests[i].amount;
                        break;
                    case 'Βεβαίωση ότι πληρώ προϋποθέσεις απόκτησης πτυχίου χωρίς βαθμό πτυχίου':
                        formData.VevaiosiDegree = data.requests[i].amount;
                        break;
                    case 'Βεβαίωση ότι πληρώ προϋποθέσεις απόκτησης πτυχίου με βαθμό πτυχίου (*)':
                        formData.VevaiosiDegree_1 = data.requests[i].amount;
                        break;
                    case 'Βεβαίωση ότι συμμετείχα στο μάθημα : Πρακτική Ασκηση':
                        formData.VevaiosiPraktiki = data.requests[i].amount;
                        break;
                    case 'Βεβαίωση με τα υπολειπόμενα μαθήματα για απόκτηση πτυχίου':
                        formData.VevaiosiRemainingLessons = data.requests[i].amount;
                        break;
                    case 'Αλλο':
                        formData.other = data.requests[i].amount;
                        formData.otherTxt = data.requests[i].what;
                        break;
                    default:
                        break;
                }
            }
        }
    }

    // build the request
    var option = {};
    option.url = this.department.url + this.department.request_url;
    (this.department === DEPART.MPES) ? option.formData = formData : option.form = formData;
    option.method = 'POST';
    option.headers = {'Cookie': cookie};
    option.encoding = 'binary';

    request(option, function (error, response, body) {
        if (error) {
            console.log('error:', error); // Print the error if one occurred
            return callback(error, null);
        }

        // parse charset
        var charset = charsetParser(body);

        // decode binary with charset
        var decodedBody = iconv.decode(body, charset);

        // parse html
        var document = new JSDOM(decodedBody);

        return callback(null, decodedBody)
    });

};

Parser.prototype.getDocument = function (cookie, callback) {
    // check if logged in
    request({
        url: self.department.url + '/' + self.department.main_url,
        method: 'GET',
        headers: {'Cookie': cookie},
        encoding: 'binary',
        body: 'buffer'
    }, function (error, response, body) {
        if (error) {
            console.log('error:', error); // Print the error if one occurred
            return callback(error, null);
        }

        // parse charset
        var charset = charsetParser(body);

        // decode binary with charset
        var decodedBody = iconv.decode(body, charset);

        //remove comments correct & symbol (encoding issues)
        decodedBody = decodedBody.replace(/<!--[\s\S]/g, '').replace(/&/g, 'και');

        // parse html
        var document = new JSDOM(decodedBody);

        return callback(null, document);
    });
}

// export the class
module.exports = Parser;