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)