app moved to next.js
This commit is contained in:
1 parent
dcca513aea
commit
43af2996bf
48 files changed
+1147
-1027
No files matched your search
+5
-5
@@ -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"
|
||||
|
||||
@@ -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 (
|
||||
<Html>
|
||||
<Head>
|
||||
<style>{`body { margin: 0 } /* custom! */`}</style>
|
||||
|
||||
<script src='/static/likely.js'></script>
|
||||
<link href='/static/likely.css' rel='stylesheet' />
|
||||
</Head>
|
||||
|
||||
<body className="custom_class">
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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) => (
|
||||
<App
|
||||
menu={buildMenu(props.pageUrl, menuModel)}
|
||||
showAuthor={true}
|
||||
menuPadding={true}
|
||||
>
|
||||
<div className="content content_thin">
|
||||
<Article
|
||||
title={props.album.title}
|
||||
date={props.album.date}
|
||||
shareable={true}
|
||||
>
|
||||
<Html
|
||||
html={props.album.post}
|
||||
/>
|
||||
</Article>
|
||||
</div>
|
||||
</App>
|
||||
)
|
||||
|
||||
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
|
||||
@@ -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`
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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`
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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`
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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`
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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`
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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`
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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`
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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`
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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`
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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`
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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`
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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) => (
|
||||
<App
|
||||
menu={buildMenu(props.pageUrl, menuModel)}
|
||||
showAuthor={true}
|
||||
menuPadding={true}
|
||||
>
|
||||
<div className={'content content_thin'}>
|
||||
<Article
|
||||
title={props.article.title}
|
||||
date={props.article.date}
|
||||
tags={props.article.tags}
|
||||
shareable={true}
|
||||
>
|
||||
<Html
|
||||
html={props.article.post}
|
||||
/>
|
||||
</Article>
|
||||
</div>
|
||||
</App>
|
||||
)
|
||||
|
||||
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
|
||||
@@ -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) => (
|
||||
<App
|
||||
menu={buildMenu(props.pageUrl, menuModel)}
|
||||
showAuthor={true}
|
||||
menuPadding={true}
|
||||
>
|
||||
<div className="content content_wide">
|
||||
<ArticleCardList
|
||||
articles={props.articles}
|
||||
prevPage={props.prevPage}
|
||||
nextPage={props.nextPage}
|
||||
/>
|
||||
</div>
|
||||
</App>
|
||||
)
|
||||
|
||||
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
|
||||
@@ -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 }) => (
|
||||
<div className="PersonCardList">
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
|
||||
const Page = (props) => (
|
||||
<App
|
||||
menu={buildMenu(props.pageUrl, menuModel)}
|
||||
showAuthor={true}
|
||||
menuPadding={true}
|
||||
>
|
||||
<div className="content content_semi-wide">
|
||||
{!props.image ? null : (
|
||||
<CollectiveImage data={props.image} />
|
||||
)}
|
||||
|
||||
<PersonCardList>
|
||||
{props.persons.map((person, index) => (
|
||||
<PersonCard
|
||||
key={index}
|
||||
profile={person}
|
||||
picture={person.picture}
|
||||
url={person.url}
|
||||
name={person.name}
|
||||
/>
|
||||
))}
|
||||
</PersonCardList>
|
||||
</div>
|
||||
</App>
|
||||
)
|
||||
|
||||
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
|
||||
@@ -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) => (
|
||||
<App
|
||||
menu={buildMenu(props.pageUrl, menuModel)}
|
||||
showAuthor={true}
|
||||
menuPadding={true}
|
||||
>
|
||||
<div className="content content_wide">
|
||||
<Document {...props.file} />
|
||||
<Share />
|
||||
</div>
|
||||
</App>
|
||||
)
|
||||
|
||||
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
|
||||
@@ -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) => (
|
||||
<App
|
||||
menu={buildMenu(props.pageUrl, menuModel)}
|
||||
showAuthor={true}
|
||||
menuPadding={true}
|
||||
>
|
||||
<div className="content content_thin">
|
||||
{/* <pre>{JSON.stringify(props, null, 4)}</pre> */}
|
||||
|
||||
{props.collections.map(({ name, items }, index) => (
|
||||
<DocumentList
|
||||
key={index}
|
||||
name={name}
|
||||
documents={items}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</App>
|
||||
)
|
||||
|
||||
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
|
||||
@@ -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 }) => (
|
||||
<picture>
|
||||
<img
|
||||
className="opa"
|
||||
alt={alt}
|
||||
src={data.src}
|
||||
width={data.width * m}
|
||||
height={data.height * m}
|
||||
srcSet={(data.set || []).map(({ url, density }) => `${url} ${density}x`)}
|
||||
/>
|
||||
</picture>
|
||||
)
|
||||
|
||||
const GItem = ({ album }) => (
|
||||
<div className="gallery-item">
|
||||
<a className="invisible" href={album.url}>
|
||||
<AlbumImage data={album.preview} alt={album.title} />
|
||||
</a>
|
||||
</div>
|
||||
)
|
||||
|
||||
const ACollection = ({ title, albums }) => (
|
||||
<div className="album-collection">
|
||||
<div className="album-collection__title">{title}</div>
|
||||
<div className="album-collection__body">{
|
||||
albums.map((album, index) => (
|
||||
<GItem key={index} album={album} />
|
||||
))
|
||||
}</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
|
||||
const Page = (props) => (
|
||||
<App
|
||||
menu={buildMenu(props.pageUrl, menuModel)}
|
||||
showAuthor={true}
|
||||
menuPadding={true}
|
||||
>
|
||||
<div className="content content_semi-wide">
|
||||
<Article
|
||||
// title={meta.title}
|
||||
title={'Галерея'}
|
||||
>
|
||||
{props.collections.map(([year, albums], index) => (
|
||||
<ACollection
|
||||
key={index}
|
||||
title={year}
|
||||
albums={albums}
|
||||
/>
|
||||
))
|
||||
}
|
||||
</Article>
|
||||
</div>
|
||||
</App>
|
||||
)
|
||||
|
||||
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
|
||||
@@ -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) => (
|
||||
<App
|
||||
menu={buildMenu(props.pageUrl, menuModel)}
|
||||
showAuthor={true}
|
||||
menuPadding={true}
|
||||
>
|
||||
<div className="content content_wide">
|
||||
<HudozkaTitle />
|
||||
|
||||
<ArticleCardList
|
||||
articles={props.articles}
|
||||
prevPage={props.prevPage}
|
||||
nextPage={props.nextPage}
|
||||
/>
|
||||
</div>
|
||||
</App>
|
||||
)
|
||||
|
||||
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
|
||||
@@ -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) => (
|
||||
<App
|
||||
menu={buildMenu(props.pageUrl, menuModel)}
|
||||
showAuthor={true}
|
||||
menuPadding={true}
|
||||
>
|
||||
{/* <pre>{JSON.stringify(props, null, 4)}</pre> */}
|
||||
<div className={'content content_thin'}>
|
||||
<Page
|
||||
shareable={true}
|
||||
>
|
||||
{props.content}
|
||||
</Page>
|
||||
</div>
|
||||
</App>
|
||||
)
|
||||
|
||||
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
|
||||
@@ -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) => (
|
||||
<App
|
||||
menu={buildMenu(props.pageUrl, menuModel)}
|
||||
showAuthor={true}
|
||||
menuPadding={true}
|
||||
>
|
||||
<div className="content content_wide">
|
||||
{/*<ScheduleList schedules={schedules}/>*/}
|
||||
|
||||
<Schedule {...props.schedule} />
|
||||
|
||||
<Share />
|
||||
</div>
|
||||
</App>
|
||||
)
|
||||
|
||||
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
|
||||
@@ -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) => (
|
||||
<App
|
||||
menu={buildMenu(props.pageUrl, menuModel)}
|
||||
showAuthor={true}
|
||||
menuPadding={true}
|
||||
>
|
||||
<div className="content content_thin">
|
||||
<Page shareable={true}>
|
||||
{props.person.post}
|
||||
</Page>
|
||||
</div>
|
||||
</App>
|
||||
)
|
||||
|
||||
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
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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),
|
||||
}
|
||||
}
|
||||
@@ -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}) => (
|
||||
<div className="body-wrapper theme-default">
|
||||
<header>
|
||||
|
||||
+17
-15
@@ -1,17 +1,19 @@
|
||||
const React = require('react')
|
||||
const Share = require('./Share')
|
||||
const getHtml = require('../lib/component').getHtml
|
||||
import React from 'react'
|
||||
import Share from './Share'
|
||||
import Html from './Html'
|
||||
|
||||
const Page = ({children, shareable}) => (
|
||||
<div className="Article Article--cloud">
|
||||
<div className="Article-Body">
|
||||
{getHtml(children)}
|
||||
</div>
|
||||
export default function Page({ children, shareable }) {
|
||||
return (
|
||||
<div className={'Article Article--cloud'}>
|
||||
<div className={'Article-Body'}>
|
||||
<Html
|
||||
html={children}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{!shareable ? null : (
|
||||
<Share/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
|
||||
module.exports = Page
|
||||
{!shareable ? null : (
|
||||
<Share />
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
+12
-6
@@ -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
|
||||
+28
-23
@@ -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
|
||||
+1
-11
@@ -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 (
|
||||
<Html
|
||||
html={html}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
exports.renderApp = renderApp
|
||||
exports.getHtml = getHtml
|
||||
+9
-5
@@ -1,8 +1,10 @@
|
||||
const {readFile} = require('async-file')
|
||||
import React from 'react'
|
||||
import Html from '../components/Html'
|
||||
|
||||
const { readFile } = require('async-file')
|
||||
const handlebars = require('handlebars')
|
||||
|
||||
const renderApp = require('../lib/component').renderApp
|
||||
const getHtml = require('../lib/component').getHtml
|
||||
|
||||
const menuModel = require('../models/menu').default
|
||||
const buildMenu = require('./menu').buildMenu
|
||||
@@ -32,9 +34,11 @@ const isHtml = data => typeof data === 'string'
|
||||
async function render(path, data, meta, options = {}) {
|
||||
const renderOptions = {...defaultOptions, ...options}
|
||||
|
||||
const component = isHtml(data)
|
||||
? getHtml(data)
|
||||
: data
|
||||
const component = !isHtml(data) ? data : (
|
||||
<Html
|
||||
html={data}
|
||||
/>
|
||||
)
|
||||
|
||||
const menu = buildMenu(path, menuModel)
|
||||
const content = renderApp({...renderOptions, menu, component})
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
const React = require('react')
|
||||
const Article = require('../components/Article')
|
||||
const Album = require('../core/Album')
|
||||
const {render} = require('../lib/render')
|
||||
const getHtml = require('../lib/component').getHtml
|
||||
|
||||
function getMeta(album) {
|
||||
return {
|
||||
title: album.title,
|
||||
description: album.title,
|
||||
}
|
||||
}
|
||||
|
||||
async function renderAlbum(id) {
|
||||
const album = await Album.findById(id)
|
||||
|
||||
if (!album) return null
|
||||
|
||||
const Component = (
|
||||
<div className="content content_thin">
|
||||
<Article
|
||||
title={album.title}
|
||||
date={album.date}
|
||||
shareable={true}
|
||||
>
|
||||
{getHtml(album.post)}
|
||||
</Article>
|
||||
</div>
|
||||
)
|
||||
|
||||
return render(album.url, Component, getMeta(album), {commentsEnabled: true, menuPadding: true})
|
||||
}
|
||||
|
||||
exports.renderAlbum = renderAlbum
|
||||
@@ -1,131 +0,0 @@
|
||||
const React = require('react')
|
||||
const Article = require('../core/Article')
|
||||
const ArticleComponent = require('../components/Article')
|
||||
const ArticleCardList = require('../components/ArticleCardList')
|
||||
const {render} = require('../lib/render')
|
||||
const timestamp = require('../lib/date').timestamp
|
||||
const ImageArtifactType = require('../core/ImageArtifactType')
|
||||
const {sortBy} = require('../utils/sort')
|
||||
const getHtml = require('../lib/component').getHtml
|
||||
|
||||
const sortArticleByDate = sortBy(
|
||||
x => timestamp(new Date(x.date))
|
||||
)
|
||||
|
||||
function getMeta(article) {
|
||||
const types = [
|
||||
ImageArtifactType.FACEBOOK,
|
||||
ImageArtifactType.MEDIUM,
|
||||
ImageArtifactType.BIG,
|
||||
ImageArtifactType.ORIGIN,
|
||||
]
|
||||
const meta = {
|
||||
title: article.title,
|
||||
}
|
||||
|
||||
if (article.preview) {
|
||||
try {
|
||||
const artifact = article.preview.findArtifact(types)
|
||||
meta.image = artifact.url
|
||||
meta.imageWidth = artifact.width
|
||||
meta.imageHeight = artifact.height
|
||||
} catch (error) {
|
||||
meta.image = 'https://art.shlisselburg.org/entrance.jpg'
|
||||
meta.imageWidth = 1200
|
||||
meta.imageHeight = 630
|
||||
}
|
||||
}
|
||||
return meta
|
||||
}
|
||||
|
||||
async function findArticlesNin(nin, skip, limit, sort) {
|
||||
const query = {
|
||||
_id: {$nin: nin}
|
||||
}
|
||||
|
||||
return Article.find(query, {
|
||||
sort,
|
||||
skip,
|
||||
limit,
|
||||
})
|
||||
}
|
||||
|
||||
async function createArticleCardList(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 content = [
|
||||
...pinnedArticles.sort(sortArticleByDate),
|
||||
...articles
|
||||
]
|
||||
.map(x => x.plain())
|
||||
.map(x => ({
|
||||
...x,
|
||||
preview: !x.preview ? null : (
|
||||
x.preview.getPicture(ImageArtifactType.MEDIUM)
|
||||
)
|
||||
}))
|
||||
|
||||
return (
|
||||
<ArticleCardList
|
||||
articles={content}
|
||||
prevPage={prevPage}
|
||||
nextPage={nextPage}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
async function renderArticles(path, page, pageSize) {
|
||||
const articles = await createArticleCardList(page, pageSize)
|
||||
|
||||
const Component = (
|
||||
<div className="content content_wide">
|
||||
{articles}
|
||||
</div>
|
||||
)
|
||||
|
||||
return render(path, Component, getMeta({title: `Статьи`}))
|
||||
}
|
||||
|
||||
async function renderArticle(id) {
|
||||
const article = await Article.findById(id)
|
||||
if (!article) return null
|
||||
|
||||
const Component = (
|
||||
<div className="content content_thin">
|
||||
<ArticleComponent
|
||||
title={article.title}
|
||||
date={article.date}
|
||||
tags={article.tags}
|
||||
shareable={true}
|
||||
>
|
||||
{getHtml(article.post)}
|
||||
</ArticleComponent>
|
||||
</div>
|
||||
)
|
||||
|
||||
return render(article.url, Component, getMeta(article), {commentsEnabled: true, menuPadding: true})
|
||||
}
|
||||
|
||||
exports.createArticleCardList = createArticleCardList
|
||||
exports.renderArticles = renderArticles
|
||||
exports.renderArticle = renderArticle
|
||||
@@ -1,26 +0,0 @@
|
||||
const React = require('react')
|
||||
const HudozkaTitle = require('../components/HudozkaTitle')
|
||||
const {createArticleCardList} = require('../render/articles')
|
||||
const {render} = require('../lib/render')
|
||||
|
||||
function getMeta(article) {
|
||||
return {
|
||||
title: article.title,
|
||||
}
|
||||
}
|
||||
|
||||
async function renderHome(path, pageSize) {
|
||||
const articles = await createArticleCardList(1, pageSize)
|
||||
|
||||
const Component = (
|
||||
<div className="content content_wide">
|
||||
<HudozkaTitle/>
|
||||
|
||||
{articles}
|
||||
</div>
|
||||
)
|
||||
|
||||
return render(path, Component, getMeta({title: 'Шлиссельбургская ДХШ'}), {showAuthor: true})
|
||||
}
|
||||
|
||||
exports.renderHome = renderHome
|
||||
@@ -1,116 +0,0 @@
|
||||
const React = require('react')
|
||||
const Picture = require('../components/Image')
|
||||
const CollectiveImage = require('../components/CollectiveImage')
|
||||
const Page = require('../components/Page')
|
||||
const PersonCard = require('../components/PersonCard')
|
||||
const {render} = require('../lib/render')
|
||||
const timestamp = require('../lib/date').timestamp
|
||||
const ImageArtifactType = require('../core/ImageArtifactType')
|
||||
const Teacher = require('../core/Teacher')
|
||||
const Image = require('../core/Image')
|
||||
const Config = require('../core/Config')
|
||||
const {sortBy} = require('../utils/sort')
|
||||
const {prioritySort} = require('../lib/sort')
|
||||
|
||||
const metaImageTypesPriority = [
|
||||
ImageArtifactType.FACEBOOK,
|
||||
ImageArtifactType.MEDIUM,
|
||||
ImageArtifactType.BIG,
|
||||
ImageArtifactType.ORIGIN,
|
||||
]
|
||||
|
||||
function getMeta(teacher) {
|
||||
const meta = {
|
||||
title: teacher.name,
|
||||
}
|
||||
|
||||
if (teacher.preview) {
|
||||
try {
|
||||
const artifact = teacher.preview.findArtifact(metaImageTypesPriority)
|
||||
meta.image = artifact.url
|
||||
meta.imageWidth = artifact.width
|
||||
meta.imageHeight = artifact.height
|
||||
} catch (error) {
|
||||
}
|
||||
}
|
||||
return meta
|
||||
}
|
||||
|
||||
function getCollectiveMeta(picture) {
|
||||
const meta = {
|
||||
title: 'Преподаватели Шлиссельбургской ДХШ',
|
||||
description: 'Преподаватели Шлиссельбургской ДХШ',
|
||||
}
|
||||
|
||||
if (picture) {
|
||||
const artifact = picture.findArtifact(metaImageTypesPriority)
|
||||
meta.image = artifact.url
|
||||
meta.imageWidth = artifact.width
|
||||
meta.imageHeight = artifact.height
|
||||
}
|
||||
|
||||
return meta
|
||||
}
|
||||
|
||||
async function renderPerson(id) {
|
||||
const teacher = await Teacher.findById(id)
|
||||
if (!teacher) return null
|
||||
|
||||
const Component = (
|
||||
<div className="content content_thin">
|
||||
<Page shareable={true}>{teacher.post}</Page>
|
||||
</div>
|
||||
)
|
||||
|
||||
return render(teacher.url, Component, getMeta(teacher), {commentsEnabled: true, menuPadding: true})
|
||||
}
|
||||
|
||||
const profilePicture = profile => profile.picture.getPicture(ImageArtifactType.BIG)
|
||||
|
||||
async function renderCollective(path, order) {
|
||||
const config = await Config.findConfig()
|
||||
if (!config) return null
|
||||
|
||||
const collectiveImage = await Image.findByFile(config.collectiveImage)
|
||||
|
||||
let teachers = await Teacher.find({hidden: false})
|
||||
if (!teachers) return null
|
||||
|
||||
const teachersSorted = prioritySort.bind(null, [...order], t => t.id)
|
||||
teachers = teachersSorted(teachers)
|
||||
|
||||
const image = collectiveImage
|
||||
? collectiveImage.getPicture(ImageArtifactType.LARGE)
|
||||
: null
|
||||
|
||||
const PersonCardList = ({children}) => (
|
||||
<div className="PersonCardList">
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
|
||||
const Component = (
|
||||
<div className="content content_semi-wide">
|
||||
{!image ? null : (
|
||||
<CollectiveImage data={image}/>
|
||||
)}
|
||||
|
||||
<PersonCardList>
|
||||
{teachers.map((teacher, index) => (
|
||||
<PersonCard
|
||||
key={index}
|
||||
profile={teacher}
|
||||
picture={profilePicture(teacher)}
|
||||
url={teacher.url}
|
||||
name={teacher.splitName()}
|
||||
/>
|
||||
))}
|
||||
</PersonCardList>
|
||||
</div>
|
||||
)
|
||||
|
||||
return render(path, Component, getCollectiveMeta(collectiveImage), {menuPadding: true})
|
||||
}
|
||||
|
||||
exports.renderPerson = renderPerson
|
||||
exports.renderCollective = renderCollective
|
||||
@@ -1,17 +0,0 @@
|
||||
const {renderAlbum} = require('../render/albums')
|
||||
const {get} = require('koa-route')
|
||||
|
||||
function getAlbum() {
|
||||
return get('/album/:id', async (ctx, id) => {
|
||||
const body = await renderAlbum(id)
|
||||
|
||||
if (body) {
|
||||
ctx.type = 'text/html'
|
||||
ctx.body = body
|
||||
} else {
|
||||
ctx.status = 404
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
exports.getAlbum = getAlbum
|
||||
@@ -1,46 +0,0 @@
|
||||
const {get} = require('koa-route')
|
||||
const Article = require('../components/Article')
|
||||
const {renderArticles, renderArticle} = require('../render/articles')
|
||||
const getPathWithNoTrailingSlash = require('../lib/url').getPathWithNoTrailingSlash
|
||||
const accepts = require('./index').accepts
|
||||
|
||||
function getArticles(pageSize) {
|
||||
return get('/articles/:page?', async (ctx, page) => {
|
||||
page = parseInt(page) || 1
|
||||
|
||||
if (page === 1) {
|
||||
ctx.redirect('/')
|
||||
} else {
|
||||
const path = getPathWithNoTrailingSlash(ctx.path)
|
||||
|
||||
ctx.body = await renderArticles(path, page, pageSize)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function getArticle() {
|
||||
return get('/article/:id', accepts({
|
||||
'text/html': async (ctx, id) => {
|
||||
const body = await renderArticle(id)
|
||||
|
||||
if (body) {
|
||||
ctx.type = 'text/html'
|
||||
ctx.body = body
|
||||
} else {
|
||||
ctx.status = 404
|
||||
}
|
||||
},
|
||||
'application/json': async (ctx, id) => {
|
||||
const article = await Article.findById(id)
|
||||
|
||||
if (article) {
|
||||
ctx.body = article
|
||||
} else {
|
||||
ctx.status = 404
|
||||
}
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
exports.getArticles = getArticles
|
||||
exports.getArticle = getArticle
|
||||
@@ -1,126 +0,0 @@
|
||||
const React = require('react')
|
||||
const Share = require('../components/Share')
|
||||
const DocumentComponent = require('../components/Document')
|
||||
const Document = require('../core/Document')
|
||||
const ImageArtifactType = require('../core/ImageArtifactType')
|
||||
const {render} = require('../lib/render')
|
||||
const {prioritySort} = require('../lib/sort')
|
||||
const getPathWithNoTrailingSlash = require('../lib/url').getPathWithNoTrailingSlash
|
||||
const {get} = require('koa-route')
|
||||
const {splitBy} = require('../lib/array')
|
||||
const {unique} = require('../utils/common')
|
||||
const {bakeDocument} = require('./documents')
|
||||
|
||||
const sizes = [
|
||||
ImageArtifactType.MEDIUM,
|
||||
ImageArtifactType.BIG,
|
||||
ImageArtifactType.ORIGIN,
|
||||
]
|
||||
|
||||
function getMeta(document) {
|
||||
return {
|
||||
title: document.title,
|
||||
description: document.title,
|
||||
}
|
||||
}
|
||||
|
||||
function getDocument() {
|
||||
return get('/document/:id', async (ctx, id) => {
|
||||
const path = getPathWithNoTrailingSlash(ctx.path)
|
||||
const document = await Document.findById(id)
|
||||
const data = document
|
||||
? await bakeDocument(document)
|
||||
: null
|
||||
|
||||
if (data) {
|
||||
const Component = (
|
||||
<div className="content content_wide">
|
||||
<DocumentComponent {...data}/>
|
||||
|
||||
<Share/>
|
||||
</div>
|
||||
)
|
||||
|
||||
ctx.type = 'text/html'
|
||||
ctx.body = await render(path, Component, getMeta(document), {menuPadding: true})
|
||||
} else {
|
||||
ctx.status = 404
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
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)
|
||||
}], [])
|
||||
}
|
||||
|
||||
exports.getDocument = getDocument
|
||||
@@ -1,159 +0,0 @@
|
||||
const React = require('react')
|
||||
const Article = require('../components/Article')
|
||||
const DocumentList = require('../components/DocumentList')
|
||||
const Document = require('../core/Document')
|
||||
const ImageArtifactType = require('../core/ImageArtifactType')
|
||||
const {render} = require('../lib/render')
|
||||
const {prioritySort} = require('../lib/sort')
|
||||
const getPathWithNoTrailingSlash = require('../lib/url').getPathWithNoTrailingSlash
|
||||
const {get} = require('koa-route')
|
||||
const {splitBy} = require('../lib/array')
|
||||
const {unique} = require('../utils/common')
|
||||
|
||||
const sizes = [
|
||||
ImageArtifactType.MEDIUM,
|
||||
ImageArtifactType.BIG,
|
||||
ImageArtifactType.ORIGIN,
|
||||
]
|
||||
|
||||
function getDocumentsMeta() {
|
||||
return {
|
||||
title: 'Документы',
|
||||
description: 'Документы Шлиссельбургской ДХШ',
|
||||
}
|
||||
}
|
||||
|
||||
function getMeta(teacher) {
|
||||
return {
|
||||
title: teacher.name,
|
||||
description: teacher.name,
|
||||
}
|
||||
}
|
||||
|
||||
async function bakeDocument(document) {
|
||||
const preview = document.preview
|
||||
if (!preview) return null
|
||||
|
||||
const image = preview.findArtifact(sizes)
|
||||
if (!image) return null
|
||||
|
||||
const category = (document.category || '')
|
||||
.replace('Documents/', '')
|
||||
.replace('Pages/', '')
|
||||
.replace('Albums/', '')
|
||||
.replace('Articles /', '')
|
||||
|
||||
return {
|
||||
category,
|
||||
title: document.title,
|
||||
fileName: document.fileInfo.name,
|
||||
fileSize: document.fileInfo.size,
|
||||
fileUrl: document.url,
|
||||
imageUrl: image.url,
|
||||
url: document.viewUrl,
|
||||
}
|
||||
}
|
||||
|
||||
function getDocuments() {
|
||||
return get('/documents', async ctx => {
|
||||
const path = getPathWithNoTrailingSlash(ctx.path)
|
||||
let documents = await Document.find({hidden: false})
|
||||
|
||||
if (documents) {
|
||||
documents = await Promise.all(documents.map(bakeDocument))
|
||||
documents = documents.filter(Boolean)
|
||||
|
||||
const collections = getSorted(documents)
|
||||
|
||||
const Component = (
|
||||
<div className="content content_thin">
|
||||
{collections.map(({name, items}, index) => (
|
||||
<DocumentList key={index} name={name} documents={items}/>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
|
||||
ctx.type = 'text/html'
|
||||
ctx.body = await render(path, Component, getDocumentsMeta(), {menuPadding: true})
|
||||
} else {
|
||||
ctx.status = 404
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
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)
|
||||
}], [])
|
||||
}
|
||||
|
||||
exports.bakeDocument = bakeDocument
|
||||
exports.getDocuments = getDocuments
|
||||
@@ -1,90 +0,0 @@
|
||||
const React = require('react')
|
||||
const Article = require('../components/Article')
|
||||
const Album = require('../core/Album')
|
||||
const {render} = require('../lib/render')
|
||||
const {splitBy} = require('../lib/array')
|
||||
const getPathWithNoTrailingSlash = require('../lib/url').getPathWithNoTrailingSlash
|
||||
const {get} = require('koa-route')
|
||||
|
||||
function getMeta() {
|
||||
return {
|
||||
title: 'Галерея',
|
||||
description: 'Галерея работ учащихся Шлиссельбургской Детской Художественной Школы'
|
||||
}
|
||||
}
|
||||
|
||||
// {data.set.map((s, i) => (
|
||||
// <source
|
||||
// key={i}
|
||||
// src={i}
|
||||
// />
|
||||
// ))}
|
||||
// const m = 0.5
|
||||
const m = 1
|
||||
const AlbumImage = ({data, alt}) => (
|
||||
<picture>
|
||||
<img
|
||||
className="opa"
|
||||
alt={alt}
|
||||
src={data.src}
|
||||
width={data.width * m}
|
||||
height={data.height * m}
|
||||
srcSet={(data.set || []).map(({url, density}) => `${url} ${density}x`)}
|
||||
/>
|
||||
</picture>
|
||||
)
|
||||
|
||||
const GItem = ({album}) => (
|
||||
<div className="gallery-item">
|
||||
<a className="invisible" href={album.url}>
|
||||
<AlbumImage data={album.preview} alt={album.title}/>
|
||||
</a>
|
||||
</div>
|
||||
)
|
||||
|
||||
const ACollection = ({title, albums}) => (
|
||||
<div className="album-collection">
|
||||
<div className="album-collection__title">{title}</div>
|
||||
<div className="album-collection__body">{
|
||||
albums.map((album, index) => (
|
||||
<GItem key={index} album={album}/>
|
||||
))
|
||||
}</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
function getGallery() {
|
||||
return get('/gallery', async ctx => {
|
||||
const path = getPathWithNoTrailingSlash(ctx.path)
|
||||
const query = {}
|
||||
const albums = await Album.find(query, {sort: {date: -1}})
|
||||
|
||||
if (albums.length) {
|
||||
const meta = getMeta()
|
||||
const albumsByYear = splitBy(a => a.date.getFullYear())(albums)
|
||||
|
||||
const Component = (
|
||||
<div className="content content_wide">
|
||||
<Article title={meta.title}>
|
||||
{
|
||||
[...albumsByYear.entries()].map(([year, albums], index) => (
|
||||
<ACollection
|
||||
key={index}
|
||||
title={year}
|
||||
albums={albums}
|
||||
/>
|
||||
))
|
||||
}
|
||||
</Article>
|
||||
</div>
|
||||
)
|
||||
|
||||
ctx.type = 'text/html'
|
||||
ctx.body = await render(path, Component, getMeta(), {menuPadding: true})
|
||||
} else {
|
||||
ctx.status = 404
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
exports.getGallery = getGallery
|
||||
@@ -1,12 +0,0 @@
|
||||
const {get} = require('koa-route')
|
||||
const {renderHome} = require('../render/home')
|
||||
const getPathWithNoTrailingSlash = require('../lib/url').getPathWithNoTrailingSlash
|
||||
|
||||
function getHome(pageSize) {
|
||||
return get('/', async ctx => {
|
||||
const path = getPathWithNoTrailingSlash(ctx.path)
|
||||
ctx.body = await renderHome(path, pageSize)
|
||||
})
|
||||
}
|
||||
|
||||
exports.getHome = getHome
|
||||
@@ -1,67 +0,0 @@
|
||||
import {readFile} from 'async-file'
|
||||
import handlebars from 'handlebars'
|
||||
|
||||
import {map, assign} from '../utils/common'
|
||||
import {index as indexFile} from '../config'
|
||||
|
||||
export function queryObject() {
|
||||
let toTrue = map(true, i => i === 'true')
|
||||
let toFalse = map(false, i => i === 'false')
|
||||
const processors = [toTrue, toFalse]
|
||||
|
||||
return async(ctx, next) => {
|
||||
ctx.query = Object
|
||||
.keys(ctx.query)
|
||||
.reduce((query, key) => assign(
|
||||
query,
|
||||
key,
|
||||
processors
|
||||
.reduce((value, fn) => fn(value), query[key])
|
||||
), ctx.query)
|
||||
|
||||
await next()
|
||||
}
|
||||
}
|
||||
|
||||
export function accepts(routes) {
|
||||
return async function (ctx) {
|
||||
const types = Object
|
||||
.keys(routes)
|
||||
.filter(type => ctx.request.accepts(type))
|
||||
|
||||
if (types.length) {
|
||||
let fn = routes[types[0]]
|
||||
|
||||
await fn.apply(ctx, arguments)
|
||||
} else {
|
||||
ctx.status = 406
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function index(fn) {
|
||||
return async function (ctx) {
|
||||
let test = true
|
||||
if (fn) test = await fn.apply(ctx, arguments)
|
||||
if (!test) ctx.status = 404
|
||||
|
||||
const data = await getInitialData()
|
||||
const source = await readFile(indexFile, 'utf-8')
|
||||
const template = handlebars.compile(source)
|
||||
|
||||
ctx.type = 'text/html'
|
||||
ctx.body = template({data: JSON.stringify(data)})
|
||||
}
|
||||
}
|
||||
|
||||
export function json(fn) {
|
||||
return accepts({
|
||||
'text/html': index(),
|
||||
'text/plain': index(),
|
||||
'application/json': fn
|
||||
})
|
||||
}
|
||||
|
||||
async function getInitialData() {
|
||||
return {pages: []}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
const {renderPage} = require('../render/page')
|
||||
const {get} = require('koa-route')
|
||||
const getPathWithNoTrailingSlash = require('../lib/url').getPathWithNoTrailingSlash
|
||||
|
||||
module.exports = function (handleNotFound) {
|
||||
return get('*', async ctx => {
|
||||
const path = getPathWithNoTrailingSlash(ctx.path)
|
||||
const body = await renderPage(path)
|
||||
if (body) {
|
||||
ctx.type = 'text/html'
|
||||
ctx.body = body
|
||||
} else {
|
||||
await handleNotFound(ctx)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
const getPathWithNoTrailingSlash = require('../lib/url').getPathWithNoTrailingSlash
|
||||
const {renderPerson, renderCollective} = require('../render/persons')
|
||||
const {get} = require('koa-route')
|
||||
|
||||
function getCollective(order) {
|
||||
return get('/collective', async ctx => {
|
||||
const path = getPathWithNoTrailingSlash(ctx.path)
|
||||
const body = await renderCollective(path, order)
|
||||
|
||||
if (body) {
|
||||
ctx.type = 'text/html'
|
||||
ctx.body = body
|
||||
} else {
|
||||
ctx.status = 404
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function getTeacher() {
|
||||
return get('/teacher/:id', async (ctx, id) => {
|
||||
const body = await renderPerson(id)
|
||||
|
||||
if (body) {
|
||||
ctx.type = 'text/html'
|
||||
ctx.body = body
|
||||
} else {
|
||||
ctx.status = 404
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
exports.getCollective = getCollective
|
||||
exports.getTeacher = getTeacher
|
||||
+33
-88
@@ -1,101 +1,46 @@
|
||||
import path from 'path'
|
||||
import { createServer } from 'http'
|
||||
import Koa from 'koa'
|
||||
import serve from 'koa-static'
|
||||
import logger from 'koa-logger'
|
||||
import convert from 'koa-convert'
|
||||
import conditional from 'koa-conditional-get'
|
||||
import etag from 'koa-etag'
|
||||
import helmet from 'koa-helmet'
|
||||
import cookie from 'koa-cookie'
|
||||
import session from 'koa-session'
|
||||
import bodyParser from 'koa-bodyparser'
|
||||
import next from 'next'
|
||||
|
||||
import {queryObject} from './routes'
|
||||
import handlebars from 'handlebars'
|
||||
|
||||
const {sessionConfig, view404} = require('./config')
|
||||
const error = require('./middlewares/error')
|
||||
const redirect = require('./middlewares/redirect')
|
||||
const home = require('./routes/home')
|
||||
const article = require('./routes/articles')
|
||||
const albums = require('./routes/albums')
|
||||
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 pages = require('./routes/pages')
|
||||
const sitemap = require('./routes/sitemap')
|
||||
|
||||
const dirPublic = path.join(__dirname, '../public')
|
||||
|
||||
handlebars.registerHelper('raw-helper', options => options.fn())
|
||||
const Koa = require('koa')
|
||||
const next = require('next')
|
||||
const { get } = require('koa-route')
|
||||
const { connect } = require('./core/db')
|
||||
const Page = require('./core/Page')
|
||||
|
||||
const dev = process.env.NODE_ENV !== 'production'
|
||||
const app = next({ dev })
|
||||
const handle = app.getRequestHandler()
|
||||
const port = parseInt(process.env.PORT, 10) || 3000
|
||||
|
||||
function nextHandler() {
|
||||
return async ctx => {
|
||||
await handle(ctx.req, ctx.res)
|
||||
ctx.respond = false
|
||||
app.prepare().then(async () => {
|
||||
try {
|
||||
await connect(process.env.DB_URI)
|
||||
} catch (e) {
|
||||
console.error(e.message)
|
||||
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
export default async function (config) {
|
||||
const $ = convert
|
||||
|
||||
await app.prepare()
|
||||
|
||||
const server = new Koa()
|
||||
server.keys = ['1234']
|
||||
server.proxy = true
|
||||
|
||||
server.use(bodyParser({
|
||||
extendTypes: {
|
||||
json: 'application/ejson'
|
||||
}
|
||||
}))
|
||||
server.use(logger())
|
||||
server.use(convert(session(sessionConfig, server)))
|
||||
server.use(cookie())
|
||||
server.use($(conditional()))
|
||||
server.use($(etag()))
|
||||
server.use(serve(dirPublic))
|
||||
server.use(redirect(config.redirect))
|
||||
server.use($(helmet()))
|
||||
server.use(queryObject())
|
||||
|
||||
server.use(async (ctx, next) => {
|
||||
if (ctx.session.isNew) {
|
||||
ctx.session.startDate = new Date()
|
||||
}
|
||||
|
||||
await next()
|
||||
})
|
||||
|
||||
server.use(error.notFound(view404))
|
||||
server.use(sitemap())
|
||||
|
||||
// server.use(edit.getEdit())
|
||||
server.use(home.getHome(config.articlesPerPage))
|
||||
server.use(gallery.getGallery())
|
||||
server.use(article.getArticles(config.articlesPerPage))
|
||||
server.use(article.getArticle())
|
||||
server.use(albums.getAlbum())
|
||||
server.use(teachers.getCollective(config.collectiveOrder))
|
||||
server.use(teachers.getTeacher())
|
||||
server.use(documents.getDocuments())
|
||||
server.use(document.getDocument())
|
||||
server.use(schedule.getSchedule())
|
||||
server.use(pages(nextHandler()))
|
||||
const pages = await Page.find({})
|
||||
const pagesUrls = pages.map(x => x.url)
|
||||
|
||||
const server = new Koa()
|
||||
server.use(async (ctx, next) => {
|
||||
ctx.res.statusCode = 200
|
||||
await next()
|
||||
})
|
||||
|
||||
return createServer(server.callback())
|
||||
}
|
||||
server.use(get('*', async ctx => {
|
||||
const url = ctx.req.url
|
||||
|
||||
if (pagesUrls.includes(url)) {
|
||||
await app.render(ctx.req, ctx.res, '/next', ctx.query)
|
||||
} else {
|
||||
await handle(ctx.req, ctx.res)
|
||||
}
|
||||
|
||||
ctx.respond = false
|
||||
}))
|
||||
|
||||
server.listen(port, () => {
|
||||
console.log(`> Ready on http://localhost:${port}`)
|
||||
})
|
||||
})
|
||||
|
||||
Reference in new issue
Block a user