diff --git a/modules/hudozka-api/src/controllers/file.ts b/modules/hudozka-api/src/controllers/file.ts index 503574a8..e0a9b69b 100644 --- a/modules/hudozka-api/src/controllers/file.ts +++ b/modules/hudozka-api/src/controllers/file.ts @@ -1,35 +1,16 @@ import { Request, Response } from 'express' import Document from '../core/Document' -import { encodeFile } from '../factory/file' +import { encodeFile, encodeFileUrl } from '../factory/file' export async function getItem(req: Request, res: Response) { - const id = req.params.slug - const document = await Document.findById(id) - - if (document) { - res.json(encodeFile(document)) + const slug = req.params.slug + const item = await Document.findBySlug(slug) + if (item) { + res.json(encodeFile(item)) } else { res.status(404) res.json({ - error: `Resource ${id} not found` - }) - } -} - -export async function getAll(req: Request, res: Response) { - 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: `Not found` + error: `Resource ${slug} not found` }) } } @@ -38,7 +19,7 @@ export async function getUrls(req: Request, res: Response) { const data = await Document.find({}) if (data) { - const items = data.map(x => `/document/${x.id}`) + const items = data.map(encodeFileUrl) res.json({ items }) diff --git a/modules/hudozka-api/src/controllers/image.ts b/modules/hudozka-api/src/controllers/image.ts index 569fbcb6..24d303d4 100644 --- a/modules/hudozka-api/src/controllers/image.ts +++ b/modules/hudozka-api/src/controllers/image.ts @@ -1,11 +1,33 @@ import Image from '../core/Image' import { encodeImage } from '../factory/image' import { Request, Response } from 'express' +import { oid } from '../db' export async function getItem(req: Request, res: Response) { + const slug = req.params.slug + const id = oid(slug) + if (!id) { + res.status(400) + return res.json({ + error: `Failed to parse ${slug} as ObjectId` + }) + } + + const image = await Image.findById(id) + if (image) { + res.json(encodeImage(image)) + } else { + res.status(404) + res.json({ + error: `Resource ${slug} not found` + }) + } +} + +export async function getItemByFile(req: Request, res: Response) { const file = req.query.file const image = await Image.findByFile(file) - + if (image) { res.json(encodeImage(image)) } else { diff --git a/modules/hudozka-api/src/core/Document.ts b/modules/hudozka-api/src/core/Document.ts index 7dd182b5..94639ace 100644 --- a/modules/hudozka-api/src/core/Document.ts +++ b/modules/hudozka-api/src/core/Document.ts @@ -11,8 +11,8 @@ export default class Document { return Promise.all(items.map(processDocument)) } - static async findById(id) { - const data = await findOne(store(), { id }) + static async findBySlug(slug: string) { + const data = await findOne(store(), { id: slug }) if (!data) return null return processDocument(data) @@ -21,22 +21,22 @@ export default class Document { public id: any public hash: any public file: any - public fileInfo: any + public fileInfo: FileInfo public type: any public title: any public category: any public url: any - public preview: any + public preview: Image public viewUrl: any - constructor(data) { + constructor(data: { preview: Image, [name: string]: any }) { this.id = data.id this.hash = data.hash this.file = data.file // In the future: use fileInfo only this.fileInfo = data.fileInfo - ? new DocumentFile(data.fileInfo) - : new DocumentFile(data.file) + ? new FileInfo(data.fileInfo) + : new FileInfo(data.file) this.type = data.type this.title = data.title this.category = data.category @@ -47,9 +47,9 @@ export default class Document { } } -class DocumentFile { - public name: any - public size: any +class FileInfo { + public name: string + public size: number constructor(data) { this.name = data.name diff --git a/modules/hudozka-api/src/core/Image.ts b/modules/hudozka-api/src/core/Image.ts index 49ee7ef1..034453b7 100644 --- a/modules/hudozka-api/src/core/Image.ts +++ b/modules/hudozka-api/src/core/Image.ts @@ -1,5 +1,4 @@ import Data from './Data' -import ImageArtifactType from './ImageArtifactType' import { findOne } from '../lib/store' import { ObjectId } from 'mongodb' @@ -47,47 +46,9 @@ export default class Image { this.artifacts = mapOf(ImageArtifact, artifacts) } - getArtifact(size) { + getArtifact(size: string) { return this.artifacts.get(size) } - - findArtifact(sizes) { - for (let size of sizes) { - const a = this.getArtifact(size) - if (a) return a - } - - return null - } - - getPicture(size) { - const retinaSize = ImageArtifactType.retina(size) - - const a = this.getArtifact(size) - const a2 = this.getArtifact(retinaSize) - const srcset = !a2 - ? [] - : [{ - url: a2.url, - density: ImageArtifactType.RETINA_DENSITY, - }] - - return { - src: a.url, - width: a.width, - height: a.height, - set: srcset, - } - } - - getSrc(): string | null { - const a = this.getArtifact(ImageArtifactType.ORIGINAL) - if (!a) { - return null - } - - return a.url - } } class ImageArtifact { diff --git a/modules/hudozka-api/src/core/ImageArtifactType.js b/modules/hudozka-api/src/core/ImageArtifactType.js deleted file mode 100644 index 360cf5d8..00000000 --- a/modules/hudozka-api/src/core/ImageArtifactType.js +++ /dev/null @@ -1,19 +0,0 @@ -class ImageArtifactType { - constructor() { - throw new Error('Cannot create instance of ImageArtifactType') - } -} - -ImageArtifactType.SMALL = 'small' -ImageArtifactType.MEDIUM = 'medium' -ImageArtifactType.BIG = 'big' -ImageArtifactType.LARGE = 'large' -ImageArtifactType.ORIGIN = 'original' -ImageArtifactType.ORIGINAL = 'original' - -ImageArtifactType.FACEBOOK = 'fb' - -ImageArtifactType.RETINA_DENSITY = 2 -ImageArtifactType.retina = type => `${type}@${ImageArtifactType.RETINA_DENSITY}` - -module.exports = ImageArtifactType diff --git a/modules/hudozka-api/src/core/Page.ts b/modules/hudozka-api/src/core/Page.ts index 208967b9..3cfb0a6b 100644 --- a/modules/hudozka-api/src/core/Page.ts +++ b/modules/hudozka-api/src/core/Page.ts @@ -20,14 +20,6 @@ export default class Page { return Promise.all(items.map(processPage)) } - static async findById(id) { - const item = await findOne(store(), { id }) - - return !item - ? null - : processPage(item) - } - static async findByUrl(url: string) { const item = await findOne(store(), { url }) diff --git a/modules/hudozka-api/src/db.ts b/modules/hudozka-api/src/db.ts index 1442a6aa..ecfb9fe4 100644 --- a/modules/hudozka-api/src/db.ts +++ b/modules/hudozka-api/src/db.ts @@ -12,14 +12,25 @@ export async function connect(dbName: string, mongoUri: string) { return db } -export function collection(name) { +export function collection(name: string) { return db.collection(name) } -export function id(i) { - if (typeof i === 'string') return new ObjectId(i) - else if (i instanceof ObjectId) return i - else if (i instanceof Object) return '_id' in i ? new ObjectId(i._id) : null +export type ObjectIdLike = ObjectId | string +export function oid(i: ObjectIdLike | { _id: ObjectIdLike }): ObjectId | null { + if (i instanceof ObjectId) { + return i + } else if (typeof i === 'string') { + try { + return new ObjectId(i) + } catch (error) { + console.error(error) + return null + } + } else if (i instanceof Object) { + return '_id' in i ? oid(i._id) : null + } + return null } diff --git a/modules/hudozka-api/src/factory/file.ts b/modules/hudozka-api/src/factory/file.ts index 02b465f3..7066de88 100644 --- a/modules/hudozka-api/src/factory/file.ts +++ b/modules/hudozka-api/src/factory/file.ts @@ -1,35 +1,36 @@ -import ImageArtifactType from '../core/ImageArtifactType' +import Document from '../core/Document' +import { encodeImage, ImageDto } from './image' -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('Articles /', '') - - return { - imageUrl, - category, - title: file.title, - fileName: file.fileInfo.name, - fileSize: file.fileInfo.size, - fileUrl: file.url, - url: file.viewUrl, +export type FileDto = { + url: string + slug: string + name: string + cover?: ImageDto + file: { + name: string + size: number + type: string + src: string } } + +export function encodeFile(file: Document): FileDto { + const cover = file.preview ? encodeImage(file.preview) : null + + return { + url: encodeFileUrl(file), + slug: file.id, + cover, + name: file.title, + file: { + type: 'application/pdf', + name: file.fileInfo.name, + size: file.fileInfo.size, + src: file.url, + } + } +} + +export function encodeFileUrl(file: Document): string { + return `/document/${file.id}` +} diff --git a/modules/hudozka-api/src/factory/image.ts b/modules/hudozka-api/src/factory/image.ts index 9720c850..587c747a 100644 --- a/modules/hudozka-api/src/factory/image.ts +++ b/modules/hudozka-api/src/factory/image.ts @@ -1,48 +1,22 @@ -import ImageArtifactType from '../core/ImageArtifactType' import Image from '../core/Image' -export type ImageArtifactDto = { - height: number - width: number - src: string - set: Array<{ - density: number - url: string - }> -} +const ORIGINAL = 'original' export type ImageDto = { - artifacts: { - original: ImageArtifactDto, - large: ImageArtifactDto, - big: ImageArtifactDto, - medium: ImageArtifactDto, - small: ImageArtifactDto, - fb: ImageArtifactDto, - }, - hash: string - file: string + width: number + height: number + src: string } export function encodeImage(image: Image): ImageDto { - const artifacts = [ - ImageArtifactType.SMALL, - ImageArtifactType.MEDIUM, - ImageArtifactType.BIG, - ImageArtifactType.LARGE, - ImageArtifactType.ORIGIN, - ImageArtifactType.ORIGINAL, - ImageArtifactType.FACEBOOK = 'fb' - ].reduce((acc, size) => { - return { - ...acc, - [size]: image.getPicture(size), - } - }, {}) + const a = image.getArtifact(ORIGINAL) + if (!image) { + return null + } return { - artifacts: artifacts as any, - hash: image.hash, - file: image.file, + src: a.url, + width: a.width, + height: a.height, } } diff --git a/modules/hudozka-api/src/factory/page.ts b/modules/hudozka-api/src/factory/page.ts index bc2cad20..8d15d528 100644 --- a/modules/hudozka-api/src/factory/page.ts +++ b/modules/hudozka-api/src/factory/page.ts @@ -9,29 +9,24 @@ type Token = { } type PageDto = { - id: string title: string date?: string url: string data: string description: string - preview?: ImageDto + cover?: ImageDto tokens: Token[] tags: Tag[] featured: boolean breadcrumb: Breadcrumb - coverSrc?: string } export function encodePage(page: Page): PageDto { - const preview = page.preview ? encodeImage(page.preview) : null + const cover = page.preview ? encodeImage(page.preview) : null const date = page.date ? page.date.toString() : null const breadcrumb = page.getBreadcrumb() - const coverSrc = page.preview ? page.preview.getSrc() : null - return { - id: page.id, title: page.title, url: page.url, data: page.data, @@ -39,9 +34,8 @@ export function encodePage(page: Page): PageDto { tokens: page.tokens, tags: page.tags, featured: page.featured, - preview, + cover, date, breadcrumb, - coverSrc, } } diff --git a/modules/hudozka-api/src/server.ts b/modules/hudozka-api/src/server.ts index 21104af6..fb63eddc 100644 --- a/modules/hudozka-api/src/server.ts +++ b/modules/hudozka-api/src/server.ts @@ -21,7 +21,6 @@ async function main() { } const app = express() - app.get('/files', file.getAll) app.get('/files/urls', file.getUrls) app.get('/files/:slug', file.getItem) diff --git a/modules/sync/settings.py b/modules/sync/settings.py index bff13c45..e4b9829c 100644 --- a/modules/sync/settings.py +++ b/modules/sync/settings.py @@ -49,6 +49,8 @@ image_sizes = [ ('large', 2500, 1000), ('large@2', 5000, 2000), + # ('large', 2500, 1000), + # ('large@2', 5000, 2000), ('big', 1500, 667), ('big@2', 3000, 1334), @@ -58,12 +60,18 @@ image_sizes = [ ('small', 250, 175), ('small@2', 500, 350), + # ('small', 250, 175), + # ('small@2', 500, 350), ('og', 968, 504), ('og@2', 1936, 1008), + # ('og', 968, 504), + # ('og@2', 1936, 1008), ('fb', 1200, 630), ('fb@2', 2400, 1260), + # ('fb', 1200, 630), + # ('fb@2', 2400, 1260), ] date_formats = [ diff --git a/modules/sync/sync/__init__.py b/modules/sync/sync/__init__.py index ab8dc7fc..fb14ebad 100644 --- a/modules/sync/sync/__init__.py +++ b/modules/sync/sync/__init__.py @@ -86,7 +86,7 @@ async def create_post(provider: Provider, folder: str, md: str, sizes): text = data['caption'] if data['caption'] else data['file'] url = f'/document/{document.id}' - image_url = document.preview.get_size('small')['url'] + image_url = document.preview.get_src() return { 'url': url, diff --git a/pages/[...slug].tsx b/pages/[...slug].tsx index 0af772c7..b7a4031b 100644 --- a/pages/[...slug].tsx +++ b/pages/[...slug].tsx @@ -62,7 +62,7 @@ export const getStaticProps = async (ctx: any) => { const breadcrumbSize = page?.breadcrumb?.length ?? 0 const breadcrumb = breadcrumbSize < 2 ? null : page.breadcrumb const meta = (new MetaBuilder()) - .setImage(page.preview) + .setImage(page.cover) .setTitle(page.title) .setDescription(description) .build() diff --git a/pages/collective.tsx b/pages/collective.tsx index 30e02884..f111d753 100644 --- a/pages/collective.tsx +++ b/pages/collective.tsx @@ -109,15 +109,13 @@ export const getStaticProps = async (ctx: NextPageContext) => { const data: CardData[] = pages .filter(Boolean) .map(x => { - const image = x.preview.artifacts.large - return { title: x.title, caption: x.description, href: x.url, imageAlt: title, - imageSrc: image.src, - imageSrcSet: imageSrcSet(image.src, [ImageSize.medium, ImageSize.small]) + imageSrc: x.cover.src, + imageSrcSet: imageSrcSet(x.cover.src, [ImageSize.medium, ImageSize.small]) } }) diff --git a/pages/document/[slug].tsx b/pages/document/[slug].tsx index 16327895..667a4beb 100644 --- a/pages/document/[slug].tsx +++ b/pages/document/[slug].tsx @@ -1,16 +1,15 @@ -import React from 'react' import Head from 'next/head' import { App } from 'src/components/App' -import Document from 'src/components/Document' +import { File } from 'src/components/File' import { Share } from 'src/components/Share' -import { meta } from 'src/lib/meta' +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 { IMeta } from 'src/types' +import { IMeta, FileDefinition } from 'src/types' type Props = { - data: any //(file) + data: FileDefinition meta: IMeta } @@ -26,25 +25,28 @@ const Page: NextPage = props => { showAuthor={true} > - {props.data.title} + {props.data.name} - + ) } export const getStaticProps = async (ctx: any) => { - const id = ctx.params.slug - const data = await requestGet(createApiUrl(`/api/files/${id}`), {}) + const slug = ctx.params.slug + const data = await requestGet(createApiUrl(`/api/files/${slug}`), null) + const meta = (new MetaBuilder()) + .setImage(data.cover) + .setTitle(data.name) + .setDescription(data.name) + .build() return { props: { data, - meta: meta({ - // title: file.meta, - }) + meta, } } } diff --git a/pages/index.tsx b/pages/index.tsx index ce5a84c7..0df49ce2 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -20,7 +20,7 @@ const Index: NextPage = props => { title: item.title, featured: item.featured, date: new Date(item.date), - coverSrc: item.coverSrc, + coverSrc: item.cover?.src, })) return ( diff --git a/src/components/Document.js b/src/components/Document.js deleted file mode 100644 index 1b3a473b..00000000 --- a/src/components/Document.js +++ /dev/null @@ -1,23 +0,0 @@ -const React = require('react') -const {ext, size} = require('../lib/file') -const {titleCase} = require('../lib/string') - -const Document = ({title, url, imageUrl, fileUrl, fileName, fileSize}) => ( -
-
- - {title}/ - -
- -
- {titleCase(title)} -
- - -
-) - -module.exports = Document diff --git a/src/components/File/index.tsx b/src/components/File/index.tsx new file mode 100644 index 00000000..c2c81632 --- /dev/null +++ b/src/components/File/index.tsx @@ -0,0 +1,25 @@ +import { FileDefinition } from 'src/types' +import { ext, size } from 'src/lib/file' +import { titleCase } from 'src/lib/string' + +export const File: React.SFC = props => ( +
+

{titleCase(props.name)}

+ + {!props.cover?.src ? null : ( +
+ + {props.name} + +
+ )} + +
+ {titleCase(props.name)} +
+ + +
+) diff --git a/src/lib/meta.ts b/src/lib/meta.ts index 667607f2..6763aed7 100644 --- a/src/lib/meta.ts +++ b/src/lib/meta.ts @@ -66,11 +66,10 @@ export class MetaBuilder { return null } - const artifact = this.image.artifacts.fb return { - image: artifact.src, - imageWidth: artifact.width, - imageHeight: artifact.height, + image: this.image.src, + imageWidth: this.image.width, + imageHeight: this.image.height, } } } diff --git a/src/rest.ts b/src/rest.ts index a792e864..a8f0fc91 100644 --- a/src/rest.ts +++ b/src/rest.ts @@ -27,7 +27,7 @@ export async function getPagesCardsByTags(tags: string[]): Promise(tags, { fields, skip, limit, sortBy: '-date' }) diff --git a/src/types.ts b/src/types.ts index 7945e4e6..e2b41594 100644 --- a/src/types.ts +++ b/src/types.ts @@ -21,7 +21,20 @@ export type PageCardDto = { title: string featured: boolean date: string - coverSrc: string + cover?: ImageDefinition +} + +export type FileDefinition = { + url: string + slug: string + name: string + cover?: ImageDefinition + file: { + name: string + size: string + type: string + src: string + } } export interface IPage { @@ -30,7 +43,7 @@ export interface IPage { url: string data: string date: string - preview: ImageDefinition + cover: ImageDefinition description: string tokens: any[] tags: ITag[] @@ -85,25 +98,8 @@ export enum ImageSize { thumbnail = 200, } -export type ImageArtifact = { +export type ImageDefinition = { width: number height: number src: string - set: Array<{ - density: number - url: string - }> -} - -export type ImageDefinition = { - file: string - hash: string - artifacts: { - original: ImageArtifact - large?: ImageArtifact - big?: ImageArtifact - medium?: ImageArtifact - small?: ImageArtifact - fb?: ImageArtifact - } }