diff --git a/package.json b/package.json
index 0722d249..d75ce02c 100644
--- a/package.json
+++ b/package.json
@@ -5,11 +5,11 @@
"description": "",
"main": "src/bin/www.js",
"scripts": {
- "start": "node src/index.js",
- "start-next": "NODE_ENV=production node src/index.js",
- "dev": "babel-node src/index.js",
- "build-next": "next build",
- "out": "babel src/ -d out/",
+ "start": "NODE_ENV=production node src/index.js",
+ "dev": "node src/server.js",
+ "next": "next",
+ "build": "next build",
+ "export": "npm run build && next export -o dist",
"gulp": "gulp",
"test": "mocha --compilers js:babel-register",
"coverage": "istanbul cover mocha -- --compilers js:babel-register"
diff --git a/pages/_document.jsx b/pages/_document.jsx
new file mode 100644
index 00000000..69d7a40f
--- /dev/null
+++ b/pages/_document.jsx
@@ -0,0 +1,27 @@
+import React from 'react'
+import Document, { Html, Head, Main, NextScript } from 'next/document'
+
+export default class MyDocument extends Document {
+ // static async getInitialProps(ctx) {
+ // const initialProps = await Document.getInitialProps(ctx);
+ // return { ...initialProps };
+ // }
+
+ render() {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+ }
+}
diff --git a/pages/album/[album].js b/pages/album/[album].js
new file mode 100644
index 00000000..a9a18ebe
--- /dev/null
+++ b/pages/album/[album].js
@@ -0,0 +1,42 @@
+import React from 'react'
+import axios from 'axios'
+import App from '../../src/components/App'
+import Article from '../../src/components/Article'
+import Html from '../../src/components/Html'
+import menuModel from '../../src/models/menu'
+import { buildMenu } from '../../src/lib/menu'
+
+const Page = (props) => (
+
+
+
+)
+
+Page.getInitialProps = async (ctx) => {
+ const pageUrl = ctx.req.url
+ const id = ctx.query.album
+ const apiUrl = `http://localhost:3000/api/albums/${id}`
+ const res = await axios.get(apiUrl)
+ const album = res.data
+
+ return {
+ album,
+ pageUrl,
+ }
+}
+
+export default Page
\ No newline at end of file
diff --git a/pages/api/albums/[album].js b/pages/api/albums/[album].js
new file mode 100644
index 00000000..a88f69e9
--- /dev/null
+++ b/pages/api/albums/[album].js
@@ -0,0 +1,19 @@
+import { dbUri } from '../../../src/config'
+import { connect } from '../../../src/core/db'
+import Album from '../../../src/core/Album'
+
+export default async (req, res) => {
+ await connect(dbUri)
+
+ const id = req.query.album
+ const album = await Album.findById(id)
+
+ if (album) {
+ res.json(album)
+ } else {
+ res.status(404)
+ res.json({
+ error: `Album ${id} not found`
+ })
+ }
+}
diff --git a/pages/api/albums/index.js b/pages/api/albums/index.js
new file mode 100644
index 00000000..de1cf601
--- /dev/null
+++ b/pages/api/albums/index.js
@@ -0,0 +1,19 @@
+import { dbUri } from '../../../src/config'
+import { connect } from '../../../src/core/db'
+import Album from '../../../src/core/Album'
+
+export default async (req, res) => {
+ await connect(dbUri)
+
+ const data = await Album.find({}, { sort: { date: -1 } })
+ if (data) {
+ res.json({
+ items: data,
+ })
+ } else {
+ res.status(404)
+ res.json({
+ error: `Article not found`
+ })
+ }
+}
diff --git a/pages/api/articles/[article].js b/pages/api/articles/[article].js
new file mode 100644
index 00000000..3a35e4af
--- /dev/null
+++ b/pages/api/articles/[article].js
@@ -0,0 +1,22 @@
+import { dbUri } from '../../../src/config'
+import { connect } from '../../../src/core/db'
+import Article from '../../../src/core/Article'
+
+export default async (req, res) => {
+ await connect(dbUri)
+
+ const {
+ query: { article: id }
+ } = req;
+
+ const article = await Article.findById(id)
+
+ if (article) {
+ res.json(article)
+ } else {
+ res.status(404)
+ res.json({
+ error: `Article ${id} not found`
+ })
+ }
+}
diff --git a/pages/api/articles/index.js b/pages/api/articles/index.js
new file mode 100644
index 00000000..fd977d01
--- /dev/null
+++ b/pages/api/articles/index.js
@@ -0,0 +1,22 @@
+import { dbUri } from '../../../src/config'
+import { connect } from '../../../src/core/db'
+import { findArticles } from '../../../src/api/articles'
+
+export default async (req, res) => {
+ await connect(dbUri)
+
+ const { query } = req
+ const page = parseInt(query.page)
+ const pageSize = parseInt(query.pageSize)
+
+ const data = await findArticles(page, pageSize)
+
+ if (data) {
+ res.json(data)
+ } else {
+ res.status(404)
+ res.json({
+ error: `Article ${id} not found`
+ })
+ }
+}
diff --git a/pages/api/files/[document].js b/pages/api/files/[document].js
new file mode 100644
index 00000000..60758a54
--- /dev/null
+++ b/pages/api/files/[document].js
@@ -0,0 +1,20 @@
+import { dbUri } from '../../../src/config'
+import { connect } from '../../../src/core/db'
+import Document from '../../../src/core/Document'
+import { encodeFile } from '../../../src/api/files'
+
+export default async (req, res) => {
+ await connect(dbUri)
+
+ const id = req.query.document
+ const document = await Document.findById(id)
+
+ if (document) {
+ res.json(encodeFile(document))
+ } else {
+ res.status(404)
+ res.json({
+ error: `Document ${id} not found`
+ })
+ }
+}
diff --git a/pages/api/files/index.js b/pages/api/files/index.js
new file mode 100644
index 00000000..44728a8a
--- /dev/null
+++ b/pages/api/files/index.js
@@ -0,0 +1,24 @@
+import { dbUri } from '../../../src/config'
+import { connect } from '../../../src/core/db'
+import Document from '../../../src/core/Document'
+import { encodeFile } from '../../../src/api/files'
+
+export default async (req, res) => {
+ await connect(dbUri)
+
+ const documents = await Document.find({hidden: false})
+ if (documents) {
+ const items = documents
+ .map(encodeFile)
+ .filter(x => x.imageUrl) // skip documents without preview image; needs to be refactored
+
+ res.json({
+ items,
+ })
+ } else {
+ res.status(404)
+ res.json({
+ error: `Documents not found`
+ })
+ }
+}
diff --git a/pages/api/image.js b/pages/api/image.js
new file mode 100644
index 00000000..a4465dbd
--- /dev/null
+++ b/pages/api/image.js
@@ -0,0 +1,21 @@
+import { dbUri } from '../../src/config'
+import { connect } from '../../src/core/db'
+import Image from '../../src/core/Image'
+import ImageArtifactType from '../../src/core/ImageArtifactType'
+
+export default async (req, res) => {
+ await connect(dbUri)
+
+ const file = req.query.file
+ const image = await Image.findByFile(file)
+
+ if (image) {
+ const data = image.getPicture(ImageArtifactType.LARGE)
+ res.json(data)
+ } else {
+ res.status(404)
+ res.json({
+ error: `Image ${file} not found`
+ })
+ }
+}
diff --git a/pages/api/page.js b/pages/api/page.js
new file mode 100644
index 00000000..7012f719
--- /dev/null
+++ b/pages/api/page.js
@@ -0,0 +1,26 @@
+import { dbUri } from '../../src/config'
+import { connect } from '../../src/core/db'
+import Page from '../../src/core/Page'
+import { getPathWithNoTrailingSlash } from '../../src/lib/url'
+
+export default async (req, res) => {
+ await connect(dbUri)
+
+ const page = getPathWithNoTrailingSlash(req.query.page)
+ const resource = await Page.findByUrl(page)
+
+ if (resource) {
+ res.json({
+ id: resource.id,
+ title: resource.title,
+ url: resource.url,
+ data: resource.data,
+ preview: resource.preview,
+ })
+ } else {
+ res.status(404)
+ res.json({
+ error: `Image ${page} not found`
+ })
+ }
+}
diff --git a/pages/api/persons/[person].js b/pages/api/persons/[person].js
new file mode 100644
index 00000000..08ba331c
--- /dev/null
+++ b/pages/api/persons/[person].js
@@ -0,0 +1,21 @@
+import { dbUri } from '../../../src/config'
+import { connect } from '../../../src/core/db'
+import Teacher from '../../../src/core/Teacher'
+import { encodePerson } from '../../../src/api/persons'
+
+export default async (req, res) => {
+ await connect(dbUri)
+
+ const id = req.query.person
+ const person = await Teacher.findById(id)
+ const data = encodePerson(person)
+
+ if (data) {
+ res.json(data)
+ } else {
+ res.status(404)
+ res.json({
+ error: `Article ${id} not found`
+ })
+ }
+}
diff --git a/pages/api/persons/index.js b/pages/api/persons/index.js
new file mode 100644
index 00000000..aa4b8355
--- /dev/null
+++ b/pages/api/persons/index.js
@@ -0,0 +1,33 @@
+import { dbUri } from '../../../src/config'
+import { connect } from '../../../src/core/db'
+import Teacher from '../../../src/core/Teacher'
+import { prioritySort } from '../../../src/lib/sort'
+import { encodePerson } from '../../../src/api/persons'
+
+export default async (req, res) => {
+ await connect(dbUri)
+
+ const order = [
+ 'mg-timasheva',
+ 'va-sarzhin',
+ 'od-gogoleva',
+ 'my-valkova',
+ 'nv-andreeva',
+ 'vv-voronova',
+ ]
+ const teachersSorted = prioritySort.bind(null, [...order], t => t.id)
+
+ const teachers = await Teacher.find({ hidden: false })
+ const data = teachersSorted(teachers).map(encodePerson)
+
+ if (data) {
+ res.json({
+ items: data,
+ })
+ } else {
+ res.status(404)
+ res.json({
+ error: `Article ${id} not found`
+ })
+ }
+}
diff --git a/pages/api/schedule.js b/pages/api/schedule.js
new file mode 100644
index 00000000..ef596840
--- /dev/null
+++ b/pages/api/schedule.js
@@ -0,0 +1,20 @@
+import { dbUri } from '../../src/config'
+import { connect } from '../../src/core/db'
+import { findSchedule } from '../../src/core/schedule'
+
+export default async (req, res) => {
+ await connect(dbUri)
+
+ const period = req.query.period
+ const semester = req.query.semester
+ const data = await findSchedule(period, semester)
+
+ if (data) {
+ res.json(data)
+ } else {
+ res.status(404)
+ res.json({
+ error: `Schedule ${period}:${semester} not found`
+ })
+ }
+}
diff --git a/pages/article/[article].jsx b/pages/article/[article].jsx
new file mode 100644
index 00000000..897f80f7
--- /dev/null
+++ b/pages/article/[article].jsx
@@ -0,0 +1,43 @@
+import React from 'react'
+import axios from 'axios'
+import App from '../../src/components/App'
+import Article from '../../src/components/Article'
+import Html from '../../src/components/Html'
+import menuModel from '../../src/models/menu'
+import { buildMenu } from '../../src/lib/menu'
+
+const Page = (props) => (
+
+
+
+)
+
+Page.getInitialProps = async (ctx) => {
+ const pageUrl = ctx.req.url
+ const id = ctx.query.article
+ const apiUrl = `http://localhost:3000/api/articles/${id}`
+ const res = await axios.get(apiUrl)
+ const article = res.data
+
+ return {
+ article,
+ pageUrl,
+ }
+}
+
+export default Page
\ No newline at end of file
diff --git a/pages/articles/[page].jsx b/pages/articles/[page].jsx
new file mode 100644
index 00000000..7cb685be
--- /dev/null
+++ b/pages/articles/[page].jsx
@@ -0,0 +1,52 @@
+import React from 'react'
+import axios from 'axios'
+import App from '../../src/components/App'
+import ArticleCardList from '../../src/components/ArticleCardList'
+import menuModel from '../../src/models/menu'
+import { buildMenu } from '../../src/lib/menu'
+
+function getMeta(article) {
+ return {
+ title: article.title,
+ }
+}
+
+// async function renderHome(path, pageSize) {
+// return render(path, Component, getMeta({ title: 'Шлиссельбургская ДХШ' }), { showAuthor: true })
+// }
+
+const Page = (props) => (
+
+
+
+)
+
+Page.getInitialProps = async (ctx) => {
+ const pageUrl = ctx.req.url
+ const page = parseInt(ctx.query.page)
+ const pageSize = 10
+ const apiUrl = `http://localhost:3000/api/articles?page=${page}&pageSize=${pageSize}`
+ const res = await axios.get(apiUrl)
+ const articles = res.data.items
+ const nextPage = res.data.nextPage
+ const prevPage = res.data.prevPage
+
+ return {
+ articles,
+ nextPage,
+ prevPage,
+ pageUrl,
+ }
+}
+
+export default Page
\ No newline at end of file
diff --git a/pages/collective.jsx b/pages/collective.jsx
new file mode 100644
index 00000000..2d4f75e4
--- /dev/null
+++ b/pages/collective.jsx
@@ -0,0 +1,64 @@
+import React from 'react'
+import axios from 'axios'
+import App from '../src/components/App'
+import CollectiveImage from '../src/components/CollectiveImage'
+import PersonCard from '../src/components/PersonCard'
+import menuModel from '../src/models/menu'
+import { buildMenu } from '../src/lib/menu'
+
+function getMeta(article) {
+ return {
+ title: article.title,
+ }
+}
+
+const PersonCardList = ({ children }) => (
+
+ {children}
+
+)
+
+const Page = (props) => (
+
+
+ {!props.image ? null : (
+
+ )}
+
+
+ {props.persons.map((person, index) => (
+
+ ))}
+
+
+
+)
+
+Page.getInitialProps = async (ctx) => {
+ const pageUrl = ctx.req.url
+ const apiUrl = `http://localhost:3000/api/persons`
+ const res = await axios.get(apiUrl)
+ const persons = res.data.items
+
+ const imageFile = 'Images/HudozkaCollective2017.jpg'
+ const imageUrl = `http://localhost:3000/api/image?file=${imageFile}`
+ const resImage = await axios.get(imageUrl)
+
+ return {
+ persons,
+ image: resImage.data,
+ pageUrl,
+ }
+}
+
+export default Page
\ No newline at end of file
diff --git a/pages/document/[document].jsx b/pages/document/[document].jsx
new file mode 100644
index 00000000..bc53f65d
--- /dev/null
+++ b/pages/document/[document].jsx
@@ -0,0 +1,35 @@
+import React from 'react'
+import axios from 'axios'
+import App from '../../src/components/App'
+import Document from '../../src/components/Document'
+import Share from '../../src/components/Share'
+import menuModel from '../../src/models/menu'
+import { buildMenu } from '../../src/lib/menu'
+
+const Page = (props) => (
+
+
+
+
+
+
+)
+
+Page.getInitialProps = async (ctx) => {
+ const pageUrl = ctx.req.url
+ const id = ctx.query.document
+ const apiUrl = `http://localhost:3000/api/files/${id}`
+ const res = await axios.get(apiUrl)
+ const file = res.data
+
+ return {
+ file,
+ pageUrl,
+ }
+}
+
+export default Page
\ No newline at end of file
diff --git a/pages/documents.jsx b/pages/documents.jsx
new file mode 100644
index 00000000..80a79b0b
--- /dev/null
+++ b/pages/documents.jsx
@@ -0,0 +1,135 @@
+import React from 'react'
+import axios from 'axios'
+import App from '../src/components/App'
+import menuModel from '../src/models/menu'
+import { buildMenu } from '../src/lib/menu'
+
+import DocumentList from '../src/components/DocumentList'
+import ImageArtifactType from '../src/core/ImageArtifactType'
+import { prioritySort } from '../src/lib/sort'
+import { splitBy } from '../src/lib/array'
+import { unique } from '../src/utils/common'
+
+function getDocumentsMeta() {
+ return {
+ title: 'Документы',
+ description: 'Документы Шлиссельбургской ДХШ',
+ }
+}
+
+function getMeta(teacher) {
+ return {
+ title: teacher.name,
+ description: teacher.name,
+ }
+}
+
+function getSorted(documents) {
+ const compose = (...fns) => value => fns
+ .map(fn => fn)
+ .reverse()
+ .reduce((acc, fn) => fn(acc), value)
+
+ const pass = fn => value => {
+ fn(value)
+ return value
+ }
+
+ const subtract = (a, b) => a - b
+
+ const uniqueCategories = unique(i => i.category)
+
+ const priority = {
+ 'Основные документы': [
+ 'https://static.shlisselburg.org/art/uploads/ustav-2015.pdf',
+ 'https://static.shlisselburg.org/art/uploads/obrazovatelnaia-litsenziia-2015.pdf',
+ 'https://static.shlisselburg.org/art/uploads/svidetelstvo-na-pomeshchenie.pdf',
+ 'https://static.shlisselburg.org/art/uploads/egriul.pdf',
+ 'https://static.shlisselburg.org/art/uploads/inn.pdf',
+ 'https://static.shlisselburg.org/art/uploads/reshenie-o-sozdanii-shkoly.pdf',
+ 'https://static.shlisselburg.org/art/uploads/kopiia-resheniia-o-naznachenii-rukovoditelia.pdf',
+ 'https://static.shlisselburg.org/art/uploads/postanovlenie-o-sozdanii-munitsipalnogo-obrazovatelnogo-uchrezhdeniia-kultury-detskaia-khudozhestvennaia-shkola.pdf',
+ ],
+ 'Учебные программы': [
+ 'https://static.shlisselburg.org/art/uploads/uchebnaia-programma-zhivopis.pdf',
+ ]
+ }
+
+ const CATEGORY_PRIORITY = [
+ 'Основные документы',
+ 'Планы ФХД',
+ 'Самообследование деятельности',
+ 'Инструкции',
+ 'Образование',
+ 'Учебные программы',
+ 'Платные образовательные услуги',
+ 'Дополнительные общеразвивающие программы',
+ 'Документы для поступления',
+ ]
+
+ const sortBy = fn => (a, b) => [a, b]
+ .map(fn)
+ .reduce(subtract)
+
+ const getPriorityFn = (m, list) => value => list.includes(value)
+ ? list.indexOf(value)
+ : m
+
+ const safeSelect = (d, store, key) => key in store
+ ? store[key]
+ : d
+
+ const categoryPriority = getPriorityFn(10000, CATEGORY_PRIORITY)
+
+ const documentPriority = ({ category, fileUrl }) => compose(
+ getPriorityFn.bind(null, 10000),
+ safeSelect.bind(null, [], priority)
+ )(category)(fileUrl)
+
+ const documentsOf = category => documents.filter(i => i.category === category)
+ const sorted = documents => documents.sort(sortBy(documentPriority))
+ const collectDocumentsByCategory = compose(sorted, documentsOf)
+
+ return uniqueCategories(documents)
+ .sort(sortBy(categoryPriority))
+ .reduce((acc, name) => [...acc, {
+ name,
+ items: collectDocumentsByCategory(name)
+ }], [])
+}
+
+const Page = (props) => (
+
+
+ {/*
{JSON.stringify(props, null, 4)} */}
+
+ {props.collections.map(({ name, items }, index) => (
+
+ ))}
+
+
+)
+
+Page.getInitialProps = async (ctx) => {
+ const pageUrl = ctx.req.url
+ const apiUrl = `http://localhost:3000/api/files`
+ const res = await axios.get(apiUrl)
+ const files = res.data.items
+
+ const collections = getSorted(files)
+
+ return {
+ collections,
+ pageUrl,
+ }
+}
+
+export default Page
\ No newline at end of file
diff --git a/pages/gallery.jsx b/pages/gallery.jsx
new file mode 100644
index 00000000..3dd84b73
--- /dev/null
+++ b/pages/gallery.jsx
@@ -0,0 +1,90 @@
+import React from 'react'
+import axios from 'axios'
+import App from '../src/components/App'
+// import Album from '../src/components/Album'
+import Article from '../src/components/Article'
+import menuModel from '../src/models/menu'
+import { buildMenu } from '../src/lib/menu'
+import { splitBy } from '../src/lib/array'
+
+const albumsByYear = splitBy(album => new Date(album.date).getFullYear())
+
+function getMeta() {
+ return {
+ title: 'Галерея',
+ description: 'Галерея работ учащихся Шлиссельбургской Детской Художественной Школы'
+ }
+}
+
+const m = 1
+const AlbumImage = ({ data, alt }) => (
+
+
`${url} ${density}x`)}
+ />
+
+)
+
+const GItem = ({ album }) => (
+
+)
+
+const ACollection = ({ title, albums }) => (
+
+
{title}
+
{
+ albums.map((album, index) => (
+
+ ))
+ }
+
+)
+
+
+const Page = (props) => (
+
+
+
+ {props.collections.map(([year, albums], index) => (
+
+ ))
+ }
+
+
+
+)
+
+Page.getInitialProps = async (ctx) => {
+ const pageUrl = ctx.req.url
+ const apiUrl = `http://localhost:3000/api/albums`
+ const res = await axios.get(apiUrl)
+ const items = res.data.items
+ const albumCollections = albumsByYear(items)
+
+ return {
+ collections: [...albumCollections.entries()],
+ pageUrl,
+ }
+}
+
+export default Page
\ No newline at end of file
diff --git a/pages/index.jsx b/pages/index.jsx
new file mode 100644
index 00000000..bdaf7802
--- /dev/null
+++ b/pages/index.jsx
@@ -0,0 +1,55 @@
+import React from 'react'
+import axios from 'axios'
+import App from '../src/components/App'
+import ArticleCardList from '../src/components/ArticleCardList'
+import HudozkaTitle from '../src/components/HudozkaTitle'
+import menuModel from '../src/models/menu'
+import { buildMenu } from '../src/lib/menu'
+
+function getMeta(article) {
+ return {
+ title: article.title,
+ }
+}
+
+// async function renderHome(path, pageSize) {
+// return render(path, Component, getMeta({ title: 'Шлиссельбургская ДХШ' }), { showAuthor: true })
+// }
+
+const Page = (props) => (
+
+
+
+)
+
+Page.getInitialProps = async (ctx) => {
+ const pageUrl = ctx.req.url
+ const page = 1
+ const pageSize = 10
+ const apiUrl = `http://localhost:3000/api/articles?page=${page}&pageSize=${pageSize}`
+ const res = await axios.get(apiUrl)
+ const articles = res.data.items
+ const nextPage = res.data.nextPage
+ const prevPage = res.data.prevPage
+
+ return {
+ articles,
+ nextPage,
+ prevPage,
+ pageUrl,
+ }
+}
+
+export default Page
\ No newline at end of file
diff --git a/pages/next.jsx b/pages/next.jsx
new file mode 100644
index 00000000..9e320461
--- /dev/null
+++ b/pages/next.jsx
@@ -0,0 +1,38 @@
+import React from 'react'
+import axios from 'axios'
+import App from '../src/components/App'
+import Page from '../src/components/Page'
+import menuModel from '../src/models/menu'
+import { buildMenu } from '../src/lib/menu'
+
+const Index = (props) => (
+
+ {/* {JSON.stringify(props, null, 4)} */}
+
+
+)
+
+Index.getInitialProps = async (ctx) => {
+ const pageUrl = ctx.req.url
+ // // const pageUrl = '/neighbors/2018'
+ const apiUrl = `http://localhost:3000/api/page?page=${pageUrl}`
+ const res = await axios.get(apiUrl)
+ const page = res.data
+
+ return {
+ content: page.data,
+ pageUrl,
+ }
+}
+
+export default Index
\ No newline at end of file
diff --git a/pages/schedule.jsx b/pages/schedule.jsx
new file mode 100644
index 00000000..df94c351
--- /dev/null
+++ b/pages/schedule.jsx
@@ -0,0 +1,39 @@
+import React from 'react'
+import axios from 'axios'
+import App from '../src/components/App'
+import Schedule from '../src/components/Schedule'
+import Share from '../src/components/Share'
+import menuModel from '../src/models/menu'
+import { buildMenu } from '../src/lib/menu'
+
+const Page = (props) => (
+
+
+ {/**/}
+
+
+
+
+
+
+)
+
+Page.getInitialProps = async (ctx) => {
+ const pageUrl = ctx.req.url
+ const period = '2016-2017'
+ const semester = 'spring'
+ const apiUrl = `http://localhost:3000/api/schedule?period=${period}&semester=${semester}`
+ const res = await axios.get(apiUrl)
+ const schedule = res.data
+
+ return {
+ schedule,
+ pageUrl,
+ }
+}
+
+export default Page
\ No newline at end of file
diff --git a/pages/teacher/[person].jsx b/pages/teacher/[person].jsx
new file mode 100644
index 00000000..3bf95cc5
--- /dev/null
+++ b/pages/teacher/[person].jsx
@@ -0,0 +1,35 @@
+import React from 'react'
+import axios from 'axios'
+import App from '../../src/components/App'
+import Page from '../../src/components/Page'
+import menuModel from '../../src/models/menu'
+import { buildMenu } from '../../src/lib/menu'
+
+const Index = (props) => (
+
+
+
+ {props.person.post}
+
+
+
+)
+
+Index.getInitialProps = async (ctx) => {
+ const pageUrl = ctx.req.url
+ const id = ctx.query.person
+ const apiUrl = `http://localhost:3000/api/persons/${id}`
+ const res = await axios.get(apiUrl)
+ const person = res.data
+
+ return {
+ pageUrl,
+ person,
+ }
+}
+
+export default Index
\ No newline at end of file
diff --git a/src/api/articles.js b/src/api/articles.js
new file mode 100644
index 00000000..88ebf709
--- /dev/null
+++ b/src/api/articles.js
@@ -0,0 +1,62 @@
+import Article from '../core/Article'
+import ImageArtifactType from '../core/ImageArtifactType'
+import { sortBy } from '../utils/sort'
+import { timestamp } from '../lib/date'
+
+export const sortArticleByDate = sortBy(
+ x => timestamp(new Date(x.date))
+)
+
+export async function findArticlesNin(nin, skip, limit, sort) {
+ const query = {
+ _id: { $nin: nin }
+ }
+
+ return Article.find(query, {
+ sort,
+ skip,
+ limit,
+ })
+}
+
+export async function findArticles(page, pageSize) {
+ const limit = pageSize
+ const skip = (page - 1) * pageSize
+
+ const pinnedArticles = page === 1
+ ? await Article.findPinned()
+ : []
+
+ const total = await Article.total()
+ const totalPages = total / pageSize
+
+ const id = i => i._id
+ const pinnedIds = pinnedArticles.map(id)
+ const articles = await findArticlesNin(pinnedIds, skip, limit, { date: -1 })
+
+ const prevPage = page > 1
+ ? page - 1
+ : null
+
+ const nextPage = page < totalPages
+ ? page + 1
+ : null
+
+ const items = [
+ ...pinnedArticles.sort(sortArticleByDate),
+ ...articles
+ ]
+ .map(x => x.plain())
+ .map(x => ({
+ ...x,
+ preview: !x.preview ? null : (
+ x.preview.getPicture(ImageArtifactType.MEDIUM)
+ )
+ }))
+
+ return {
+ items,
+ prevPage,
+ nextPage,
+ }
+}
\ No newline at end of file
diff --git a/src/api/files.js b/src/api/files.js
new file mode 100644
index 00000000..1866de43
--- /dev/null
+++ b/src/api/files.js
@@ -0,0 +1,36 @@
+import ImageArtifactType from '../core/ImageArtifactType'
+
+const sizes = [
+ ImageArtifactType.MEDIUM,
+ ImageArtifactType.BIG,
+ ImageArtifactType.ORIGIN,
+]
+
+export function encodeFilePreview(file, sizes) {
+ const preview = file.preview
+ if (!preview) return null
+
+ const image = preview.findArtifact(sizes)
+ if (!image) return null
+
+ return image.url
+}
+
+export function encodeFile(file) {
+ const imageUrl = encodeFilePreview(file, sizes)
+ const category = (file.category || '')
+ .replace('Documents/', '')
+ .replace('Pages/', '')
+ .replace('Albums/', '')
+ .replace('Articles /', '')
+
+ return {
+ imageUrl,
+ category,
+ title: file.title,
+ fileName: file.fileInfo.name,
+ fileSize: file.fileInfo.size,
+ fileUrl: file.url,
+ url: file.viewUrl,
+ }
+}
diff --git a/src/api/pages.js b/src/api/pages.js
new file mode 100644
index 00000000..58fc21d9
--- /dev/null
+++ b/src/api/pages.js
@@ -0,0 +1,29 @@
+const { get } = require('koa-route')
+const getPathWithNoTrailingSlash = require('../lib/url').getPathWithNoTrailingSlash
+
+const Page = require('../core/Page')
+
+function getPage() {
+ return get('/api/pages/*', async ctx => {
+ const path = getPathWithNoTrailingSlash(ctx.path)
+ const pagePath = path.replace('/api/pages', '')
+
+ const resource = await Page.findByUrl(pagePath)
+ if (!resource) {
+ ctx.status = 404
+ ctx.body = {
+ error: 'not found'
+ }
+ } else {
+ ctx.body = {
+ id: resource.id,
+ title: resource.title,
+ url: resource.url,
+ data: resource.data,
+ preview: resource.preview,
+ }
+ }
+ })
+}
+
+exports.getPage = getPage
diff --git a/src/api/persons.js b/src/api/persons.js
new file mode 100644
index 00000000..e04b1155
--- /dev/null
+++ b/src/api/persons.js
@@ -0,0 +1,11 @@
+import ImageArtifactType from '../core/ImageArtifactType'
+const profilePicture = profile => profile.picture.getPicture(ImageArtifactType.BIG)
+
+export function encodePerson(person) {
+ return {
+ ...person,
+ shortName: person.shortName(),
+ name: person.splitName(),
+ picture: profilePicture(person),
+ }
+}
\ No newline at end of file
diff --git a/src/components/App.js b/src/components/App.js
index b990e38e..2d669ae8 100644
--- a/src/components/App.js
+++ b/src/components/App.js
@@ -3,6 +3,8 @@ const Menu = require('./Menu')
const Footer = require('./Footer')
const Comments = require('./Comments')
+import '../style/style.scss'
+
const App = ({children, menu, showAuthor, menuPadding}) => (
+ )
+}
diff --git a/src/core/Data.js b/src/core/Data.js
index 5f84f721..70388deb 100644
--- a/src/core/Data.js
+++ b/src/core/Data.js
@@ -1,13 +1,19 @@
+const db = require('./db')
+
const store = new Map()
class Data {
- static setStore(Class, collection) {
- store.set(Class, collection)
- }
+ static setStore(Class, collection) {
+ store.set(Class, collection)
+ }
- static getStore(Class) {
- return store.get(Class)
- }
+ static getStore(Class) {
+ return store.get(Class)
+ }
+
+ static getCollection(name) {
+ return db.collection(name)
+ }
}
module.exports = Data
diff --git a/src/core/db.js b/src/core/db.js
index b3a6e123..e0022efb 100644
--- a/src/core/db.js
+++ b/src/core/db.js
@@ -7,37 +7,42 @@ const Document = require('./Document')
const Image = require('./Image')
const Settings = require('./Config')
-const {MongoClient, ObjectId} = require('mongodb')
+const { MongoClient, ObjectId } = require('mongodb')
-export var db
+var db
-export async function connect(uri) {
- const c = await MongoClient.connect(uri)
- db = init(c)
- return db
+async function connect(uri) {
+ const connection = await MongoClient.connect(uri)
+ db = init(connection)
+ return db
}
-export function collection(name) {
- return db.collection(name)
+function collection(name) {
+ return db.collection(name)
}
-export const c = collection
-
-export function id(i) {
- if (typeof i === 'string') return ObjectId(i)
- else if (i instanceof ObjectId) return i
- else if (i instanceof Object) return '_id' in i ? ObjectId(i._id) : null
- return null
+function id(i) {
+ if (typeof i === 'string') return ObjectId(i)
+ else if (i instanceof ObjectId) return i
+ else if (i instanceof Object) return '_id' in i ? ObjectId(i._id) : null
+ return null
}
function init(db) {
- Data.setStore(Page, db.collection('pages'))
- Data.setStore(Article, db.collection('articles'))
- Data.setStore(Album, db.collection('albums'))
- Data.setStore(Image, db.collection('images'))
- Data.setStore(Teacher, db.collection('collective'))
- Data.setStore(Document, db.collection('documents'))
- Data.setStore(Settings, db.collection('settings'))
+ // Data.setStore('Page', db.collection('pages'))
+ Data.setStore(Page, db.collection('pages'))
+ Data.setStore(Article, db.collection('articles'))
+ Data.setStore(Album, db.collection('albums'))
+ Data.setStore(Image, db.collection('images'))
+ Data.setStore(Teacher, db.collection('collective'))
+ Data.setStore(Document, db.collection('documents'))
+ Data.setStore(Settings, db.collection('settings'))
- return db
+ return db
}
+
+exports.getDb = () => db
+exports.connect = connect
+exports.collection = collection
+exports.c = collection
+exports.id = id
\ No newline at end of file
diff --git a/src/lib/component.js b/src/lib/component.js
index 3be95f64..6da5df89 100644
--- a/src/lib/component.js
+++ b/src/lib/component.js
@@ -1,8 +1,7 @@
import React from 'react'
import {renderToStaticMarkup} from 'react-dom/server'
-const App = require('../components/App')
-const Html = require('../components/Html')
+import App from '../components/App'
function renderApp({component, ...options}) {
const app = (
@@ -13,13 +12,4 @@ function renderApp({component, ...options}) {
return renderToStaticMarkup(app)
}
-function getHtml(html) {
- return (
-