-
- {this.state.cards.map(card =>
-
-
- {card.description}
-
-
-
- ,
- )}
-
+
+
+ {this.state.events.map(event =>
+
+
+ {`${moment(event.start).format('dddd, MMMM Do YYYY, HH:mm')} to ${moment(event.end).format('MMMM Do, HH:mm')}`}
+
+
+
+ ,
+ )}
+
+
+
+
+
+
+
+
+
+
+
+
{
+ this.database.createEventWeekly(req.params.school, req.params.group, req.body)
+ .then((data) => {
+ res.json(data);
+ })
+ .catch(next);
+ });
this.router.post('/schools/:school/groups/:group/eventsOnce/', this.auth, (req, res, next) => {
this.database.createEventOnce(req.params.school, req.params.group, req.body)
.then((data) => {
@@ -134,6 +143,23 @@ export default class API {
.catch(next);
});
+ this.router.get('/schools/:school/users/:id/events', this.auth, (req, res, next) => {
+ this.database.getUserEventsBetween(
+ req.params.school,
+ req.params.id,
+ req.query.start,
+ req.query.end,
+ )
+ .then((data) => {
+ const eventsWeekly = computeOccurrences(data.eventsWeekly, req.query.start, req.query.end);
+ res.json(data.eventsOnce
+ .map(e => Object.assign({ type: 'once' }, e))
+ .concat(eventsWeekly)
+ .map(e => Object.assign({ type: 'weekly' }, e)));
+ })
+ .catch(next);
+ });
+
this.router.use('/*', (req, res, next) => {
next(new NotFoundError());
});
diff --git a/server/database.js b/server/database.js
index f5232fb..89ebe63 100644
--- a/server/database.js
+++ b/server/database.js
@@ -1,7 +1,7 @@
import mysql from 'mysql';
import semver from 'semver';
-import { fatal, getVersion } from './utils';
+import { fatal, getVersion, stripTimezone } from './utils';
import { NotFoundError, attachNoun } from './errors';
const DATABASE = 'chronos';
@@ -75,7 +75,7 @@ export default class Database {
}
async getUserGroups(school, id) {
return this.query(`
- SELECT *
+ SELECT group_.*
FROM member, group_
WHERE member.group_ = group_.id
AND member.user = ?
@@ -85,7 +85,7 @@ export default class Database {
async getGroups(school) {
return this.query(`
- SELECT *
+ SELECT group_.*
FROM user, member, group_
WHERE member.group_ = group_.id
AND member.user = user.id
@@ -130,21 +130,36 @@ export default class Database {
FROM event_once
WHERE event_once.group_ = ?
`, [id]);
- return Promise.all([getGroup, getMembers, getEventsOnce])
+ const getEventsWeekly = this.query(`
+ SELECT *
+ FROM event_weekly
+ WHERE event_weekly.group_ = ?
+ `, [id]);
+ return Promise.all([getGroup, getMembers, getEventsOnce, getEventsWeekly])
.then(results => Object.assign({}, results[0], {
members: results[1].map(m => Object.assign(m, {
pwd_hash: undefined,
oid_id: undefined,
})),
eventsOnce: results[2],
+ eventsWeekly: results[3],
}));
}
+ async createEventWeekly(school, group, data) {
+ console.log(data.starttime);
+ return this.query(`
+ INSERT INTO event_weekly (group_, name, day, starttime, endtime)
+ VALUES (?, ?, ?, ?, ?)
+ `, [group, data.name, data.day, stripTimezone(data.starttime), stripTimezone(data.endtime)]);
+ }
+
async createEventOnce(school, group, data) {
+ console.log(data.starttime);
return this.query(`
INSERT INTO event_once (group_, name, start, end)
VALUES (?, ?, ?, ?)
- `, [group, data.name, data.start, data.end]);
+ `, [group, data.name, stripTimezone(data.start), stripTimezone(data.end)]);
}
async getEventOnce(school, group, id) {
return this.query(`
@@ -154,6 +169,7 @@ export default class Database {
AND event_once.id = ?
`, [group, id]);
}
+
// eslint-disable-next-line
async getEventClashesWith(school, group, id) {
// TODO
@@ -161,6 +177,26 @@ export default class Database {
async getUserEventsBetween(school, user, start, end) {
// oh shit
+ const getEventsOnce = this.query(`
+ SELECT event_once.*
+ FROM member, event_once
+ WHERE member.group_ = event_once.group_
+ AND member.user = ?
+
+ AND (
+ (event_once.start >= ? AND event_once.start <= ?)
+ OR
+ (event_once.end >= ? AND event_once.end <= ?)
+ )
+ `, [user, stripTimezone(start), stripTimezone(end), stripTimezone(start), stripTimezone(end)]);
+ const getEventsWeekly = this.query(`
+ SELECT event_weekly.*
+ FROM member, event_weekly
+ WHERE member.group_ = event_weekly.group_
+ AND member.user = ?
+ `, [user]);
+ return Promise.all([getEventsOnce, getEventsWeekly])
+ .then(results => ({ eventsOnce: results[0], eventsWeekly: results[1] }));
}
query(query, values, options = {}) {
diff --git a/server/utils.js b/server/utils.js
index fc6a58c..7103863 100644
--- a/server/utils.js
+++ b/server/utils.js
@@ -1,13 +1,93 @@
-const getVersion = () => {
+import moment from 'moment-timezone';
+
+export function getVersion() {
if (process.env.npm_package_version) {
return process.env.npm_package_version;
}
throw new Error('Unable to obtain running version');
-};
+}
-const fatal = (e) => {
+export function fatal(e) {
console.error(e);
process.exit(1);
-};
+}
-export { getVersion, fatal };
+export function stripTimezone(date) {
+ // TODO:
+ // move timezone fixes to client side,
+ // let client send dates and times as strings to be directly stored into database
+ const d = new Date(date);
+ if (isNaN(d.getTime())) {
+ return new Date(parseInt(date, 10));
+ }
+ return d;
+}
+
+export function computeOccurrences(events, startd, endd) {
+ const SECONDS_IN_WEEK = 7 * 24 * 60 * 60;
+
+ const start = moment(stripTimezone(startd)).tz('Asia/Singapore');
+ const end = moment(stripTimezone(endd)).tz('Asia/Singapore');
+ const eventsOccurrences = [];
+
+ const secondsToPreviousStartOfWeek =
+ -(
+ (start.day() * 24 * 60 * 60) +
+ (start.hour() * 60 * 60) +
+ (start.minute() * 60) +
+ (start.second())
+ );
+
+ const secondsToEnd =
+ moment(end).unix() -
+ moment(start).unix();
+
+ const secondsToNextOccurrence = events.map((e) => {
+ const startT = e.starttime.split(':').map(c => parseInt(c, 10));
+ const endT = e.endtime.split(':').map(c => parseInt(c, 10));
+ const nextStart =
+ (e.day * 24 * 60 * 60) +
+ (startT[0] * 60 * 60) +
+ (startT[1] * 60) +
+ (startT[2]) +
+ secondsToPreviousStartOfWeek;
+ const nextEnd =
+ (e.day * 24 * 60 * 60) +
+ (endT[0] * 60 * 60) +
+ (endT[1] * 60) +
+ (endT[2]) +
+ secondsToPreviousStartOfWeek;
+ return {
+ start: nextStart,
+ end: nextEnd,
+ };
+ });
+
+ secondsToNextOccurrence.forEach((o) => {
+ while (o.end < 0) {
+ // eslint-disable-next-line no-param-reassign
+ o.start += SECONDS_IN_WEEK;
+ // eslint-disable-next-line no-param-reassign
+ o.end += SECONDS_IN_WEEK;
+ }
+ });
+
+ secondsToNextOccurrence.forEach((o, i) => {
+ while (o.start < secondsToEnd) {
+ const nextStart = moment(start).add(o.start, 'seconds');
+ const nextEnd = moment(start).add(o.end, 'seconds');
+
+ eventsOccurrences.push(Object.assign({}, events[i], {
+ start: nextStart,
+ end: nextEnd,
+ }));
+
+ // eslint-disable-next-line no-param-reassign
+ o.start += SECONDS_IN_WEEK;
+ // eslint-disable-next-line no-param-reassign
+ o.end += SECONDS_IN_WEEK;
+ }
+ });
+
+ return eventsOccurrences;
+}