From 68b7f4225daee0368b975e93b7f475b3f489fe1a Mon Sep 17 00:00:00 2001 From: Roman Timashev Date: Mon, 2 Mar 2020 00:36:16 +0300 Subject: [PATCH 01/34] api Page update --- modules/hudozka-api/src/core/Page.ts | 20 ++++------------ modules/hudozka-api/src/factory/image.ts | 29 +++++++++++++++++++++--- modules/hudozka-api/src/factory/page.ts | 28 ++++++++++++++++++++--- 3 files changed, 56 insertions(+), 21 deletions(-) diff --git a/modules/hudozka-api/src/core/Page.ts b/modules/hudozka-api/src/core/Page.ts index 90ca78e0..c19a4f74 100644 --- a/modules/hudozka-api/src/core/Page.ts +++ b/modules/hudozka-api/src/core/Page.ts @@ -1,6 +1,7 @@ import Data from './Data' import { find as storeFind, findOne, total } from '../lib/store' import Image from './Image' +import { Tag } from './Tag' const store = () => Data.getStore('Page') @@ -37,6 +38,8 @@ export default class Page { public url: string public content: any public title: any + public date: Date + public tags: Tag[] public data: any public images: any public documents: any @@ -52,27 +55,14 @@ export default class Page { this.content = data.content this.title = data.title this.data = data.data + this.date = data.date this.images = data.images this.documents = data.documents this.preview = data.preview this.tokens = data.tokens + this.tags = (data.tags || []).map(x => new Tag(x)) this.description = data.description } - - plain() { - return { - id: this.id, - images: this.images, - documents: this.documents, - data: this.data, - title: this.title, - content: this.content, - hash: this.hash, - file: this.file, - preview: this.preview, - url: this.url, - } - } } const previewFromImage = (imgs = []) => imgs.length diff --git a/modules/hudozka-api/src/factory/image.ts b/modules/hudozka-api/src/factory/image.ts index 717ec47b..828eaebc 100644 --- a/modules/hudozka-api/src/factory/image.ts +++ b/modules/hudozka-api/src/factory/image.ts @@ -1,6 +1,29 @@ import ImageArtifactType from '../core/ImageArtifactType' -export function encodeImage(image) { +export type ImageArtifactDto = { + height: number + width: number + src: string + set: Array<{ + density: number + url: string + }> +} + +export type ImageDto = { + artifacts: { + original: ImageArtifactDto, + large: ImageArtifactDto, + big: ImageArtifactDto, + medium: ImageArtifactDto, + small: ImageArtifactDto, + fb: ImageArtifactDto, + }, + hash: string + file: string +} + +export function encodeImage(image): ImageDto { const artifacts = [ ImageArtifactType.SMALL, ImageArtifactType.MEDIUM, @@ -17,8 +40,8 @@ export function encodeImage(image) { }, {}) return { - artifacts, + artifacts: artifacts as any, hash: image.hash, - file: image.file, + file: image.file, } } diff --git a/modules/hudozka-api/src/factory/page.ts b/modules/hudozka-api/src/factory/page.ts index 003887ae..66272eab 100644 --- a/modules/hudozka-api/src/factory/page.ts +++ b/modules/hudozka-api/src/factory/page.ts @@ -1,9 +1,29 @@ -import { encodeImage } from './image' +import { encodeImage, ImageDto } from './image' import Page from '../core/Page' import { Breadcrumb } from '../types' +import { Tag } from '../core/Tag' -export function encodePage(page: Page, breadcrumb: Breadcrumb) { +type Token = { + token: string + data: any +} + +type PageDto = { + id: string + title: string + date?: string + url: string + data: string + description: string + preview?: ImageDto + tokens: Token[] + tags: Tag[] + breadcrumb: Breadcrumb +} + +export function encodePage(page: Page, breadcrumb: Breadcrumb): PageDto { const preview = page.preview ? encodeImage(page.preview) : null + const date = page.date ? page.date.toString() : null return { id: page.id, @@ -11,8 +31,10 @@ export function encodePage(page: Page, breadcrumb: Breadcrumb) { url: page.url, data: page.data, description: page.description, - preview, tokens: page.tokens, + tags: page.tags, + preview, + date, breadcrumb, } } From 348c3baba82cd367d6e73ecd4a16a4004c995703 Mon Sep 17 00:00:00 2001 From: Roman Timashev Date: Mon, 2 Mar 2020 04:40:01 +0300 Subject: [PATCH 02/34] api Page updated: refactor to make it looks like article --- .../hudozka-api/src/controllers/article.ts | 11 +--- modules/hudozka-api/src/controllers/page.ts | 51 +++++++++++++++-- modules/hudozka-api/src/core/Article.ts | 48 ++++++++-------- modules/hudozka-api/src/core/Image.ts | 3 +- modules/hudozka-api/src/core/Page.ts | 55 ++++++++++++++----- modules/hudozka-api/src/core/Tag.ts | 17 ++++-- modules/hudozka-api/src/factory/image.ts | 3 +- modules/hudozka-api/src/factory/page.ts | 5 +- modules/hudozka-api/src/lib/array.ts | 13 +++++ modules/hudozka-api/src/lib/url.ts | 16 ++++++ modules/hudozka-api/src/server.ts | 1 + 11 files changed, 160 insertions(+), 63 deletions(-) diff --git a/modules/hudozka-api/src/controllers/article.ts b/modules/hudozka-api/src/controllers/article.ts index 4f9a2f31..63e17ce1 100644 --- a/modules/hudozka-api/src/controllers/article.ts +++ b/modules/hudozka-api/src/controllers/article.ts @@ -2,11 +2,7 @@ import Article from '../core/Article' import { findArticles } from '../server/articles' import { Request, Response } from 'express' import { encodeArticle } from '../factory/article' - -const int = (value: string | string[]) => parseInt(Array.isArray(value) - ? value[0] - : value -) +import { readQueryInt } from '../lib/url' export async function getItem(req: Request, res: Response) { const id = req.params.slug @@ -23,9 +19,8 @@ export async function getItem(req: Request, res: Response) { } export async function getAll(req: Request, res: Response) { - const { query } = req - const page = int(query.page) - const pageSize = int(query.pageSize) + const page = readQueryInt(req, 'page') + const pageSize = readQueryInt(req, 'pageSize') const data = await findArticles(page, pageSize) diff --git a/modules/hudozka-api/src/controllers/page.ts b/modules/hudozka-api/src/controllers/page.ts index 58f99752..33ea8155 100644 --- a/modules/hudozka-api/src/controllers/page.ts +++ b/modules/hudozka-api/src/controllers/page.ts @@ -1,20 +1,27 @@ import { Request, Response } from 'express' import Page from '../core/Page' -import { dropTrailingSlash, getPathWaterfall } from '../lib/url' +import { dropTrailingSlash, getPathWaterfall, readQueryArray, readQueryInt } from '../lib/url' import { encodePage } from '../factory/page' import * as breadcrumb from './breadcrumb' +async function resolveItem(page: Page) { + const breadcrumbs = await breadcrumb.getItems(page.getUrl()) + page.setBreadcrumb(breadcrumbs) + + return page +} + export async function getItem(req: Request, res: Response) { - const page = dropTrailingSlash(req.query.page) - const breadcrumbs = await breadcrumb.getItems(page) - const resource = await Page.findByUrl(page) + const pageUrl = dropTrailingSlash(req.query.page) + const resource = await Page.findByUrl(pageUrl) if (resource) { - res.json(encodePage(resource, breadcrumbs)) + const page = await resolveItem(resource) + res.json(encodePage(page)) } else { res.status(404) res.json({ - error: `Resource ${page} not found` + error: `Resource ${pageUrl} not found` }) } } @@ -34,6 +41,38 @@ export async function getAll(req: Request, res: Response) { } } +export async function getByTags(req: Request, res: Response) { + const skip = readQueryInt(req, 'skip') + const limit = readQueryInt(req, 'limit') + + const tags = readQueryArray(req, 'tag') + if (tags.length === 0) { + res.status(400) + return res.json({ + error: `No tags in request` + }) + } + + const options = { skip, limit } + const models = await Page.find({ + tags: { $in: ['event', 'album'] }, + }, options) + + if (models) { + const pages = await Promise.all(models.map(resolveItem)) + const items = pages.map(encodePage) + + res.json({ + items, + }) + } else { + res.status(404) + res.json({ + error: `Not found` + }) + } +} + export async function getUrls(req: Request, res: Response) { const data = await Page.find({}) diff --git a/modules/hudozka-api/src/core/Article.ts b/modules/hudozka-api/src/core/Article.ts index 0f093140..3187c5f7 100644 --- a/modules/hudozka-api/src/core/Article.ts +++ b/modules/hudozka-api/src/core/Article.ts @@ -5,10 +5,6 @@ import { Tag } from './Tag' const store = () => Data.getStore
('Article') -function make(C) { - return x => new C(x) -} - export default class Article { static async find(query, options = {}): Promise { const items = await find(store(), query, options as any) @@ -63,7 +59,7 @@ export default class Article { this.date = data.date this.title = data.title this.until = data.until - this.tags = (data.tags || []).map(make(Tag)) + this.tags = (data.tags || []).map((x: string) => Tag.fromCyrillic(x)) this.content = data.content this.hash = data.hash this.type = data.type @@ -76,27 +72,27 @@ export default class Article { this.url = `/article/${this.id}` } - plain() { - return { - id: this.id, - images: this.images, - post: this.post, - folder: this.folder, - date: this.date, - title: this.title, - until: this.until, - tags: this.tags, - content: this.content, - hash: this.hash, - type: this.type, - origin: this.origin, - file: this.file, - version: this.version, - preview: this.preview, - url: this.url, - featured: this.featured, - } - } + // plain() { + // return { + // id: this.id, + // images: this.images, + // post: this.post, + // folder: this.folder, + // date: this.date, + // title: this.title, + // until: this.until, + // tags: this.tags, + // content: this.content, + // hash: this.hash, + // type: this.type, + // origin: this.origin, + // file: this.file, + // version: this.version, + // preview: this.preview, + // url: this.url, + // featured: this.featured, + // } + // } } const previewFromImage = (imgs = []) => imgs.length diff --git a/modules/hudozka-api/src/core/Image.ts b/modules/hudozka-api/src/core/Image.ts index 3e1608f2..be306683 100644 --- a/modules/hudozka-api/src/core/Image.ts +++ b/modules/hudozka-api/src/core/Image.ts @@ -2,11 +2,12 @@ import Data from './Data' import ImageArtifactType from './ImageArtifactType' import { findOne } from '../lib/store' import { mapOf } from '../server/lib' +import { ObjectId } from 'mongodb' const store = () => Data.getStore('Image') export default class Image { - static async findById(id) { + static async findById(id: ObjectId) { const data = await findOne(store(), { _id: id }) if (!data) return null diff --git a/modules/hudozka-api/src/core/Page.ts b/modules/hudozka-api/src/core/Page.ts index c19a4f74..208967b9 100644 --- a/modules/hudozka-api/src/core/Page.ts +++ b/modules/hudozka-api/src/core/Page.ts @@ -2,9 +2,17 @@ import Data from './Data' import { find as storeFind, findOne, total } from '../lib/store' import Image from './Image' import { Tag } from './Tag' +import { ObjectId } from 'mongodb' +import { Breadcrumb } from '../types' const store = () => Data.getStore('Page') +type PageDto = { + [name: string]: any + preview?: ObjectId + images: ObjectId[] +} + export default class Page { static async find(query, options = {}): Promise { const items = await storeFind(store(), query, options as any) @@ -20,7 +28,7 @@ export default class Page { : processPage(item) } - static async findByUrl(url) { + static async findByUrl(url: string) { const item = await findOne(store(), { url }) return !item @@ -41,13 +49,16 @@ export default class Page { public date: Date public tags: Tag[] public data: any - public images: any + public images: ObjectId[] public documents: any - public preview: any + public preview?: Image public tokens: any[] public description: string + public featured: boolean - constructor(data) { + private breadcrumb: Breadcrumb + + constructor(data: { [name: string]: any }) { this.id = data.id this.hash = data.hash this.file = data.file @@ -60,27 +71,43 @@ export default class Page { this.documents = data.documents this.preview = data.preview this.tokens = data.tokens - this.tags = (data.tags || []).map(x => new Tag(x)) + this.tags = (data.tags || []).map((x: string) => new Tag(x, x)) + this.featured = data.featured this.description = data.description } + + public setBreadcrumb(value: Breadcrumb) { + this.breadcrumb = value + return this + } + + public getBreadcrumb() { + return this.breadcrumb + } + + public getUrl() { + return this.url + } } -const previewFromImage = (imgs = []) => imgs.length - ? imgs[0] - : null +function firstItem(items: T[] = []): T { + return items.length + ? items[0] + : null +} -async function processPage(article) { - let preview = null - const previewId = article.preview - ? article.preview - : previewFromImage(article.images) +async function processPage(item: PageDto): Promise { + let preview: Image = null + const previewId = item.preview + ? item.preview + : firstItem(item.images) if (previewId) { preview = await Image.findById(previewId) } return new Page({ - ...article, + ...item, preview, }) } diff --git a/modules/hudozka-api/src/core/Tag.ts b/modules/hudozka-api/src/core/Tag.ts index 1e6dae59..2f121c2d 100644 --- a/modules/hudozka-api/src/core/Tag.ts +++ b/modules/hudozka-api/src/core/Tag.ts @@ -1,15 +1,20 @@ import { translit } from '../lib/translit' export class Tag { + public static fromCyrillic(tag: string) { + const slug = tag + ? translit(tag).toLowerCase() + : tag + + return new Tag(tag, slug) + } + public name: string public slug: string - constructor(tag: string) { - this.name = tag - - if (tag) { - this.slug = translit(tag).toLowerCase() - } + constructor(name: string, slug: string) { + this.name = name + this.slug = slug } public isValid() { diff --git a/modules/hudozka-api/src/factory/image.ts b/modules/hudozka-api/src/factory/image.ts index 828eaebc..9720c850 100644 --- a/modules/hudozka-api/src/factory/image.ts +++ b/modules/hudozka-api/src/factory/image.ts @@ -1,4 +1,5 @@ import ImageArtifactType from '../core/ImageArtifactType' +import Image from '../core/Image' export type ImageArtifactDto = { height: number @@ -23,7 +24,7 @@ export type ImageDto = { file: string } -export function encodeImage(image): ImageDto { +export function encodeImage(image: Image): ImageDto { const artifacts = [ ImageArtifactType.SMALL, ImageArtifactType.MEDIUM, diff --git a/modules/hudozka-api/src/factory/page.ts b/modules/hudozka-api/src/factory/page.ts index 66272eab..231b5916 100644 --- a/modules/hudozka-api/src/factory/page.ts +++ b/modules/hudozka-api/src/factory/page.ts @@ -18,12 +18,14 @@ type PageDto = { preview?: ImageDto tokens: Token[] tags: Tag[] + featured: boolean breadcrumb: Breadcrumb } -export function encodePage(page: Page, breadcrumb: Breadcrumb): PageDto { +export function encodePage(page: Page): PageDto { const preview = page.preview ? encodeImage(page.preview) : null const date = page.date ? page.date.toString() : null + const breadcrumb = page.getBreadcrumb() return { id: page.id, @@ -33,6 +35,7 @@ export function encodePage(page: Page, breadcrumb: Breadcrumb): PageDto { description: page.description, tokens: page.tokens, tags: page.tags, + featured: page.featured, preview, date, breadcrumb, diff --git a/modules/hudozka-api/src/lib/array.ts b/modules/hudozka-api/src/lib/array.ts index 65031f2a..294db4eb 100644 --- a/modules/hudozka-api/src/lib/array.ts +++ b/modules/hudozka-api/src/lib/array.ts @@ -3,3 +3,16 @@ export function unique(items: T[], key: (item: T) => string): T[]{ return [...map.values()] } + +export function ensureArray(value: T | T[]): T[] { + if (!value) { + return [] + } + + if (Array.isArray(value)) { + return value + } + + return [value] +} + diff --git a/modules/hudozka-api/src/lib/url.ts b/modules/hudozka-api/src/lib/url.ts index f6c2bd5f..4ac3bb88 100644 --- a/modules/hudozka-api/src/lib/url.ts +++ b/modules/hudozka-api/src/lib/url.ts @@ -1,3 +1,6 @@ +import { Request } from 'express' +import { ensureArray } from './array' + export function dropTrailingSlash(path: string) { if (path === '/' || path === '') { return '/' @@ -26,3 +29,16 @@ export function getPathWaterfall(path: string): string[] { return ['/', ...parts] } + +export function readQueryInt(req: Request, key: string) { + const int = (value: string | string[]) => parseInt(Array.isArray(value) + ? value[0] + : value + ) + + return int(req.query[key]) || 0 +} + +export function readQueryArray(req: Request, key: string) { + return ensureArray(req.query[key]) +} diff --git a/modules/hudozka-api/src/server.ts b/modules/hudozka-api/src/server.ts index d0dfdb6e..b8c82676 100644 --- a/modules/hudozka-api/src/server.ts +++ b/modules/hudozka-api/src/server.ts @@ -33,6 +33,7 @@ async function main() { app.get('/pages', page.getAll) app.get('/pages/urls', page.getUrls) + app.get('/pages/tags', page.getByTags) app.get('/page', page.getItem) app.get('/image', image.getItem) From d859fdb3027109d49c252f34e2e2194ed89081b8 Mon Sep 17 00:00:00 2001 From: Roman Timashev Date: Mon, 2 Mar 2020 05:08:09 +0300 Subject: [PATCH 03/34] api pages by tags sorting key --- modules/hudozka-api/src/controllers/page.ts | 22 +++++++++++++++++++-- modules/hudozka-api/src/lib/url.ts | 4 ++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/modules/hudozka-api/src/controllers/page.ts b/modules/hudozka-api/src/controllers/page.ts index 33ea8155..6544620c 100644 --- a/modules/hudozka-api/src/controllers/page.ts +++ b/modules/hudozka-api/src/controllers/page.ts @@ -1,9 +1,25 @@ import { Request, Response } from 'express' import Page from '../core/Page' -import { dropTrailingSlash, getPathWaterfall, readQueryArray, readQueryInt } from '../lib/url' +import { dropTrailingSlash, getPathWaterfall, readQueryArray, readQueryInt, readQueryString } from '../lib/url' import { encodePage } from '../factory/page' import * as breadcrumb from './breadcrumb' +function getSort(sortBy: string) { + if (!sortBy) { + return null + } + + if (sortBy.charAt(0) === '-') { + return { + [sortBy.substr(1, sortBy.length)]: -1, + } + } + + return { + [sortBy]: 1, + } +} + async function resolveItem(page: Page) { const breadcrumbs = await breadcrumb.getItems(page.getUrl()) page.setBreadcrumb(breadcrumbs) @@ -44,6 +60,8 @@ export async function getAll(req: Request, res: Response) { export async function getByTags(req: Request, res: Response) { const skip = readQueryInt(req, 'skip') const limit = readQueryInt(req, 'limit') + const sortBy = readQueryString(req, 'sortBy') + const sort = getSort(sortBy) const tags = readQueryArray(req, 'tag') if (tags.length === 0) { @@ -53,7 +71,7 @@ export async function getByTags(req: Request, res: Response) { }) } - const options = { skip, limit } + const options = { skip, limit, sort } const models = await Page.find({ tags: { $in: ['event', 'album'] }, }, options) diff --git a/modules/hudozka-api/src/lib/url.ts b/modules/hudozka-api/src/lib/url.ts index 4ac3bb88..f7e0ea79 100644 --- a/modules/hudozka-api/src/lib/url.ts +++ b/modules/hudozka-api/src/lib/url.ts @@ -39,6 +39,10 @@ export function readQueryInt(req: Request, key: string) { return int(req.query[key]) || 0 } +export function readQueryString(req: Request, key: string) { + return `${req.query[key]}` +} + export function readQueryArray(req: Request, key: string) { return ensureArray(req.query[key]) } From 06745b45f493799218f7a10ba8ba7da67d786e46 Mon Sep 17 00:00:00 2001 From: Roman Timashev Date: Tue, 3 Mar 2020 01:33:17 +0300 Subject: [PATCH 04/34] api drop unused code --- .../hudozka-api/src/controllers/article.ts | 54 ------- modules/hudozka-api/src/controllers/page.ts | 6 +- .../hudozka-api/src/controllers/schedule.ts | 18 --- modules/hudozka-api/src/controllers/tag.ts | 6 +- modules/hudozka-api/src/core/Article.ts | 116 --------------- modules/hudozka-api/src/core/Image.ts | 16 ++- modules/hudozka-api/src/db.ts | 1 - modules/hudozka-api/src/factory/article.ts | 11 -- modules/hudozka-api/src/lib/date.ts | 7 - modules/hudozka-api/src/lib/file.ts | 23 --- modules/hudozka-api/src/lib/sort.js | 22 --- modules/hudozka-api/src/lib/store.ts | 20 +-- modules/hudozka-api/src/lib/string.js | 12 -- modules/hudozka-api/src/models/course.js | 22 --- modules/hudozka-api/src/models/schedule.js | 44 ------ modules/hudozka-api/src/server.ts | 7 - modules/hudozka-api/src/server/articles.ts | 56 -------- modules/hudozka-api/src/server/lib.ts | 14 -- modules/hudozka-api/src/server/schedule.ts | 134 ------------------ modules/hudozka-api/src/utils/common.ts | 106 -------------- modules/hudozka-api/src/utils/date.js | 21 --- modules/hudozka-api/src/utils/fn.js | 13 -- modules/hudozka-api/src/utils/net.js | 8 -- modules/hudozka-api/src/utils/populate.js | 35 ----- modules/hudozka-api/src/utils/sort.js | 26 ---- modules/hudozka-api/src/utils/string.js | 22 --- 26 files changed, 32 insertions(+), 788 deletions(-) delete mode 100644 modules/hudozka-api/src/controllers/article.ts delete mode 100644 modules/hudozka-api/src/controllers/schedule.ts delete mode 100644 modules/hudozka-api/src/core/Article.ts delete mode 100644 modules/hudozka-api/src/factory/article.ts delete mode 100644 modules/hudozka-api/src/lib/date.ts delete mode 100644 modules/hudozka-api/src/lib/file.ts delete mode 100644 modules/hudozka-api/src/lib/sort.js delete mode 100644 modules/hudozka-api/src/lib/string.js delete mode 100644 modules/hudozka-api/src/models/course.js delete mode 100644 modules/hudozka-api/src/models/schedule.js delete mode 100644 modules/hudozka-api/src/server/articles.ts delete mode 100644 modules/hudozka-api/src/server/lib.ts delete mode 100644 modules/hudozka-api/src/server/schedule.ts delete mode 100644 modules/hudozka-api/src/utils/common.ts delete mode 100644 modules/hudozka-api/src/utils/date.js delete mode 100644 modules/hudozka-api/src/utils/fn.js delete mode 100644 modules/hudozka-api/src/utils/net.js delete mode 100644 modules/hudozka-api/src/utils/populate.js delete mode 100644 modules/hudozka-api/src/utils/sort.js delete mode 100644 modules/hudozka-api/src/utils/string.js diff --git a/modules/hudozka-api/src/controllers/article.ts b/modules/hudozka-api/src/controllers/article.ts deleted file mode 100644 index 63e17ce1..00000000 --- a/modules/hudozka-api/src/controllers/article.ts +++ /dev/null @@ -1,54 +0,0 @@ -import Article from '../core/Article' -import { findArticles } from '../server/articles' -import { Request, Response } from 'express' -import { encodeArticle } from '../factory/article' -import { readQueryInt } from '../lib/url' - -export async function getItem(req: Request, res: Response) { - const id = req.params.slug - const article = await Article.findById(id) - - if (article) { - res.json(encodeArticle(article)) - } else { - res.status(404) - res.json({ - error: `Resource ${id} not found` - }) - } -} - -export async function getAll(req: Request, res: Response) { - const page = readQueryInt(req, 'page') - const pageSize = readQueryInt(req, 'pageSize') - - const data = await findArticles(page, pageSize) - - if (data) { - res.json({ - ...data, - items: data.items.map(encodeArticle) - }) - } else { - res.status(404) - res.json({ - error: `Articles not found` - }) - } -} - -export async function getUrls(req: Request, res: Response) { - const data = await Article.find({}) - - if (data) { - const items = data.map(x => `/article/${x.id}`) - res.json({ - items - }) - } else { - res.status(404) - res.json({ - error: `Not found` - }) - } -} diff --git a/modules/hudozka-api/src/controllers/page.ts b/modules/hudozka-api/src/controllers/page.ts index 6544620c..7f3296eb 100644 --- a/modules/hudozka-api/src/controllers/page.ts +++ b/modules/hudozka-api/src/controllers/page.ts @@ -10,8 +10,10 @@ function getSort(sortBy: string) { } if (sortBy.charAt(0) === '-') { + const key = sortBy.substr(1, sortBy.length) + return { - [sortBy.substr(1, sortBy.length)]: -1, + [key]: -1, } } @@ -73,7 +75,7 @@ export async function getByTags(req: Request, res: Response) { const options = { skip, limit, sort } const models = await Page.find({ - tags: { $in: ['event', 'album'] }, + tags: { $in: tags }, }, options) if (models) { diff --git a/modules/hudozka-api/src/controllers/schedule.ts b/modules/hudozka-api/src/controllers/schedule.ts deleted file mode 100644 index 706bb983..00000000 --- a/modules/hudozka-api/src/controllers/schedule.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { findSchedule } from '../server/schedule' -import { Request, Response } from 'express' -import { collection } from '../db' - -export async function getItem(req: Request, res: Response) { - const period = req.query.period - const semester = req.query.semester - const data = await findSchedule(collection, period, semester) - - if (data) { - res.json(data) - } else { - res.status(404) - res.json({ - error: `Schedule ${period}:${semester} not found` - }) - } -} diff --git a/modules/hudozka-api/src/controllers/tag.ts b/modules/hudozka-api/src/controllers/tag.ts index 6daf0469..4e5ca030 100644 --- a/modules/hudozka-api/src/controllers/tag.ts +++ b/modules/hudozka-api/src/controllers/tag.ts @@ -1,9 +1,9 @@ -import Article from '../core/Article' +import Page from '../core/Page' import { Request, Response } from 'express' import { unique } from '../lib/array' export async function getAll(req: Request, res: Response) { - const data = await Article.find({}) + const data = await Page.find({}) const tags = data .flatMap(x => x.tags) .filter(x => x.isValid()) @@ -24,7 +24,7 @@ export async function getAll(req: Request, res: Response) { export async function findItems(req: Request, res: Response) { const slug = req.params.slug - const data = await Article.find({ + const data = await Page.find({ tags: { } diff --git a/modules/hudozka-api/src/core/Article.ts b/modules/hudozka-api/src/core/Article.ts deleted file mode 100644 index 3187c5f7..00000000 --- a/modules/hudozka-api/src/core/Article.ts +++ /dev/null @@ -1,116 +0,0 @@ -import Data from './Data' -import Image from './Image' -import { find, findOne, total } from '../lib/store' -import { Tag } from './Tag' - -const store = () => Data.getStore
('Article') - -export default class Article { - static async find(query, options = {}): Promise { - const items = await find(store(), query, options as any) - - return Promise.all(items.map(processArticle)) - } - - static async findById(id) { - const item = await findOne(store(), { id }) - - return !item - ? null - : processArticle(item) - } - - static async total(query = {}) { - return total(store(), query) - } - - static async findPinned() { - const now = new Date() - const query = { until: { $gte: now } } - - return Article.find(query, { - sort: { date: -1 }, - }) - } - - public id: any - public images: any - public post: any - public folder: any - public date: any - public title: any - public until: any - public tags: Tag[] - public content: any - public hash: any - public type: any - public origin: any - public file: any - public version: any - public preview: any - public url: any - public featured: boolean - - constructor(data) { - this.id = data.id - this.images = data.images - this.post = data.post - this.folder = data.folder - this.date = data.date - this.title = data.title - this.until = data.until - this.tags = (data.tags || []).map((x: string) => Tag.fromCyrillic(x)) - this.content = data.content - this.hash = data.hash - this.type = data.type - this.origin = data.origin - this.file = data.file - this.version = data.version - this.preview = data.preview - this.featured = data.featured || false - - this.url = `/article/${this.id}` - } - - // plain() { - // return { - // id: this.id, - // images: this.images, - // post: this.post, - // folder: this.folder, - // date: this.date, - // title: this.title, - // until: this.until, - // tags: this.tags, - // content: this.content, - // hash: this.hash, - // type: this.type, - // origin: this.origin, - // file: this.file, - // version: this.version, - // preview: this.preview, - // url: this.url, - // featured: this.featured, - // } - // } -} - -const previewFromImage = (imgs = []) => imgs.length - ? imgs[0] - : null - -async function processArticle(article) { - let preview = null - const previewId = article.preview - ? article.preview - : previewFromImage(article.images) - - if (previewId) { - preview = await Image.findById(previewId) - } - - return new Article({ - ...article, - preview, - }) -} diff --git a/modules/hudozka-api/src/core/Image.ts b/modules/hudozka-api/src/core/Image.ts index be306683..568d7edc 100644 --- a/modules/hudozka-api/src/core/Image.ts +++ b/modules/hudozka-api/src/core/Image.ts @@ -1,9 +1,23 @@ import Data from './Data' import ImageArtifactType from './ImageArtifactType' import { findOne } from '../lib/store' -import { mapOf } from '../server/lib' import { ObjectId } from 'mongodb' +/** + * + * {a: {}, b: {}, ...} -> Map (a: Class, b: Class) + * + * @param Class + * @param object + */ +function mapOf(Class, object) { + return Object + .entries(object) + .reduce((map, i) => ( + map.set(i[0], new Class(i[1])) + ), new Map()) +} + const store = () => Data.getStore('Image') export default class Image { diff --git a/modules/hudozka-api/src/db.ts b/modules/hudozka-api/src/db.ts index 8816e724..1442a6aa 100644 --- a/modules/hudozka-api/src/db.ts +++ b/modules/hudozka-api/src/db.ts @@ -27,7 +27,6 @@ function init(db: Db) { console.log('INIT DB') Data.setStore('Page', db.collection('pages')) - Data.setStore('Article', db.collection('articles')) Data.setStore('Image', db.collection('images')) Data.setStore('Document', db.collection('documents')) Data.setStore('Settings', db.collection('settings')) diff --git a/modules/hudozka-api/src/factory/article.ts b/modules/hudozka-api/src/factory/article.ts deleted file mode 100644 index b4cfd83c..00000000 --- a/modules/hudozka-api/src/factory/article.ts +++ /dev/null @@ -1,11 +0,0 @@ -import Article from '../core/Article' -import { encodeImage } from './image' - -export function encodeArticle(article: Article) { - const preview = article.preview ? encodeImage(article.preview) : null - - return { - ...article, - preview, - } -} \ No newline at end of file diff --git a/modules/hudozka-api/src/lib/date.ts b/modules/hudozka-api/src/lib/date.ts deleted file mode 100644 index 4cfdd5f9..00000000 --- a/modules/hudozka-api/src/lib/date.ts +++ /dev/null @@ -1,7 +0,0 @@ -/** - * - * Date -> Unix time - * - * @param date - */ -export const timestamp = (date: Date) => date.getTime() diff --git a/modules/hudozka-api/src/lib/file.ts b/modules/hudozka-api/src/lib/file.ts deleted file mode 100644 index 504cc26d..00000000 --- a/modules/hudozka-api/src/lib/file.ts +++ /dev/null @@ -1,23 +0,0 @@ -const getExt = (name: string) => /\.(\w+)$/.exec(name)[1] -const defaultExt = (ext: string) => ext.toUpperCase() -const exts = ['png', 'pdf', 'jpg', 'jpeg', 'gif', 'doc'] -const extd = ['ПНГ', 'ПДФ', 'ЖПГ', 'ЖПГ', 'ГИФ', 'ДОК'] -const units = ['байт', 'КБ', 'МБ', 'ГБ', 'ТБ', 'ПБ'] - -export function ext(filname: string): string { - const ext = getExt(filname) - const i = exts.indexOf(ext) - - return i > -1 - ? extd[i] - : defaultExt(ext) -} - -export function size(bytes: any, precision = 1): string { - if (isNaN(parseFloat(bytes)) || !isFinite(bytes)) return '' - - const number = Math.floor(Math.log(bytes) / Math.log(1024)) - const size = (bytes / Math.pow(1024, Math.floor(number))).toFixed(precision) - - return `${size} ${units[number]}` -} diff --git a/modules/hudozka-api/src/lib/sort.js b/modules/hudozka-api/src/lib/sort.js deleted file mode 100644 index e1287244..00000000 --- a/modules/hudozka-api/src/lib/sort.js +++ /dev/null @@ -1,22 +0,0 @@ -function sort(list, fn, reverse = false) { - return list - .map(i => [fn(i), i]) - .sort((a, b) => reverse - ? a[0] - b[0] - : b[0] - a[0]) - .map(i => i[1]) -} - -function sortBy(fn, reverse = false) { - return (i1, i2) => { - const t1 = fn(i1) - const t2 = fn(i2) - - return reverse - ? t1 - t2 - : t2 - t1 - } -} - -exports.sortBy = sortBy -exports.sort = sort diff --git a/modules/hudozka-api/src/lib/store.ts b/modules/hudozka-api/src/lib/store.ts index 309848bd..d7cb40ba 100644 --- a/modules/hudozka-api/src/lib/store.ts +++ b/modules/hudozka-api/src/lib/store.ts @@ -1,19 +1,19 @@ -export async function find(collection, query, {sort, skip, limit}) { - const cursor = collection.find(query) +export async function find(collection, query, { sort, skip, limit }) { + const cursor = collection.find(query) - if (sort) cursor.sort(sort) - if (skip) cursor.skip(skip) - if (limit) cursor.limit(limit) + if (sort) cursor.sort(sort) + if (skip) cursor.skip(skip) + if (limit) cursor.limit(limit) - return cursor.toArray() + return cursor.toArray() } export async function findOne(collection, query) { - return collection.findOne(query) + return collection.findOne(query) } export async function total(collection, query) { - return collection - .find(query) - .count() + return collection + .find(query) + .count() } diff --git a/modules/hudozka-api/src/lib/string.js b/modules/hudozka-api/src/lib/string.js deleted file mode 100644 index 9a8a5493..00000000 --- a/modules/hudozka-api/src/lib/string.js +++ /dev/null @@ -1,12 +0,0 @@ -function titleCase(str) { - return str.charAt(0).toUpperCase() + str.slice(1) -} - -function trim(string) { - return string - .replace(/^\s+/, '') - .replace(/\s+$/, '') -} - -exports.titleCase = titleCase -exports.trim = trim diff --git a/modules/hudozka-api/src/models/course.js b/modules/hudozka-api/src/models/course.js deleted file mode 100644 index 35c33679..00000000 --- a/modules/hudozka-api/src/models/course.js +++ /dev/null @@ -1,22 +0,0 @@ -const courses = { - painting: ['Живопись', ''], - drawing: ['Рисунок', '/courses/drawing'], - sculpting: ['Скульптура', ''], - sculpture: ['Скульптура', ''], - ceramic: ['Керамика', '/courses/ceramics'], - ceramics: ['Керамика', '/courses/ceramics'], - composition: ['Композиция', ''], - 'easel-composition': ['Станковая композиция', ''], - dpi: ['ДПИ', ''], - 'art-talks': ['Беседа по искусству', ''], - history: ['История искусства', '/courses/art-history'], - cg: ['Комп. графика', '/courses/cg'], -} - -export function getCourse(id) { - const course = id in courses ? courses[id] : null - if (!course) return null - - const [title, url] = course - return {id, title, url} -} diff --git a/modules/hudozka-api/src/models/schedule.js b/modules/hudozka-api/src/models/schedule.js deleted file mode 100644 index 7acdde25..00000000 --- a/modules/hudozka-api/src/models/schedule.js +++ /dev/null @@ -1,44 +0,0 @@ -export const autumnMonth = 8; -export const springMonth = 0; - -export function scheduleDate(schedule){ - let {period, semester} = schedule; - - let i = semester === 'spring' ? 1 : 0; - let year = getPeriod(period)[i]; - - return new Date( - year, - i ? springMonth : autumnMonth, - 1 - ); -} - -/** - * - * f("2012-2015") -> [2012, 2015] - * f(["2012", "2015"]) -> [2012, 2015] - * f([2012, 2015]) -> [2012, 2015] - * - * @param i - * @returns {*} - */ -export function getPeriod(i){ - if (typeof i === 'string') return getPeriod(i.split('-')); - - return i.map(Number); -} - -/** - * - * f("2012-2015") -> "2012-2015" - * f(["2012", "2015"]) -> "2012-2015" - * f([2012, 2015]) -> "2012-2015" - * - * @param i - * @returns {*} - */ -export function getPeriodString(i) { - return getPeriod(i) - .join('-') -} diff --git a/modules/hudozka-api/src/server.ts b/modules/hudozka-api/src/server.ts index b8c82676..458a4bbe 100644 --- a/modules/hudozka-api/src/server.ts +++ b/modules/hudozka-api/src/server.ts @@ -1,8 +1,6 @@ import { config } from 'dotenv' import express from 'express' import { connect } from './db' -import * as article from './controllers/article' -import * as schedule from './controllers/schedule' import * as file from './controllers/file' import * as page from './controllers/page' import * as image from './controllers/image' @@ -23,10 +21,6 @@ async function main() { } const app = express() - app.get('/articles', article.getAll) - app.get('/articles/urls', article.getUrls) - app.get('/articles/:slug', article.getItem) - app.get('/files', file.getAll) app.get('/files/urls', file.getUrls) app.get('/files/:slug', file.getItem) @@ -38,7 +32,6 @@ async function main() { app.get('/image', image.getItem) - app.get('/schedule', schedule.getItem) app.get('/tags', tag.getAll) app.get('/tags/:slug', tag.findItems) diff --git a/modules/hudozka-api/src/server/articles.ts b/modules/hudozka-api/src/server/articles.ts deleted file mode 100644 index df418f0a..00000000 --- a/modules/hudozka-api/src/server/articles.ts +++ /dev/null @@ -1,56 +0,0 @@ -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: number, pageSize: number) { - const limit = pageSize - const skip = (page - 1) * pageSize - - // const pinnedArticles = page === 1 - // ? await Article.findPinned() - // : [] - - const total = await Article.total() - const totalPages = Math.ceil(total / pageSize) - - const id = i => i._id - // const pinnedIds = pinnedArticles.map(id) - // const articles = await findArticlesNin(pinnedIds, skip, limit, { date: -1 }) - const articles = await Article.find({}, { skip, limit, sort: { date: -1 } }) - - const prevPage = page > 1 - ? page - 1 - : null - - const nextPage = page < totalPages - ? page + 1 - : null - - const items = [ - ...articles - ] - - return { - items, - prevPage, - nextPage, - totalPages, - } -} diff --git a/modules/hudozka-api/src/server/lib.ts b/modules/hudozka-api/src/server/lib.ts deleted file mode 100644 index 898a1080..00000000 --- a/modules/hudozka-api/src/server/lib.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * - * {a: {}, b: {}, ...} -> Map (a: Class, b: Class) - * - * @param Class - * @param object - */ -export function mapOf(Class, object) { - return Object - .entries(object) - .reduce((map, i) => ( - map.set(i[0], new Class(i[1])) - ), new Map()) -} diff --git a/modules/hudozka-api/src/server/schedule.ts b/modules/hudozka-api/src/server/schedule.ts deleted file mode 100644 index ad4cef12..00000000 --- a/modules/hudozka-api/src/server/schedule.ts +++ /dev/null @@ -1,134 +0,0 @@ -import { createMap } from '../utils/common' -import { - scheduleDate, - getPeriod as schedulePeriod, - getPeriodString -} from '../models/schedule' -import { getCourse } from '../models/course' - -// import { last } from 'lodash' -// const sortBy = require('../lib/sort').sortBy - -const SCHEDULES = 'schedules' - -export async function findSchedule(collection, period, semester) { - const schedule = await collection(SCHEDULES).findOne({ - $or: [ - { period: period }, - { period: schedulePeriod(period) } - ], - semester: semester - }) - - return schedule ? migrate(schedule) : null -} - -// async function findAllScheduleParams() { -// const schedules = await collection(SCHEDULES) -// .find({}, { -// period: 1, -// semester: 1, -// _id: 0, -// }) -// .toArray() - -// return schedules -// .map(i => ({ -// ...i, -// period: schedulePeriod(i.period), -// })) -// .sort(sortBy( -// i => scheduleDate(i).getTime(), -// true, -// )) -// } - -// function text({ semester, period }) { -// const word = semester => [['spring', 'Весна'], ['autumn', 'Осень']] -// .find(i => i[0] === semester) -// [1] -// const periodIndex = semester === 'spring' ? 1 : 0 -// const year = period[periodIndex] - -// return `${word(semester)} ${year} года` -// } - -async function migrate(schedule) { - const versions = { - '1.0': migrate10to20, - '2.0': migrate20to30, - } - - const version = schedule.version - const update = versions[version] - return version in versions ? migrate(update(schedule)) : schedule -} - -function migrate10to20(schedule) { - const dayNames = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun'] - const time = time => time - .map(i => i.split(' ')) - - const week = days => days.reduce((week, lesson, index) => { - if (lesson) { - const day = dayNames[index] - week[day] = [Object.assign(lesson, { - time: time(lesson.time) - })] - } - - return week - }, {}) - - return Object.assign(schedule, { - version: '2.0', - period: schedulePeriod(schedule.period), - groups: schedule.schedule - .map(group => ({ - name: group.group, - time: group.time, - week: week(group.week) - })) - }) -} - -async function migrate20to30(schedule) { - const days = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat']//, 'sun'] - - const persons = [] - const person = createMap(i => i.id, persons) - - const week = week => days - .map(day => week[day] || []) - .map(lessons => lessons.map(lesson)) - - const lesson = i => ({ - time: i.time, - course: getCourse(i.lesson), - teacher: person.has(i.teacher) ? teacher(i.teacher) : teacherDummy(i.teacher) - }) - - const teacher = id => ({ - id: id, - url: `/teacher/${id}`, - name: personName(id) - }) - - const teacherDummy = name => ({ - id: name, - url: null, - name: name - }) - - const personName = id => person.has(id) ? person.get(id).name : null - - return Object.assign(schedule, { - version: '3.0', - groups: schedule.groups - .map(group => ({ - name: group.name, - time: group.time, - week: week(group.week) - })) - }) -} diff --git a/modules/hudozka-api/src/utils/common.ts b/modules/hudozka-api/src/utils/common.ts deleted file mode 100644 index a2ec4754..00000000 --- a/modules/hudozka-api/src/utils/common.ts +++ /dev/null @@ -1,106 +0,0 @@ -/** - * Generates list of numbers - * @param {Number} start starting value - * @param {Number} num amount of numbers in list - * @param {Number} step difference value - * @return {Array} list of numbers - */ -export function range(start, num, step) { - var list = []; - var val = start; - for (var i = 0; i < num; i++) { - list.push(val); - val += step; - } - return list; -} - -/** - * Return a closure that compares a Number argument with specified Number - * @param withNumber Number to compare with - * @returns {Function} (i) => {} - */ -export function numberEquals(withNumber) { - return i => i === withNumber; -} - -/** - * Return a closure that compares a second Number argument with specified Number - * @param withNumber Number to compare with - * @returns {Function} (i) => {} - */ -export function indexEquals(withNumber) { - return (_, i) => i === withNumber; -} - -/** - * Return a reduce function - * [['spring', 'Весена'], ['autumn', 'Осень']] -> 'Весна' or 'Осень' depend on byCondition result - * @param byCondition - * @param map - */ -export function select(byCondition, map = i => i) { - return (result, item) => byCondition(item) ? map(item) : map(result) -} - -/** - * Select an item in Array by specified selector function - * @param scope - * @param selector - * @returns {*} - */ -export function choise(scope, selector) { - return scope.reduce(selector, null); -} - -export function unique(fn: (value: T) => U): (list: T[]) => U[] { - return list => Array.from( - new Set(list.map(fn)) - ) -} - -export function branch(fn) { - let keys = unique(fn); - - return list => keys(list) - .reduce((dict: any, key: any) => { - dict[key] = list.filter( - i => fn(i) === key - ); - - return dict; - }, {}) - -} - -export function assign(dict, key, value) { - dict[key] = value; - return dict; -} - -export function map(v, fn) { - return value => fn(value) ? v : value; -} - -/** - * - * f(g, [x, y, z, ...]) => map of {g(x): x, g(y): y, g(z): z} - * - * @param list - * @param selector - * @returns {*} - */ -export function createMap(selector, list) { - return list.reduce((map, i) => map.set(selector(i), i), new Map()); -} - -/** - * - * f(g) => x ? g(x) : null - * - * @param {function} fn - * @returns {function(*=): null} - */ -export function nullSafe(fn) { - return i => i ? fn(i) : null; -} diff --git a/modules/hudozka-api/src/utils/date.js b/modules/hudozka-api/src/utils/date.js deleted file mode 100644 index 9bdac8af..00000000 --- a/modules/hudozka-api/src/utils/date.js +++ /dev/null @@ -1,21 +0,0 @@ -import {range} from './common'; - -/** - * - * @param start - * @returns {*} - */ -export function getDates(start) { - const oneDay = (1000 * 60 * 60 * 24); - const startTime = start.getTime(); - const startDay = start.getDay(); - - return range(0, 6, 1) - .reduce((dates, weekDay) => { - let delta = 1 + weekDay - startDay; - let time = startTime + (oneDay * delta); - - return dates.concat([new Date(time)]); - }, []) - .map(i => i.getDate()); -} \ No newline at end of file diff --git a/modules/hudozka-api/src/utils/fn.js b/modules/hudozka-api/src/utils/fn.js deleted file mode 100644 index caaf894a..00000000 --- a/modules/hudozka-api/src/utils/fn.js +++ /dev/null @@ -1,13 +0,0 @@ -/** - * - * f([x, y, z, ...]) -> f(v) -> {v.x, v.y, v.z} - * - * @param fields - * @returns {function(*): *} - */ -export function select(fields=[]){ - return i => fields.reduce((out, key) => { - out[key] = i[key]; - return out; - }, {}); -} diff --git a/modules/hudozka-api/src/utils/net.js b/modules/hudozka-api/src/utils/net.js deleted file mode 100644 index 623cab68..00000000 --- a/modules/hudozka-api/src/utils/net.js +++ /dev/null @@ -1,8 +0,0 @@ -export function query(list) { - return list - .reduce( - (query, param) => query.concat([`${param[0]}=${param[1]}`]), - [] - ) - .join('&'); -} diff --git a/modules/hudozka-api/src/utils/populate.js b/modules/hudozka-api/src/utils/populate.js deleted file mode 100644 index d5a50261..00000000 --- a/modules/hudozka-api/src/utils/populate.js +++ /dev/null @@ -1,35 +0,0 @@ -export function pop(data){ - var Populator = function(data){ - this.target = data; - } - - Populator.prototype = { - populate: function(p){ - var self = this; - if(typeof p == "function"){ - self.target = p(self.target); - }else if(p instanceof Array){ - p.forEach(function(i){ - self.target = self.populate(i).result(); - }); - - } - return self; - }, - result: function(){ - return this.target; - } - }; - - var fun = new Populator(data); - return fun; -} - -export function populate(fn, key){ - return (dict) => { - let id = dict[key]; - let value = fn(id); - dict[key] = value ? value : id; - return dict; - } -} \ No newline at end of file diff --git a/modules/hudozka-api/src/utils/sort.js b/modules/hudozka-api/src/utils/sort.js deleted file mode 100644 index 774b1adf..00000000 --- a/modules/hudozka-api/src/utils/sort.js +++ /dev/null @@ -1,26 +0,0 @@ -export function sortByPattern(list, pattern, map) { - let weight = i => { - const index = pattern.indexOf(map(i)) - return index > -1 ? pattern.length - index : 0 - } - - return sortByWeight(list, weight) -} - -export function sortByWeight(list, fn) { - return list - .map(i => [fn(i), i]) - .sort((a, b) => b[0] - a[0]) - .map(i => i[1]) -} - -export function sortBy(fn) { - return (i1, i2) => { - let t1 = fn(i1) - let t2 = fn(i2) - - if (t1 < t2) return 1 - if (t1 > t2) return -1 - return 0 - } -} diff --git a/modules/hudozka-api/src/utils/string.js b/modules/hudozka-api/src/utils/string.js deleted file mode 100644 index a5e7dace..00000000 --- a/modules/hudozka-api/src/utils/string.js +++ /dev/null @@ -1,22 +0,0 @@ -import {map} from './common'; - -/** - * Return a function that accept one String parameter and returns result of replacing. - * - * @param searchValue - * @param replaceValue - */ -export const stringReplace = (searchValue, replaceValue) => - str => str.replace(searchValue, replaceValue); - -let toTrue = map(true, i => i === 'true'); -let toFalse = map(false, i => i === 'false'); -const boolProcessors = [toTrue, toFalse]; - -export function stringToBoolean(string){ - return boolProcessors - .reduce( - (value, fn) => fn(value), - string - ); -} \ No newline at end of file From 9eb087bf6d1238329c795145bd3bcf949ef5e763 Mon Sep 17 00:00:00 2001 From: Roman Timashev Date: Tue, 3 Mar 2020 01:35:36 +0300 Subject: [PATCH 05/34] api tags controller simplified: rm tags/slug route --- modules/hudozka-api/src/controllers/tag.ts | 26 ---------------------- modules/hudozka-api/src/server.ts | 1 - 2 files changed, 27 deletions(-) diff --git a/modules/hudozka-api/src/controllers/tag.ts b/modules/hudozka-api/src/controllers/tag.ts index 4e5ca030..0185cbf8 100644 --- a/modules/hudozka-api/src/controllers/tag.ts +++ b/modules/hudozka-api/src/controllers/tag.ts @@ -20,29 +20,3 @@ export async function getAll(req: Request, res: Response) { }) } } - -export async function findItems(req: Request, res: Response) { - const slug = req.params.slug - - const data = await Page.find({ - tags: { - - } - - }) - const tags = data - .flatMap(x => x.tags) - .filter(x => x.isValid()) - const items = unique(tags, t => t.slug) - - if (data) { - res.json({ - items, - }) - } else { - res.status(404) - res.json({ - error: `Not found` - }) - } -} diff --git a/modules/hudozka-api/src/server.ts b/modules/hudozka-api/src/server.ts index 458a4bbe..21104af6 100644 --- a/modules/hudozka-api/src/server.ts +++ b/modules/hudozka-api/src/server.ts @@ -33,7 +33,6 @@ async function main() { app.get('/image', image.getItem) app.get('/tags', tag.getAll) - app.get('/tags/:slug', tag.findItems) app.listen(port, () => { console.log(`> Ready on http://localhost:${port}`) From 6b6eca5f8d366bbf6772817d18a36f5383dcaf6a Mon Sep 17 00:00:00 2001 From: Roman Timashev Date: Tue, 3 Mar 2020 01:59:55 +0300 Subject: [PATCH 06/34] sync drop Article model --- modules/sync/settings.py | 3 - modules/sync/sync.py | 9 -- modules/sync/sync/models/Article.py | 186 ---------------------------- 3 files changed, 198 deletions(-) delete mode 100644 modules/sync/sync/models/Article.py diff --git a/modules/sync/settings.py b/modules/sync/settings.py index 547f70a1..bff13c45 100644 --- a/modules/sync/settings.py +++ b/modules/sync/settings.py @@ -78,10 +78,8 @@ origin = value('origin') collection_images = 'images' collection_documents = 'documents' -collection_articles = 'articles' collection_pages = 'pages' -hash_salt_articles = '8' hash_salt_pages = '4' hash_salt_documents = '4' hash_salt_images = '5' @@ -91,7 +89,6 @@ provider_root = value('provider')['root'] # env('SYNC_PROVIDER', 'fs') f = abs_fn(provider_root) -dir_articles = './Articles' dir_pages = './Pages' document_url_template = 'https://static.shlisselburg.org/art/uploads/{file}' diff --git a/modules/sync/sync.py b/modules/sync/sync.py index 5b59c929..0e14cdde 100644 --- a/modules/sync/sync.py +++ b/modules/sync/sync.py @@ -6,7 +6,6 @@ from sync.data.yandexdisk import YDProvider import asyncio import logging -from sync.models.Article import Article from sync.models.Page import Page @@ -46,17 +45,9 @@ async def run(run_interval=0): ) sync_pages.set_options(True, True, True) - sync_articles = Sync( - provider=io(settings.provider_root), - model=Article, - ) - sync_articles.set_options(True, True, True) - sync_articles.validate_urls = False - while True: await asyncio.wait([ run_sync(sync_pages), - run_sync(sync_articles), ]) if run_interval == 0: diff --git a/modules/sync/sync/models/Article.py b/modules/sync/sync/models/Article.py deleted file mode 100644 index 40d003ce..00000000 --- a/modules/sync/sync/models/Article.py +++ /dev/null @@ -1,186 +0,0 @@ -import logging - -import os - -import kazimir -import settings -from db import collection -from markdown import markdown -from sync import create_date_and_title_from_folder_name, create_date, create_post -from sync.data import list_images -from sync.models import Model -from sync.models.Image import Image - -from utils.fn import first, combine -from utils.hash import hash_str -from utils.io import parse_yaml_front_matter -from utils.text.transform import url_encode_text - -logger = logging.getLogger(settings.name + '.Article') -store = collection(settings.collection_articles) - - -class Article(Model): - @staticmethod - async def find(query): - return store.find(query) - - @staticmethod - async def delete(query): - return store.find_one_and_delete(query) - - @staticmethod - async def scan(provider): - scan_dir = settings.dir_articles - documents = [i for i in provider.scan(scan_dir) if provider.is_dir(i)] - documents = [Article.read(provider, i) for i in documents] - return documents - - @staticmethod - def read(provider, path): - file_time_formats = ['%Y.%m.%d'] - - # PARSE FOLDER NAME -> GET OPTIONAL DATE/TITLE - doc_date, doc_title = create_date_and_title_from_folder_name(path, file_time_formats) - document = { - 'folder': path, - 'date': doc_date, - 'title': doc_title, - } - - # TRY TO FILL UP BASIC_MANIFEST WITH MD_MANIFEST - manifest_file = md_from_folder(provider, path) - if manifest_file: - manifest = read_manifest(provider, manifest_file) - else: - manifest = {} - - return Article( - provider, - path, - params={ - **document, - **manifest, - }, - ) - - def __init__(self, provider, file, params=None): - self.hash_salt = settings.hash_salt_articles - self.version = '2' - self.post = None - self.preview = None - self.images = None - self.documents = None - self.tokens = None - super().__init__(provider, store, file, params=params) - - def init(self): - if self.has_param('content'): - images, documents = kazimir.extract_files(self.get_param('content')) - else: - images = list_images(self.provider, self.file) - images = [os.path.relpath(i, self.file) for i in images] - documents = [] - self.params['images'] = images - self.params['documents'] = documents - - self.__set_id() - self.__set_hash() - self.origin = settings.origin - - def validate(self): - document = self.params - if 'date' not in document or not document['date']: - return None - - if 'title' not in document or not document['title']: - return None - - async def build(self, **kwargs): - sizes = kwargs['sizes'] - - if self.has_param('content'): - markdown_post = self.get_param('content') - else: - markdown_post = create_post_from_image_list(self.get_param('images')) - - post, images, documents, tokens = await create_post(self.provider, self.get_param('folder'), markdown_post, sizes) - self.post = post - self.images = images - self.documents = documents - self.tokens = tokens - - if self.has_param('preview'): - preview = self.get_param('preview') - preview = self._get_relpath(preview) - self.preview = await Image.new(self.provider, preview, sizes) - - def bake(self): - return { - **self.params, - 'images': [x.ref for x in self.images], - 'documents': [x.ref for x in self.documents], - 'post': self.post, - 'id': self.id, - 'hash': self.hash, - 'file': self.file, - 'origin': self.origin, - 'version': self.version, - 'tokens': self.tokens, - 'preview': self.preview.ref if self.preview else None, - } - - def __set_id(self): - if 'id' in self.params: - self.id = self.params['id'] - else: - self.id = url_encode_text(self.params['title']) - - def __set_hash(self): - files = [] - files += sorted(self.get_param('images')) - files += sorted(self.get_param('documents')) - if self.has_param('preview'): - files.append(self.get_param('preview')) - - folder = self.get_param('folder') - files = [os.path.join(folder, x) for x in files] - files = [self.provider.hash(x) for x in files] - - self.hash = hash_str( - combine([self.hash_salt] + [hash_str(self.params)] + files) - ) - - def __str__(self): - return f'
' - - -def md_from_folder(provider, i): - return first(provider.type_filter(i, '.md')) - - -def read_manifest(provider, path): - data = provider.read(path).read().decode('utf-8') - manifest = parse_yaml_front_matter(data) - - if 'date' in manifest: - manifest['date'] = create_date(manifest['date'], settings.date_formats) - - if 'until' in manifest: - manifest['until'] = create_date(manifest['until'], settings.date_formats) - - if 'id' in manifest: - manifest['id'] = str(manifest['id']) - - return { - **manifest, - } - - -def create_post_from_image_list(images): - return markdown( - '\n'.join(map( - lambda i: '![]({img})'.format(img=i), - images - )) - ) From 92b64808ea5527e0bc0c2d8e607c7e90847fca6e Mon Sep 17 00:00:00 2001 From: Roman Timashev Date: Tue, 3 Mar 2020 02:01:17 +0300 Subject: [PATCH 07/34] sync Page logger warning add --- modules/sync/sync/models/Page.py | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/sync/sync/models/Page.py b/modules/sync/sync/models/Page.py index e72923d4..a4c60a27 100644 --- a/modules/sync/sync/models/Page.py +++ b/modules/sync/sync/models/Page.py @@ -64,6 +64,7 @@ class Page(Model): manifest_path = manifest_file('.md') if not provider.exists(manifest_path): + logger.warning(f'Manifest not found on path {manifest_path}') return None params = { From 5610e50863d94dd8534d29d4422957a2cdeab3c3 Mon Sep 17 00:00:00 2001 From: Roman Timashev Date: Tue, 3 Mar 2020 02:22:33 +0300 Subject: [PATCH 08/34] sync drop dead code --- modules/sync/sync/__init__.py | 34 -------------------------------- modules/sync/sync/models/Page.py | 9 +-------- modules/sync/utils/validation.py | 11 ----------- 3 files changed, 1 insertion(+), 53 deletions(-) delete mode 100644 modules/sync/utils/validation.py diff --git a/modules/sync/sync/__init__.py b/modules/sync/sync/__init__.py index 209d6afe..4886435d 100644 --- a/modules/sync/sync/__init__.py +++ b/modules/sync/sync/__init__.py @@ -45,12 +45,6 @@ def create_date(date_str, date_formats=None): return None -# 2016 На крыльях бабочек -# 2016.10 На крыльях бабочек -# 2016.10.10 На крыльях бабочек -folder_name_pattern = re.compile('([\d.]+)(.*)') - - async def untouched(items: [Model]) -> [Model]: if settings.skip_unchanged: return items @@ -73,21 +67,6 @@ async def untouched(items: [Model]) -> [Model]: # return filtered_documents -def create_date_and_title_from_folder_name(folder_name, date_formats=None): - m = folder_name_pattern.findall(folder_name) - if not m: - return None, None - - date_str, title = m[0] - title = os.path.splitext(title.strip())[0] - date = create_date(date_str, date_formats) - - if not date: - return None, title - - return date, title - - async def create_post(provider: Provider, folder: str, md: str, sizes): from kazimir.fix_links_quotes import fix_links_quotes @@ -171,19 +150,6 @@ async def create_post(provider: Provider, folder: str, md: str, sizes): return post, images, documents, encoded_tokens -def images_from_html(md): - if not md: - return [] - - post_html = lxml.html.fromstring(md) - - images = [] - for img in post_html.cssselect('img'): - src = img.get('src') - images.append(src) - return images - - def title_from_html(md): html = lxml.html.fromstring(md) titles = html.cssselect('h1') diff --git a/modules/sync/sync/models/Page.py b/modules/sync/sync/models/Page.py index a4c60a27..4b72439c 100644 --- a/modules/sync/sync/models/Page.py +++ b/modules/sync/sync/models/Page.py @@ -11,7 +11,7 @@ from db import collection from sync.data import request from sync.models import Model -from sync import create_date, images_from_html, title_from_html, create_post +from sync import create_date, title_from_html, create_post from sync.models.Image import Image from utils.hash import hash_str from utils.io import parse_yaml_front_matter @@ -174,9 +174,6 @@ class Page(Model): files = [] files += self.get_param('images') files += self.get_param('documents') - if self.has_param('contentFile'): - files += [self.get_param('contentFile')] - folder = self.get_param('folder') files = [os.path.join(folder, x) for x in files] files = sorted([self.file] + files) @@ -201,8 +198,4 @@ def get_manifest(provider, path): if 'id' in manifest: manifest['id'] = str(manifest['id']) - if 'contentFile' in manifest: - dirname = os.path.dirname(path) - manifest['contentHtml'] = provider.read(os.path.join(dirname, manifest['contentFile'])).read().decode('utf-8') - return manifest diff --git a/modules/sync/utils/validation.py b/modules/sync/utils/validation.py deleted file mode 100644 index 547eefd5..00000000 --- a/modules/sync/utils/validation.py +++ /dev/null @@ -1,11 +0,0 @@ -import os -import re -import settings - -__author__ = 'Roman Timashev' - -__check_description_filename_exp = re.compile('^[%s]+(\[\d+\])\.md$' % settings.description_available_chars) - - -def check_description_filename(filename): - return __check_description_filename_exp.match(filename) From b680cba50c91419b5d287e4fe6694d0acab3a182 Mon Sep 17 00:00:00 2001 From: Roman Timashev Date: Tue, 3 Mar 2020 02:24:10 +0300 Subject: [PATCH 09/34] drop article page --- pages/article/[slug].tsx | 85 ---------------------------------------- 1 file changed, 85 deletions(-) delete mode 100644 pages/article/[slug].tsx diff --git a/pages/article/[slug].tsx b/pages/article/[slug].tsx deleted file mode 100644 index f8deabe6..00000000 --- a/pages/article/[slug].tsx +++ /dev/null @@ -1,85 +0,0 @@ -import Head from 'next/head' -import { App } from 'src/components/App' -import { Article } from 'src/components/Article' -import { Html } from 'src/components/Html' -import { Meta } from 'src/components/Meta' -import { MetaBuilder } from 'src/lib/meta' -import { createApiUrl, requestGet, IResponseItems } from 'src/next-lib' -import { NextPage } from 'next' -import { IArticle, IMeta } from 'src/types' - -type Props = { - title: string - meta: IMeta - data: IArticle -} - -const Page: NextPage = props => { - if (!props.data) { - console.log('kek error', props) - return null - } - - return ( - - - {props.title} - - -
- -
-
- ) -} - -export const unstable_getStaticProps = async (ctx: any) => { - const id = ctx.params.slug - const data = await requestGet(createApiUrl(`/api/articles/${id}`), null) - if (!data) { - return null - } - - const meta = (new MetaBuilder()) - .setImage(data.preview) - .setTitle(data.title) - .build() - - return { - props: { - title: data.title, - data, - meta, - } - } -} - -export const unstable_getStaticPaths = async () => { - const urls = await requestGet>(createApiUrl(`/api/articles/urls`), null) - if (!urls) { - return null - } - - return { - paths: urls.items - .map(x => x.replace('/article/', '')) - .map(slug => { - return { - params: { - slug, - }, - } - }), - } -} - -export default Page From ee5cba3634300395a8db109f577c43d911471f74 Mon Sep 17 00:00:00 2001 From: Roman Timashev Date: Tue, 3 Mar 2020 02:24:24 +0300 Subject: [PATCH 10/34] drop Article component --- src/components/Article/index.tsx | 55 -------------------------------- 1 file changed, 55 deletions(-) delete mode 100644 src/components/Article/index.tsx diff --git a/src/components/Article/index.tsx b/src/components/Article/index.tsx deleted file mode 100644 index 90f4461c..00000000 --- a/src/components/Article/index.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import { dateFormat } from 'src/lib/date' -import { Share } from '../Share' -import { TagList } from '../TagList' -import { ITag } from 'src/types' - -export type ArticleProps = { - date: string - title: string - tags: ITag[] - shareable: boolean -} - -type HeadProps = { - date: string - tags: ITag[] -} - -const Head: React.FC = ({ date, tags = [], children }) => ( -
- - -

{children}

- - {!date ? null : ( -

Опубликовано: {dateFormat(date)}

- )} - - {!tags.length ? null : ( - - )} -
-) - -export const Article: React.FC = ({ children, date, tags, title, shareable }) => ( -
- - {title} - - -
- {children} -
- - {!shareable ? null : ( - - )} -
-) From 9a105ba45e48bc45394dc28cbb5c473670e3a8fe Mon Sep 17 00:00:00 2001 From: Roman Timashev Date: Tue, 3 Mar 2020 02:25:07 +0300 Subject: [PATCH 11/34] page update --- pages/[...slug].tsx | 9 +++++++-- src/components/Page/index.tsx | 25 +++++++++++++++++++++---- src/components/PageHeader/index.tsx | 22 ---------------------- src/components/PageMeta/index.tsx | 23 +++++++++++++++++++++++ src/components/PageMeta/styles.css | 5 +++++ src/components/TagList/index.tsx | 10 ++++++++-- src/style/components/Article.scss | 4 ---- src/types.ts | 2 ++ 8 files changed, 66 insertions(+), 34 deletions(-) delete mode 100644 src/components/PageHeader/index.tsx create mode 100644 src/components/PageMeta/index.tsx create mode 100644 src/components/PageMeta/styles.css diff --git a/pages/[...slug].tsx b/pages/[...slug].tsx index e632e75f..b5e261df 100644 --- a/pages/[...slug].tsx +++ b/pages/[...slug].tsx @@ -6,7 +6,7 @@ import { Meta } from 'src/components/Meta' import { MetaBuilder } from 'src/lib/meta' import { createApiUrl, requestGet, IResponseItems } from 'src/next-lib' import { NextPage } from 'next' -import { IBreadcumbsPart, IMeta, IPage } from 'src/types' +import { IBreadcumbsPart, IMeta, IPage, ITag } from 'src/types' function array(value: T | T[]) { return Array.isArray(value) @@ -16,6 +16,8 @@ function array(value: T | T[]) { type Props = { title: string + tags: ITag[] + date: string content: string breadcrumb: IBreadcumbsPart[] meta?: IMeta @@ -37,7 +39,8 @@ const Index: NextPage = props => ( {props.content} @@ -68,6 +71,8 @@ export const unstable_getStaticProps = async (ctx: any) => { props: { content: page.data, title: page.title, + tags: page.tags, + date: page.date, meta, breadcrumb, } diff --git a/src/components/Page/index.tsx b/src/components/Page/index.tsx index 5fcf8f0d..09176002 100644 --- a/src/components/Page/index.tsx +++ b/src/components/Page/index.tsx @@ -1,21 +1,38 @@ import { Share } from '../Share' import { Html } from '../Html' +import { PageMeta } from '../PageMeta' +import { ITag } from 'src/types' export interface IPageProps { - showSocialShare: boolean children: string + date: Date + tags: ITag[] } export const Page: React.FC = props => (
+
- {!props.showSocialShare ? null : ( - - )} +
+ + +
) diff --git a/src/components/PageHeader/index.tsx b/src/components/PageHeader/index.tsx deleted file mode 100644 index 6dbcd894..00000000 --- a/src/components/PageHeader/index.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import * as React from 'react' -import { dateFormat } from '../../lib/date' - -export interface IPageHeaderProps { - tags?: string[] - date?: Date - title: string -} - -export const PageHeader: React.FC = props => ( -
-

{props.title}

- - {!props.date ? null : ( -

{dateFormat(props.date)}

- )} - - {/* {!(tags.length) ? null : ( - - )} */} -
-) diff --git a/src/components/PageMeta/index.tsx b/src/components/PageMeta/index.tsx new file mode 100644 index 00000000..4a0fc8c0 --- /dev/null +++ b/src/components/PageMeta/index.tsx @@ -0,0 +1,23 @@ +import './styles.css' + +import { dateFormat } from 'src/lib/date' +import { ITag } from 'src/types' +import { TagList } from '../TagList' + +export type PageMetaProps = { + style?: React.CSSProperties + date?: Date + tags?: ITag[] +} + +export const PageMeta: React.FC = props => ( +
+ {!props.date ? null : ( +

Опубликовано: {dateFormat(props.date)}

+ )} + + {!(props.tags.length) ? null : ( + + )} +
+) diff --git a/src/components/PageMeta/styles.css b/src/components/PageMeta/styles.css new file mode 100644 index 00000000..fa1c61b1 --- /dev/null +++ b/src/components/PageMeta/styles.css @@ -0,0 +1,5 @@ +.pageMeta { + display: flex; + align-items: center; + justify-content: space-between; +} diff --git a/src/components/TagList/index.tsx b/src/components/TagList/index.tsx index 644ed604..3b72b3b8 100644 --- a/src/components/TagList/index.tsx +++ b/src/components/TagList/index.tsx @@ -5,7 +5,13 @@ import { Button } from '../Button' export const Tag: React.FC<{ href: string }> = props => (
  • - +
  • ) @@ -20,7 +26,7 @@ export const TagList: React.FC = props => ( key={x.slug} href={x.href} > - # {x.name} + {x.name} ))} diff --git a/src/style/components/Article.scss b/src/style/components/Article.scss index 02aacff5..79100fa9 100644 --- a/src/style/components/Article.scss +++ b/src/style/components/Article.scss @@ -6,10 +6,6 @@ hyphens: auto; margin-bottom: var(--post-margin); - &-Head { - margin-bottom: 1.25em; - } - h1 { margin-bottom: var(--size-s); } diff --git a/src/types.ts b/src/types.ts index 7fe64ce1..11d3d5da 100644 --- a/src/types.ts +++ b/src/types.ts @@ -13,9 +13,11 @@ export interface IPage { title: string url: string data: string + date: string preview: ImageDefinition description: string tokens: any[] + tags: ITag[] breadcrumb?: IBreadcumbsPart[] } From 85d2f7cc45a40ab433d10494d897c4b0435e6c70 Mon Sep 17 00:00:00 2001 From: Roman Timashev Date: Tue, 3 Mar 2020 02:31:07 +0300 Subject: [PATCH 12/34] drop articles pages --- pages/articles/[slug].tsx | 93 --------------------------------------- 1 file changed, 93 deletions(-) delete mode 100644 pages/articles/[slug].tsx diff --git a/pages/articles/[slug].tsx b/pages/articles/[slug].tsx deleted file mode 100644 index 4d31efc9..00000000 --- a/pages/articles/[slug].tsx +++ /dev/null @@ -1,93 +0,0 @@ -import Head from 'next/head' -import { range } from 'lodash' -import { App } from 'src/components/App' -import { ArticleGrid } from 'src/components/ArticleGrid' -import { MetaBuilder } from 'src/lib/meta' -import { Meta } from 'src/components/Meta' -import { createApiUrl, requestGet, IResponseItems } from 'src/next-lib' -import { NextPage } from 'next' -import { IArticle } from 'src/types' - -const pageSize = Number(process.env.APP_ARTICLES_PAGE_SIZE) - -type Props = { - meta: any - title: string - data: IArticle[] - nextPage: number - prevPage: number -} - -const Page: NextPage = props => { - if (!props.data) { - console.log('kek error', props) - return null - } - - return ( - - - {props.title} - - - - - ) -} - -export const unstable_getStaticProps = async (ctx: any) => { - const page = parseInt(ctx.params.slug) - const res = await requestGet>(createApiUrl(`/api/articles?page=${page}&pageSize=${pageSize}`), null) - if (!res) { - return null - } - - const data = (res.items || []) - const nextPage = res.nextPage - const prevPage = res.prevPage - const title = 'События' - const meta = (new MetaBuilder()) - .setTitle(title) - .build() - - return { - props: { - data, - nextPage, - prevPage, - title, - meta, - } - } -} - -export const unstable_getStaticPaths = async () => { - const urls = await requestGet>(createApiUrl(`/api/articles/urls`), null) - if (!urls) { - return null - } - - const count = urls.items.length - const pages = Math.ceil(count / pageSize) - - return { - paths: range(1, pages + 1) - .map(i => { - return { - params: { - slug: `${i}`, - }, - } - }), - } -} - - -export default Page From 970bdce53d01e27194317861511d8c1438b705c5 Mon Sep 17 00:00:00 2001 From: Roman Timashev Date: Tue, 3 Mar 2020 02:31:42 +0300 Subject: [PATCH 13/34] index page updated; ArticleGrid -> PageGrid --- pages/index.tsx | 34 ++++++++++++++----- .../{ArticleGrid => PageGrid}/Date.tsx | 0 .../{ArticleGrid => PageGrid}/index.tsx | 28 +++++++-------- src/types.ts | 28 +-------------- 4 files changed, 40 insertions(+), 50 deletions(-) rename src/components/{ArticleGrid => PageGrid}/Date.tsx (100%) rename src/components/{ArticleGrid => PageGrid}/index.tsx (77%) diff --git a/pages/index.tsx b/pages/index.tsx index 64e2f261..ccc3f334 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -1,19 +1,19 @@ import Head from 'next/head' import { App } from 'src/components/App' import { Meta } from 'src/components/Meta' -import { ArticleGrid } from 'src/components/ArticleGrid' +import { PageGrid } from 'src/components/PageGrid' import { HudozkaTitle } from 'src/components/HudozkaTitle' -import { meta, MetaBuilder } from 'src/lib/meta' +import { MetaBuilder } from 'src/lib/meta' import { createApiUrl, requestGet, IResponseItems } from 'src/next-lib' import { NextPage } from 'next' -import { IArticle } from 'src/types' +import { IPage } from 'src/types' interface IProps { title: string meta: any prevPage: number nextPage: number - articles: any[] + items: any[] } const Page: NextPage = props => ( @@ -32,8 +32,8 @@ const Page: NextPage = props => ( }} /> - @@ -42,10 +42,26 @@ const Page: NextPage = props => ( export const unstable_getStaticProps = async () => { const page = 1 - const pageSize = process.env.APP_ARTICLES_PAGE_SIZE - const res = await requestGet>(createApiUrl(`/api/articles?page=${page}&pageSize=${pageSize}`), null) + // const pageSize = parseInt(process.env.APP_ARTICLES_PAGE_SIZE) + const pageSize = 300 + + const limit = pageSize + const skip = (page - 1) * pageSize + + const tags = [ + 'event', + 'album', + 'post', + ] + const tagQuery = tags + .map(x => `tag=${x}`) + .join('&') + + const url = `/api/pages/tags?${tagQuery}&skip=${skip}&limit=${limit}&sortBy=-date` + const res = await requestGet>(createApiUrl(url), null) const articles = (res.items || []) - const nextPage = res.nextPage + // const nextPage = res.nextPage + const nextPage = 2 const prevPage = res.prevPage const title = 'Шлиссельбургская ДХШ' const meta = (new MetaBuilder()) diff --git a/src/components/ArticleGrid/Date.tsx b/src/components/PageGrid/Date.tsx similarity index 100% rename from src/components/ArticleGrid/Date.tsx rename to src/components/PageGrid/Date.tsx diff --git a/src/components/ArticleGrid/index.tsx b/src/components/PageGrid/index.tsx similarity index 77% rename from src/components/ArticleGrid/index.tsx rename to src/components/PageGrid/index.tsx index c9523ebe..9466e99a 100644 --- a/src/components/ArticleGrid/index.tsx +++ b/src/components/PageGrid/index.tsx @@ -1,4 +1,4 @@ -import { IArticle, ImageDefinition } from 'src/types' +import { ImageDefinition, IPage } from 'src/types' import { Pager } from '../Pager' import { CardGrid } from '../CardGrid' import { Card, CardLayout } from '../Card' @@ -47,13 +47,13 @@ function getImage(image?: ImageDefinition) { } } -export type ArticleGridProps = { - articles: IArticle[] +export type PageGridProps = { + items: IPage[] nextPage: number | null prevPage: number | null } -export const ArticleGrid: React.FC = ({ articles, nextPage, prevPage, ...props }) => { +export const PageGrid: React.FC = ({ items, nextPage, prevPage, ...props }) => { const nextHref = nextPage ? `/articles/${nextPage}` : null let prevHref = prevPage ? `/articles/${prevPage}` : null if (prevPage === 1) { @@ -67,32 +67,32 @@ export const ArticleGrid: React.FC = ({ articles, nextPage, pr marginBottom: 'var(--size-m)', }} > - {articles.map((article, i) => { - const gridColumn = article.featured ? 'span 2' : 'auto' - const layout: CardLayout = article.featured ? 'featured' : 'simple' - const { src, srcSet } = getImage(article.preview) + {items.map((item, i) => { + const gridColumn = item.featured ? 'span 2' : 'auto' + const layout: CardLayout = item.featured ? 'featured' : 'simple' + const { src, srcSet } = getImage(item.preview) - const content = !article.featured + const content = !item.featured ? ( - {article.title} + {item.title} {article.date} + }}>{item.date} ) : ( - article.title + item.title ) return ( Date: Tue, 3 Mar 2020 02:38:22 +0300 Subject: [PATCH 14/34] page fix --- pages/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pages/index.tsx b/pages/index.tsx index ccc3f334..d8f4073a 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -59,7 +59,7 @@ export const unstable_getStaticProps = async () => { const url = `/api/pages/tags?${tagQuery}&skip=${skip}&limit=${limit}&sortBy=-date` const res = await requestGet>(createApiUrl(url), null) - const articles = (res.items || []) + const items = (res.items || []) // const nextPage = res.nextPage const nextPage = 2 const prevPage = res.prevPage @@ -73,7 +73,7 @@ export const unstable_getStaticProps = async () => { return { props: { - articles, + items, nextPage, prevPage, title, From 23835c27c95e0616494fc9efaa9c94a86eef7dbe Mon Sep 17 00:00:00 2001 From: Roman Timashev Date: Tue, 3 Mar 2020 02:51:14 +0300 Subject: [PATCH 15/34] moment -> date-fns --- package-lock.json | 10 +++++----- package.json | 2 +- src/lib/date.ts | 12 ++++++++---- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/package-lock.json b/package-lock.json index 42474ac8..9743d7e2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3102,6 +3102,11 @@ } } }, + "date-fns": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.10.0.tgz", + "integrity": "sha512-EhfEKevYGWhWlZbNeplfhIU/+N+x0iCIx7VzKlXma2EdQyznVlZhCptXUY+BegNpPW2kjdx15Rvq503YcXXrcA==" + }, "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", @@ -6338,11 +6343,6 @@ } } }, - "moment": { - "version": "2.24.0", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", - "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==" - }, "move-concurrently": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", diff --git a/package.json b/package.json index c13e7f2d..24df73fb 100644 --- a/package.json +++ b/package.json @@ -21,8 +21,8 @@ "dependencies": { "axios": "^0.19.0", "classnames": "^2.2.6", + "date-fns": "^2.10.0", "lodash": "^4.17.15", - "moment": "^2.24.0", "next": "^9.2.2", "react": "^16.12.0", "react-dom": "^16.12.0", diff --git a/src/lib/date.ts b/src/lib/date.ts index 2d5b7473..dc9d6ea6 100644 --- a/src/lib/date.ts +++ b/src/lib/date.ts @@ -1,13 +1,17 @@ -import moment from 'moment' -moment.locale('ru') +import format from 'date-fns/format' +import { ru } from 'date-fns/locale' /** * - * Date -> DD.MM.YYYY + * Date -> D MMMM yyyy * * @param date */ -export const dateFormat = (date: string | Date) => moment(date).format('L') +export const dateFormat = (date: string | Date) => { + return format(new Date(2014, 6, 2), "d MMMM yyyy", { + locale: ru + }) +} /** * From 44973faea33c4dd8fee6de136e77cb74498c9503 Mon Sep 17 00:00:00 2001 From: Roman Timashev Date: Tue, 3 Mar 2020 03:05:05 +0300 Subject: [PATCH 16/34] PageMeta stability improve --- src/components/PageMeta/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/PageMeta/index.tsx b/src/components/PageMeta/index.tsx index 4a0fc8c0..d1db7c94 100644 --- a/src/components/PageMeta/index.tsx +++ b/src/components/PageMeta/index.tsx @@ -16,7 +16,7 @@ export const PageMeta: React.FC = props => (

    Опубликовано: {dateFormat(props.date)}

    )} - {!(props.tags.length) ? null : ( + {!(props.tags?.length) ? null : ( )} From 79a127636cf33b89c77da67ddb307169a19acdb4 Mon Sep 17 00:00:00 2001 From: Roman Timashev Date: Tue, 3 Mar 2020 03:05:18 +0300 Subject: [PATCH 17/34] drop articles from sitemap --- scripts/sitemap.js | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/scripts/sitemap.js b/scripts/sitemap.js index 6e20847e..415169d9 100644 --- a/scripts/sitemap.js +++ b/scripts/sitemap.js @@ -30,20 +30,10 @@ async function getPageUrls(frequency = 'daily') { })) } -async function getArticleUrls() { - const res = await api.get('/api/articles/urls') - - return res.data.items.map(url => ({ - changefreq: 'monthly', - url, - })) -} - (async () => { let urls = await Promise.all([ getMenuUrls(), getPageUrls(), - getArticleUrls(), ]) urls = urls.reduce((urls, i) => urls.concat(i)) From 0b230a26b4d01f9e11edc4df2b62d3fef8b8259d Mon Sep 17 00:00:00 2001 From: Roman Timashev Date: Tue, 3 Mar 2020 03:05:34 +0300 Subject: [PATCH 18/34] feed generator updated to tags --- scripts/feed.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/scripts/feed.js b/scripts/feed.js index 65e766b5..1e0baedc 100644 --- a/scripts/feed.js +++ b/scripts/feed.js @@ -6,9 +6,12 @@ const api = axios.create({ baseURL: 'https://api.tmshv.com/hudozka', }) -async function getArticles(pageSize) { - const page = 1 - const res = await api.get(`/api/articles?page=${page}&pageSize=${pageSize}`) +async function getArticles(limit) { + const query = ['post', 'event', 'album'] + .map(t => `tag=${t}`) + .join('&') + const url = `/api/pages/tags?${query}&sortBy=-date&skip=0&pageSize=${limit}` + const res = await api.get(url) return res.data.items } @@ -32,7 +35,7 @@ async function getArticles(pageSize) { date: new Date(article.date), id: article.id, link: article.url, - content: article.post, + content: article.data, }) }) From 9fb6eaab6605563609914e2c6e0978ef37017aef Mon Sep 17 00:00:00 2001 From: Roman Timashev Date: Tue, 3 Mar 2020 04:00:59 +0300 Subject: [PATCH 19/34] dateFormat fix --- src/lib/date.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib/date.ts b/src/lib/date.ts index dc9d6ea6..ff61c6ae 100644 --- a/src/lib/date.ts +++ b/src/lib/date.ts @@ -8,7 +8,8 @@ import { ru } from 'date-fns/locale' * @param date */ export const dateFormat = (date: string | Date) => { - return format(new Date(2014, 6, 2), "d MMMM yyyy", { + const value = typeof date === 'string' ? new Date(date) : date + return format(value, "d MMMM yyyy", { locale: ru }) } From 09b41182ce6799b63ebf19af719c8a98638d4196 Mon Sep 17 00:00:00 2001 From: Roman Timashev Date: Tue, 3 Mar 2020 04:01:11 +0300 Subject: [PATCH 20/34] PageMeta update text --- src/components/PageMeta/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/PageMeta/index.tsx b/src/components/PageMeta/index.tsx index d1db7c94..d3c18f81 100644 --- a/src/components/PageMeta/index.tsx +++ b/src/components/PageMeta/index.tsx @@ -13,7 +13,7 @@ export type PageMetaProps = { export const PageMeta: React.FC = props => (
    {!props.date ? null : ( -

    Опубликовано: {dateFormat(props.date)}

    +

    Опубликовано {dateFormat(props.date)}

    )} {!(props.tags?.length) ? null : ( From a15f0309564a8fe1d2314a9c4d2b273e0b3e5425 Mon Sep 17 00:00:00 2001 From: Roman Timashev Date: Tue, 3 Mar 2020 05:24:53 +0300 Subject: [PATCH 21/34] sync rm unused get_id function --- modules/sync/sync/core/__init__.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/modules/sync/sync/core/__init__.py b/modules/sync/sync/core/__init__.py index 96dedf44..03be9576 100644 --- a/modules/sync/sync/core/__init__.py +++ b/modules/sync/sync/core/__init__.py @@ -5,13 +5,6 @@ from sync import untouched from sync.data import Provider -def get_id(item): - try: - return item.id - except AttributeError: - return item['id'] - - class Sync: def __init__(self, provider: Provider, model): super().__init__() From 5e8ee6eec97c7e402efdb061dbe803469242449e Mon Sep 17 00:00:00 2001 From: Roman Timashev Date: Tue, 3 Mar 2020 05:25:15 +0300 Subject: [PATCH 22/34] showAuthor defaults --- pages/[...slug].tsx | 1 - src/components/App/index.tsx | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/pages/[...slug].tsx b/pages/[...slug].tsx index b5e261df..2c577e48 100644 --- a/pages/[...slug].tsx +++ b/pages/[...slug].tsx @@ -25,7 +25,6 @@ type Props = { const Index: NextPage = props => ( import('../Navigation').then(mod => mod.Navigat }) export interface IAppProps { - showAuthor: boolean + showAuthor?: boolean wide?: boolean contentStyle?: React.CSSProperties breadcrumbs?: IBreadcumbsPart[] } -export const App: React.FC = props => { +export const App: React.FC = ({ showAuthor = false, ...props }) => { const hideBreadcrumbs = useMobile() const router = useRouter() const wide = props.wide ?? false @@ -51,7 +51,7 @@ export const App: React.FC = props => { )} footer={(