diff --git a/README.md b/README.md index d5e3270..6a87ad3 100644 --- a/README.md +++ b/README.md @@ -156,7 +156,7 @@ Backend mapping: sort, full: { w, h, size }, // AVIF, max 1000×1000 (stored as-is when already AVIF and within bounds) thumb: { w, h }, // scaled AVIF, max 200×200 (fit inside) - hash, // SHA-256 hex of full image bytes + fullHash, // SHA-256 hex — use for GET /api/image/:fullHash and GET /api/thumb/:fullHash thumbHash, // base64 thumbhash of thumb preview } ``` @@ -190,20 +190,25 @@ Auth via the article's `categoryarticle` category + `resolveCategoryAccess`. Err ## `pic` -Lookup by `pic.hash` (SHA-256 hex from `addImage`), not `thumbhash`. +Lookup by `pic.hash` (`fullHash` — SHA-256 hex from `addImage.fullHash`), not `thumbhash`. | Method | Signature | Returns | | --- | --- | --- | -| `getImageByHash` | `(googleAuthId, hash)` | `{ buffer, w, h, size, contentType }` | -| `getThumbByHash` | `(googleAuthId, hash)` | `{ buffer, w, h, contentType }` | +| `getImageByHash` | `(googleAuthId, fullHash)` | `{ buffer, w, h, size, contentType }` | +| `getThumbByHash` | `(googleAuthId, fullHash)` | `{ buffer, w, h, contentType }` | Auth via `articlepic` → `categoryarticle` → `resolveCategoryAccess`. Errors: `Image not found`, `Not authorized`. -`contentType` is always `image/avif`. In dashback: +`contentType` is always `image/avif`. ```js -const { buffer, contentType } = await store.pic.getImageByHash(req.user.id, hash); +// GET /api/image/:fullHash +const { buffer, contentType } = await store.pic.getImageByHash(req.user.id, fullHash); res.set('Content-Type', contentType).send(buffer); + +// GET /api/thumb/:fullHash +const thumb = await store.pic.getThumbByHash(req.user.id, fullHash); +res.set('Content-Type', thumb.contentType).send(thumb.buffer); ``` --- @@ -224,8 +229,8 @@ res.set('Content-Type', contentType).send(buffer); | `GET /api/article/:sku` | `article.getBySku(googleAuthId, sku)` | | `PATCH /api/article/:sku` | `article.updateBySku(googleAuthId, sku, { name })` | | `POST /api/article/:sku/image` | `article.addImage(googleAuthId, sku, imageBuffer)` | -| `GET /api/image/:hash` | `pic.getImageByHash(googleAuthId, hash)` | -| `GET /api/image/:hash/thumb` | `pic.getThumbByHash(googleAuthId, hash)` | +| `GET /api/image/:fullHash` | `pic.getImageByHash(googleAuthId, fullHash)` | +| `GET /api/thumb/:fullHash` | `pic.getThumbByHash(googleAuthId, fullHash)` | --- diff --git a/scripts/test-api.js b/scripts/test-api.js index 7d0f1cb..1511eb3 100644 --- a/scripts/test-api.js +++ b/scripts/test-api.js @@ -133,12 +133,12 @@ const MENU = { { value: 'pic.getImageByHash', label: 'getImageByHash', - hint: 'googleAuthId, hash → meta', + hint: 'googleAuthId, fullHash → meta', }, { value: 'pic.getThumbByHash', label: 'getThumbByHash', - hint: 'googleAuthId, hash → meta', + hint: 'googleAuthId, fullHash → meta', }, ], }, @@ -461,11 +461,14 @@ async function runMethod(client, action) { case 'pic.getImageByHash': { const googleAuthId = await askInt('google_auth id'); if (googleAuthId == null) return; - const hash = await askText('hash (SHA-256 hex)', { + const fullHash = await askText('fullHash (SHA-256 hex)', { validate: (v) => (!v?.trim() ? 'Required' : undefined), }); - if (hash == null) return; - const image = await client.pic.getImageByHash(Number(googleAuthId), hash.trim()); + if (fullHash == null) return; + const image = await client.pic.getImageByHash( + Number(googleAuthId), + fullHash.trim(), + ); return [ 'result', { @@ -480,11 +483,14 @@ async function runMethod(client, action) { case 'pic.getThumbByHash': { const googleAuthId = await askInt('google_auth id'); if (googleAuthId == null) return; - const hash = await askText('hash (SHA-256 hex)', { + const fullHash = await askText('fullHash (SHA-256 hex)', { validate: (v) => (!v?.trim() ? 'Required' : undefined), }); - if (hash == null) return; - const image = await client.pic.getThumbByHash(Number(googleAuthId), hash.trim()); + if (fullHash == null) return; + const image = await client.pic.getThumbByHash( + Number(googleAuthId), + fullHash.trim(), + ); return [ 'result', { diff --git a/src/store/article/addImage.js b/src/store/article/addImage.js index 9f4541c..c95ea9e 100644 --- a/src/store/article/addImage.js +++ b/src/store/article/addImage.js @@ -68,7 +68,7 @@ export default function addImage(pool) { w: processed.thumb.w, h: processed.thumb.h, }, - hash: processed.full.hash, + fullHash: processed.full.hash, thumbHash: processed.thumb.hash, }; } catch (err) { diff --git a/src/store/pic/getImageByHash.js b/src/store/pic/getImageByHash.js index c41c908..da4afe4 100644 --- a/src/store/pic/getImageByHash.js +++ b/src/store/pic/getImageByHash.js @@ -4,12 +4,12 @@ import resolvePicAccess from './resolvePicAccess.js'; export default function getImageByHash(pool) { const authorize = resolvePicAccess(pool); - return async (googleAuthId, hash) => { - await authorize(googleAuthId, hash); + return async (googleAuthId, fullHash) => { + await authorize(googleAuthId, fullHash); const result = await pool .request() - .input('hash', hash) + .input('hash', fullHash) .query(GET_FULL_BY_HASH); const row = result.recordset[0]; diff --git a/src/store/pic/getThumbByHash.js b/src/store/pic/getThumbByHash.js index 777ce3a..8e50e1c 100644 --- a/src/store/pic/getThumbByHash.js +++ b/src/store/pic/getThumbByHash.js @@ -4,12 +4,12 @@ import resolvePicAccess from './resolvePicAccess.js'; export default function getThumbByHash(pool) { const authorize = resolvePicAccess(pool); - return async (googleAuthId, hash) => { - await authorize(googleAuthId, hash); + return async (googleAuthId, fullHash) => { + await authorize(googleAuthId, fullHash); const result = await pool .request() - .input('hash', hash) + .input('hash', fullHash) .query(GET_THUMB_BY_HASH); const row = result.recordset[0]; diff --git a/src/store/pic/resolvePicAccess.js b/src/store/pic/resolvePicAccess.js index 2e7d6ac..13519fe 100644 --- a/src/store/pic/resolvePicAccess.js +++ b/src/store/pic/resolvePicAccess.js @@ -4,10 +4,10 @@ import resolveCategoryAccess from '../category/resolveCategoryAccess.js'; export default function resolvePicAccess(pool) { const access = resolveCategoryAccess(pool); - return async (googleAuthId, hash) => { + return async (googleAuthId, fullHash) => { const result = await pool .request() - .input('hash', hash) + .input('hash', fullHash) .query(GET_CATEGORY_ID_BY_HASH); const categoryId = result.recordset[0]?.categoryId;