Files
arasystem/backend/test/image-fixtures.ts
T
ttipo a79f0791d0 feat(backend): 임시 저장·서명(그림)·받는 사람 추천 API와 MAIL_008
- /api/drafts: 발송과 같은 준비(정화·한도)로 초안을 만들고, 바꿔 저장은 새로 만들어 다시 읽은 뒤 옛것을 지운다.
  만들기와 지우기를 한 요청에 넣지 않는다 — 엔진이 만들기가 실패해도 지우기를 해서 저장본이 사라졌다.
  옛 초안이 이미 없으면 409 MAIL_008(새 코드), 초안이 아닌 id 는 404 RES_001 로 아무것도 지우지 않는다.
- 사용자 메일의 영구 삭제(교체한 옛 초안 · 보낸 뒤 draftId · 휴지통 영구 삭제)는 대상인지 확인한 상태 그대로일 때만
  ifInState 로 지운다 — 확인과 지우기 사이에 다른 탭이 옮긴 메일까지 지우지 않게 (Stalwart 0.16.27 에서 확인)
- /api/mail-signature: 서명(DB)과 그림(업로드 볼륨). 그림은 확장자·MIME·매직 바이트·크기·가로세로를 보고,
  보낼 때 multipart/related 의 cid 그림으로 싣는다. 서명 저장은 사용자별로 잠가 차례로 한다
- /api/recipient-suggestions: 로그인한 직원 기록(mail_directory)과 내 메일함의 최근 주소로 추천, 사용자별 10분 캐시
- 본문 그림은 첨부 표시에서 뺀다(hasAttachment 직접 계산 · isInline), 예외 필터 로그의 검색어(q)는 길이만 남긴다
- 마이그레이션 AddMailSignaturesAndDirectory: 새 표 3개만 만든다

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 19:22:45 +09:00

76 lines
2.2 KiB
TypeScript

/**
* 서명 그림 테스트용 그림 파일 머리 — 테스트 전용 도우미 (앱 코드에서 import 하지 않는다).
*
* 형식 확인(signature-image-format.ts)은 파일 앞부분만 본다 — 여기서는 그 앞부분과, 크기를 맞출 채움 바이트만 만든다
* (실제로 그릴 수 있는 그림일 필요는 없다).
*
* 위치: src 밖(test/) — cpu-time.ts 와 같은 이유로 빌드·커버리지에 들어가지 않는다.
* 단위 테스트는 `@/../test/image-fixtures`, e2e 는 `./image-fixtures` 로 부른다.
*/
/** PNG 서명 + IHDR(가로·세로·비트 깊이·색 형식) — CRC 는 보지 않으므로 비워 둔다. `size` 바이트가 되게 0 으로 채운다 */
export function pngBytes(width: number, height: number, size = 33): Buffer {
const data = Buffer.alloc(Math.max(size, 33));
Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]).copy(data);
data.writeUInt32BE(13, 8);
data.write('IHDR', 12, 'ascii');
data.writeUInt32BE(width, 16);
data.writeUInt32BE(height, 20);
data[24] = 8; // 비트 깊이
data[25] = 6; // 색 형식 RGBA
return data;
}
/** GIF 머리 (논리 화면의 가로·세로, 리틀 엔디언) */
export function gifBytes(
width: number,
height: number,
version = 'GIF89a',
): Buffer {
const data = Buffer.alloc(13);
data.write(version, 0, 'ascii');
data.writeUInt16LE(width, 6);
data.writeUInt16LE(height, 8);
return data;
}
/** SOI + APP0(JFIF) + (선택) 표지 앞 채움 바이트 + SOFn(세로·가로) + EOI */
export function jpegBytes(
width: number,
height: number,
options: { sof?: number; fill?: boolean } = {},
): Buffer {
const app0 = Buffer.from([
0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01, 0x01, 0x00,
0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
]);
const sof = Buffer.from([
0xff,
options.sof ?? 0xc0,
0x00,
0x11,
0x08,
(height >> 8) & 0xff,
height & 0xff,
(width >> 8) & 0xff,
width & 0xff,
0x03,
0x01,
0x22,
0x00,
0x02,
0x11,
0x01,
0x03,
0x11,
0x01,
]);
return Buffer.concat([
Buffer.from([0xff, 0xd8]),
app0,
...(options.fill ? [Buffer.from([0xff, 0xff])] : []),
sof,
Buffer.from([0xff, 0xd9]),
]);
}