aboutsummaryrefslogtreecommitdiff
path: root/src/server/lib/getMeetingpointData.js
blob: 2e8a6eaad1a31fd4e9c85a67e40c66180f8ee946 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
const Promise = require('bluebird');
const cheerio = require('cheerio');
const iconv = require('iconv-lite');
const debounce = require('promise-debounce');
const _ = require('lodash');
const request = Promise.promisify(require('request'));

const getUrlOfUser = require('./getURLOfUser');

let meetingpointData;
let lastUpdate;

function parseUsers(page) {
  const script = page('script').eq(1).text();

  const regexs = [/var classes = \[(.+)\];/, /var teachers = \[(.+)\];/, /var rooms = \[(.+)\];/, /var students = \[(.+)\];/];
  const items = regexs.map(regex => script.match(regex)[1].split(',').map(item => item.replace(/"/g, '')));

  const classes = items[0].map((item, index) => ({
    type: 'c',
    value: item,
    index,
  }));

  const teachers = items[1].map((item, index) => ({
    type: 't',
    value: item,
    index,
  }));

  const rooms = items[2].map((item, index) => ({
    type: 'r',
    value: item,
    index,
  }));

  const students = items[3].map((item, index) => ({
    type: 's',
    value: item,
    index,
  }));

  return _.flatten([classes, teachers, rooms, students]);
}

function parseWeeks(page) {
  const weekSelector = page('select[name="week"]');
  const weeks = _.map(weekSelector.children(), option => ({
    id: cheerio(option).attr('value'),
    text: cheerio(option).text(),
  }));

  return weeks;
}

function parseAltText(page) {
  return page('center > font').eq(2).text().trim();
}

function combineUsers(usersArrays) {
  return _.uniqBy(_.flatten(usersArrays), user => `${user.type}/${user.value}`);
}

function getAlts(users) {
  const requests = users.map(user =>
    request(getUrlOfUser('dag', user.type, user.index, 7), { timeout: 8000, encoding: null }));

  return Promise.all(requests).then(teacherResponses =>
    teacherResponses.map((teacherResponse, index) => {
      const utf8Body = iconv.decode(teacherResponse.body, 'iso-8859-1');
      const teacherResponseBody = cheerio.load(utf8Body);

      const teacherName = parseAltText(teacherResponseBody);

      return {
        ...users[index],
        alt: teacherName,
      };
    }));
}

function getMeetingpointData() {
  const navbarRequests = [
    request('http://www.meetingpointmco.nl/Roosters-AL/doc/dagroosters/frames/navbar.htm', { timeout: 5000 }),
    request('http://www.meetingpointmco.nl/Roosters-AL/doc/basisroosters/frames/navbar.htm', { timeout: 5000 }),
  ];

  return Promise.all(navbarRequests)
    .then(([dailyScheduleResponse, basisScheduleResponse]) => {
      const dailySchedulePage = cheerio.load(dailyScheduleResponse.body);
      const basisSchedulePage = cheerio.load(basisScheduleResponse.body);

      const users = parseUsers(dailySchedulePage);
      const dailyScheduleWeeks = parseWeeks(dailySchedulePage);
      const basisScheduleWeeks = parseWeeks(basisSchedulePage);

      const teachers = users.filter(user => user.type === 't');

      return getAlts(teachers)
        .then(teachersWithAlts => ({
          users: combineUsers([teachersWithAlts, users]),
          dailyScheduleWeeks,
          basisScheduleWeeks,
        }))
        .catch(() => ({
          // Just return the user data without the alts if getAlts fails, since
          // the alts are non-essential.
          users,
          dailyScheduleWeeks,
          basisScheduleWeeks,
        }));
    });
}

function getMeetingpointDataCacheWrapper() {
  if (meetingpointData == null || new Date() - lastUpdate > 30 * 60 * 1000) { // 30 minutes
    return getMeetingpointData().then((meetingpointData_) => {
      lastUpdate = new Date();
      meetingpointData = meetingpointData_;

      return meetingpointData;
    });
  }

  return Promise.resolve(meetingpointData);
}

module.exports = debounce(getMeetingpointDataCacheWrapper);