From fcf45614a3298205541e5e36a2f1705f987941c9 Mon Sep 17 00:00:00 2001 From: Roman Timashev Date: Fri, 26 May 2017 18:41:11 +0300 Subject: [PATCH] Schedule serverside --- src/client/app.js | 13 +--- src/components/Schedule.js | 130 +++++++++++++++++++++++++++++++++ src/components/ScheduleList.js | 20 +++++ src/core/schedule.js | 92 +++++++++++++++-------- src/lib/array.js | 14 ++++ src/models/menu.js | 10 ++- src/models/schedule.js | 16 ++++ src/routes/collective.js | 24 ------ src/routes/index.js | 4 - src/routes/schedule.js | 93 ++++++++++++++--------- src/server.js | 2 + 11 files changed, 311 insertions(+), 107 deletions(-) create mode 100644 src/components/Schedule.js create mode 100644 src/components/ScheduleList.js delete mode 100644 src/routes/collective.js diff --git a/src/client/app.js b/src/client/app.js index f9e24d1c..b7b8f0ec 100644 --- a/src/client/app.js +++ b/src/client/app.js @@ -82,18 +82,7 @@ app.config(($locationProvider, $routeProvider) => { } })) - let routers = [ - { - name: '/schedule/:period?/:semester?', - template: '', - title: 'Расписание', - resolve: { - list: api => api.schedule - .list() - .then(i => i.data) - } - } - ] + let routers = [] .concat(pages) .map(i => { let path = i.name diff --git a/src/components/Schedule.js b/src/components/Schedule.js new file mode 100644 index 00000000..1905b61f --- /dev/null +++ b/src/components/Schedule.js @@ -0,0 +1,130 @@ +const React = require('react') + +import {getDates} from '../utils/date' +import {shortName} from '../models/collective' + +const now = new Date() +const dates = getDates(now); + +const days = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun']; +const isToday = weekDayIndex => (now.getDay() - 1) === weekDayIndex; +const weekDay = weekDayIndex => dates[weekDayIndex]; +const short = shortName; + +const todayClass = i => isToday(i) + ? 'current' + : '' + +const HeadDay = ({i, children}) => ( +
+

{children}

+

{weekDay(i)}

+
+) + +const days2 = [ + 'Понедельник', + 'Вторник', + 'Среда', + 'Четверг', + 'Пятница', + 'Суббота', +] + +const Schedule = ({groups}) => ( +
+
+
Гр.
+ + {days2.map((day, index) => ( + {day} + ))} +
+ +
+ {groups.map((group, index) => ( + + ))} +
+
+) + +const GroupRow = ({name, time, week}) => ( +
+
+

{name}

+

{time}

+
+ + {week.map((day, index) => ( + + ))} +
+) + +const Group = ({day, dayIndex}) => ( +
+ {day.map((lesson, index) => ( + + ))} +
+) + +const Cell = ({course, teacher, time}) => ( +
+ + { + console.log(time) + } + + + + + + {time + .map(range => ({range})) + .map((range, index) => ( + + ))} +
+) + +const Lesson = ({title, url}) => ( +

+ {url + ? ( + + {title} + + ) + : ( + + {title} + + ) + } +

+) + +const Teacher = ({name, url}) => ( +

+ {url + ? ( + + {short(name)} + + ) + : ( + + {short(name)} + + ) + } +

+) + +const TimeRange = ({range}) => ( +

{(range || []).join(' — ')}

+) + +module.exports = Schedule diff --git a/src/components/ScheduleList.js b/src/components/ScheduleList.js new file mode 100644 index 00000000..36fc648a --- /dev/null +++ b/src/components/ScheduleList.js @@ -0,0 +1,20 @@ +const React = require('react') +const text = require('../core/schedule').text + +const ScheduleList = ({schedules}) => ( +
+ +
+) + +const Schedule = ({url, semester, period}) => ( +
  • + {text({semester, period})} +
  • +) + +module.exports = ScheduleList diff --git a/src/core/schedule.js b/src/core/schedule.js index be67d9a8..3e89b0dd 100644 --- a/src/core/schedule.js +++ b/src/core/schedule.js @@ -1,18 +1,20 @@ import {c} from '../core/db' -import {select} from '../utils/fn' import {createMap} from '../utils/common' import {getCollective} from './collective' -import {scheduleDate, getPeriod as schedulePeriod} from '../models/schedule' +import {scheduleDate, getPeriod as schedulePeriod, getPeriodString} from '../models/schedule' import {getCourse} from '../models/course' +const last = require('../lib/array').last +const sortBy = require('../lib/sort').sortBy + const SCHEDULES = 'schedules' -export async function getSchedule(period, semester) { +async function findSchedule(period, semester) { const schedule = await c(SCHEDULES).findOne({ $or: [ - {period: period}, - {period: schedulePeriod(period)} + {period: period}, + {period: schedulePeriod(period)} ], semester: semester }) @@ -20,19 +22,44 @@ export async function getSchedule(period, semester) { return schedule ? migrate(schedule) : null } -export async function getSchedules(fields = ['_id', 'id', 'period', 'semester']) { - const list = await c(SCHEDULES) - .find({}) - .toArray() +async function findAllScheduleParams() { + const schedules = await c(SCHEDULES) + .find({}, { + period: 1, + semester: 1, + _id: 0, + }) + .toArray() - const schedules = await Promise.all(list.map(migrate)) return schedules - .sort((a, b) => { - const ad = scheduleDate(a).getTime() - const bd = scheduleDate(b).getTime() - return ad - bd -}) - .map(select(fields)) + .map(i => ({ + ...i, + period: schedulePeriod(i.period), + })) + .sort(sortBy( + i => scheduleDate(i).getTime(), + true, + )) +} + +async function findDefaultScheduleParams() { + const schedules = await findAllScheduleParams() + return last(schedules + .map(i => ({ + ...i, + period: getPeriodString(i.period), + })) + ) +} + +function text({semester, period}) { + const word = semester => [['spring', 'Весна'], ['autumn', 'Осень']] + .find(i => i[0] === semester) + [1] + const periodIndex = semester === 'spring' ? 1 : 0 + const year = period[periodIndex] + + return `${word(semester)} ${year} года` } async function migrate(schedule) { @@ -49,7 +76,7 @@ async function migrate(schedule) { function migrate10to20(schedule) { const dayNames = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun'] const time = time => time - .map(i => i.split(' ')) + .map(i => i.split(' ')) const week = days => days.reduce((week, lesson, index) => { if (lesson) { @@ -66,23 +93,23 @@ function migrate10to20(schedule) { version: '2.0', period: schedulePeriod(schedule.period), groups: schedule.schedule - .map(group => ({ - name: group.group, - time: group.time, - week: week(group.week) -})) + .map(group => ({ + name: group.group, + time: group.time, + week: week(group.week) + })) }) } async function migrate20to30(schedule) { - const days = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun'] + const days = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat']//, 'sun'] const persons = await getCollective() const person = createMap(i => i.id, persons) const week = week => days - .map(day => week[day] || []) - .map(lessons => lessons.map(lesson)) + .map(day => week[day] || []) + .map(lessons => lessons.map(lesson)) const lesson = i => ({ time: i.time, @@ -107,10 +134,15 @@ async function migrate20to30(schedule) { return Object.assign(schedule, { version: '3.0', groups: schedule.groups - .map(group => ({ - name: group.name, - time: group.time, - week: week(group.week) -})) + .map(group => ({ + name: group.name, + time: group.time, + week: week(group.week) + })) }) } + +exports.findSchedule = findSchedule +exports.findAllScheduleParams = findAllScheduleParams +exports.findDefaultScheduleParams = findDefaultScheduleParams +exports.text = text diff --git a/src/lib/array.js b/src/lib/array.js index 78715bd1..1888d3b0 100644 --- a/src/lib/array.js +++ b/src/lib/array.js @@ -9,4 +9,18 @@ function splitBy(key) { } } +function head(list) { + return Array.isArray(list) && list.length + ? list[0] + : null +} + +function last(list) { + return Array.isArray(list) && list.length + ? list[list.length - 1] + : null +} + exports.splitBy = splitBy +exports.head = head +exports.last = last diff --git a/src/models/menu.js b/src/models/menu.js index 30dda425..0eefd0e5 100644 --- a/src/models/menu.js +++ b/src/models/menu.js @@ -10,9 +10,13 @@ export default [ ], }, { - 'text': 'Расписание', - 'url': '/schedule', - 'color': 'green' + text: 'Расписание', + url: '/schedule', + color: 'green', + items: [ + {url: '*', text: ''}, + ] + }, { 'text': 'Поступление', diff --git a/src/models/schedule.js b/src/models/schedule.js index c5ee85a6..76435652 100644 --- a/src/models/schedule.js +++ b/src/models/schedule.js @@ -28,3 +28,19 @@ export function getPeriod(i){ return i.map(Number); } + +/** + * + * f("2012-2015") -> "2012-2015" + * f(["2012", "2015"]) -> "2012-2015" + * f([2012, 2015]) -> "2012-2015" + * + * @param i + * @returns {*} + */ +function getPeriodString(i) { + return getPeriod(i) + .join('-') +} + +exports.getPeriodString = getPeriodString diff --git a/src/routes/collective.js b/src/routes/collective.js deleted file mode 100644 index 08650a93..00000000 --- a/src/routes/collective.js +++ /dev/null @@ -1,24 +0,0 @@ -import route from 'koa-route'; -import {json} from './'; -import {sortByPattern} from '../utils/sort'; -import db from '../core/db'; - -let split = d => s => s.split(d); -let toArray = split(','); - -export default function () { - return route.get('/collective', json( - function *() { - this.type = 'application/json'; - let pattern = toArray(this.query.sort || ''); - - let data = yield db.c('collective').find(); - if (!data) { - this.status = 404; - return; - } - - this.body = sortByPattern(data, pattern, i => i.id); - } - )) -}; diff --git a/src/routes/index.js b/src/routes/index.js index ba2fba90..e4855782 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -6,14 +6,10 @@ import {map, assign} from '../utils/common' import {index as indexFile} from '../config' import sitemap from './sitemap' -import schedule from './schedule' -import pages from './pages' export function routes(store) { return compose([ sitemap(), - schedule(), - pages(), ]) } diff --git a/src/routes/schedule.js b/src/routes/schedule.js index 8a283d80..1951b432 100644 --- a/src/routes/schedule.js +++ b/src/routes/schedule.js @@ -1,40 +1,65 @@ -import compose from 'koa-compose'; -import route from 'koa-route'; -import {json} from './'; +const React = require('react') +const Share = require('../components/Share') +const Schedule = require('../components/Schedule') +const ScheduleList = require('../components/ScheduleList') +const {render} = require('../lib/render') +const getPeriodString = require('../models/schedule').getPeriodString +const getPathWithNoTrailingSlash = require('../lib/url').getPathWithNoTrailingSlash +const {get} = require('koa-route') -import {getSchedule, getSchedules} from '../core/schedule'; +const {findSchedule, findDefaultScheduleParams, findAllScheduleParams} = require('../core/schedule') +const text = require('../core/schedule').text -export default function () { - return compose([ - list(), - schedule() - ]); -}; - -function list() { - return route.get('/schedule/list', json( - async(ctx) => { - ctx.type = 'application/json'; - const data = await getSchedules(); - - if (!data) ctx.status = 404; - else ctx.body = data; - } - )); +function getMeta(schedule) { + const t = text(schedule) + return { + title: t, + description: t, + } } -function schedule() { - return route.get('/schedule/:period?/:semester?', json( - async(ctx, period, semester) => { - ctx.type = 'application/json'; +function getSchedule() { + return get('/schedule/:period?/:semester?', async (ctx, period, semester) => { + const useRoute = Boolean(period) && Boolean(semester) + if (useRoute) { + const path = getPathWithNoTrailingSlash(ctx.path) - let data = await getSchedule(period, semester); - if (!data) { - ctx.status = 404; - return; - } + const data = await findSchedule(period, semester) + if (data) { - ctx.body = data; - } - )) -} \ No newline at end of file + //let schedules = await findAllScheduleParams() + //schedules = schedules.map(({semester, period}) => ({ + // period, + // semester, + // url: `/schedule/${getPeriodString(period)}/${semester}`, + //})) + + const Component = ( +
    + {/**/} + + + + +
    + ) + + ctx.type = 'text/html' + ctx.body = await render(path, Component, getMeta(data)) + } else { + ctx.status = 404 + } + } else { + const route = await findDefaultScheduleParams() + + if (route) { + const {period, semester} = route + ctx.redirect(`/schedule/${period}/${semester}`) + } else { + ctx.status = 404 + } + } + }) +} + +exports.getSchedule = getSchedule diff --git a/src/server.js b/src/server.js index 126ab047..14899f70 100644 --- a/src/server.js +++ b/src/server.js @@ -27,6 +27,7 @@ const gallery = require('./routes/gallery') const teachers = require('./routes/teachers') const documents = require('./routes/documents') const document = require('./routes/document') +const schedule = require('./routes/schedule') const dirPublic = path.join(__dirname, '../public') const dirTemplates = path.join(__dirname, 'templates') @@ -74,6 +75,7 @@ export default function (store) { app.use(teachers.getTeacher()) app.use(documents.getDocuments()) app.use(document.getDocument()) + app.use(schedule.getSchedule()) app.use(routes(store)) return Server(app.callback())