검증게시판, 압축파일, 한글파일 첨부가능
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* 검증게시판 첨부 — 이미지 + zip·hwp·hwpx
|
||||
*/
|
||||
import {
|
||||
pickImageFiles,
|
||||
prepareImagesForUpload,
|
||||
} from './clipboardImageFiles';
|
||||
|
||||
export const VERIFICATION_ATTACHMENT_ACCEPT =
|
||||
'image/jpeg,image/png,image/gif,image/webp,image/bmp,.zip,.hwp,.hwpx,application/zip,application/x-hwp,application/vnd.hancom.hwpx';
|
||||
|
||||
const DOCUMENT_EXT = new Set(['.zip', '.hwp', '.hwpx']);
|
||||
|
||||
const DOCUMENT_MIME = new Set([
|
||||
'application/zip',
|
||||
'application/x-zip-compressed',
|
||||
'application/x-hwp',
|
||||
'application/haansoft-hwp',
|
||||
'application/vnd.hancom.hwp',
|
||||
'application/hwp+zip',
|
||||
'application/vnd.hancom.hwpx',
|
||||
'application/x-hwpx',
|
||||
]);
|
||||
|
||||
function extOf(name: string): string {
|
||||
const i = name.lastIndexOf('.');
|
||||
return i >= 0 ? name.slice(i).toLowerCase() : '';
|
||||
}
|
||||
|
||||
function mimeForDocumentExt(ext: string): string | null {
|
||||
switch (ext) {
|
||||
case '.zip': return 'application/zip';
|
||||
case '.hwp': return 'application/x-hwp';
|
||||
case '.hwpx': return 'application/vnd.hancom.hwpx';
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function isImageAttachment(contentType?: string | null, fileName?: string | null): boolean {
|
||||
const mime = (contentType ?? '').split(';')[0]?.trim().toLowerCase();
|
||||
if (mime.startsWith('image/')) return true;
|
||||
const ext = fileName ? extOf(fileName) : '';
|
||||
return ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.bmp'].includes(ext);
|
||||
}
|
||||
|
||||
export function isDocumentAttachmentFile(file: File): boolean {
|
||||
const ext = extOf(file.name);
|
||||
if (DOCUMENT_EXT.has(ext)) return true;
|
||||
const mime = file.type.split(';')[0]?.trim().toLowerCase();
|
||||
return DOCUMENT_MIME.has(mime);
|
||||
}
|
||||
|
||||
function normalizeDocumentFile(file: File): File | null {
|
||||
if (file.size === 0) return null;
|
||||
const ext = extOf(file.name);
|
||||
if (!DOCUMENT_EXT.has(ext)) {
|
||||
const mime = file.type.split(';')[0]?.trim().toLowerCase();
|
||||
if (!DOCUMENT_MIME.has(mime)) return null;
|
||||
}
|
||||
const mime = mimeForDocumentExt(ext)
|
||||
?? file.type.split(';')[0]?.trim().toLowerCase()
|
||||
?? 'application/octet-stream';
|
||||
if (file.type === mime) return file;
|
||||
return new File([file], file.name, { type: mime, lastModified: file.lastModified });
|
||||
}
|
||||
|
||||
/** FileList / File[] → 허용 첨부만 (이미지·zip·hwp·hwpx) */
|
||||
export function pickAttachmentFiles(list: FileList | File[]): File[] {
|
||||
const out: File[] = [];
|
||||
for (const file of Array.from(list)) {
|
||||
if (isDocumentAttachmentFile(file)) {
|
||||
const doc = normalizeDocumentFile(file);
|
||||
if (doc) out.push(doc);
|
||||
continue;
|
||||
}
|
||||
const img = pickImageFiles([file])[0];
|
||||
if (img) out.push(img);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
const MAX_BYTES = 5 * 1024 * 1024;
|
||||
|
||||
/** 이미지는 압축·문서는 그대로 업로드 */
|
||||
export async function prepareAttachmentsForUpload(files: File[]): Promise<File[]> {
|
||||
const picked = pickAttachmentFiles(files);
|
||||
const out: File[] = [];
|
||||
for (const f of picked) {
|
||||
if (isDocumentAttachmentFile(f)) {
|
||||
if (f.size > MAX_BYTES) throw new Error('FILE_TOO_LARGE');
|
||||
out.push(f);
|
||||
} else {
|
||||
out.push(...await prepareImagesForUpload([f]));
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
export const ATTACHMENT_TYPE_HINT =
|
||||
'jpeg, png, gif, webp, bmp, zip, hwp, hwpx (파일당 5MB)';
|
||||
Reference in New Issue
Block a user