MSG File Analyzer را با استفاده از NextJS بسازید

هنگام درخواست برای یک شغل فنی، داشتن یک نمونه کار قوی برای تحت تاثیر قرار دادن شرکت مهم است. به خصوص برای توسعه دهندگان مبتدی، اولین برداشت از رزومه و پروژه ها نقش مهمی ایفا می کند. متداول ترین انواع پروژه عبارتند از اپ To-do، اپلیکیشن آب و هوا، بلاگ و غیره که می باشد حوصله سر بر.
این پست به صورت متقابل از Notion با OnePublish منتشر شده است.
در این سری جدید ما چیزهای منحصر به فرد و خلاقانه ای می سازیم و آن را به تولید می فرستیم. انتشار قبلی از این مجموعه را در زیر ببینید:
https://www.developertimeline.io/build-a-phishing-site-detector-with-nextjs-and-virustotal/
بنابراین، در این قسمت نمایشگر جزئیات ایمیل را می سازیم که فایل MSG را به عنوان ورودی می گیرد، محتوای آن را می خواند و به کاربر نمایش می دهد.
ما قصد داریم از NextJS برای ساخت سریع برنامه خود استفاده کنیم و آن را به راحتی با استفاده از Vercel به تولید ارسال کنیم. هر بار که یک کامیت جدید ایجاد می کنیم، Vercel برنامه ما را به روز می کند، بنابراین لازم نیست نگران استقرار باشیم، بلکه فقط روی ساختن تمرکز کنیم.
چرا این پروژه عالی است؟
زیرا شامل مهارت های زیادی است که به عنوان یک توسعه دهنده باید داشته باشند:
- TypeScript.
- ادغام شخص ثالث
- استفاده از خود NextJS
- مهارت های UI/UX.
- Tailwind CSS (eh)
- گسترش
چه چیزی می سازیم؟
این پروژه قرار است یک برنامه تک صفحه ای باشد که به کاربر اجازه می دهد فایل MSG یا به عبارت دیگر آیتم Microsoft Outlook را آپلود کند. پس از آپلود فایل توسط کاربر، باید هدر ایمیل، محتوا، پیوستها و سایر جزئیات ایمیل را استخراج کند و سپس نتیجه را با UI/UX زیبا به کاربر نمایش دهد.
شروع شدن
بیایید با ایجاد یک پروژه NextJS جدید شروع کنیم. من از آخرین نسخه NextJS که نسخه 14 است در زمان نوشتن این پست استفاده خواهم کرد.
npx create-next-app@latest
چند سوال برای پیکربندی پروژه NextJS ایجاد می کند. من استفاده از TypeScript را انتخاب می کنم، Tailwind CSS را مقداردهی اولیه می کنم و از روتر App استفاده می کنم.
✔ What is your project named? …
✔ Would you like to use TypeScript? … No / **Yes**
✔ Would you like to use ESLint? … No / **Yes**
✔ Would you like to use Tailwind CSS? … No / **Yes**
✔ Would you like to use `src/` directory? … **No** / Yes
✔ Would you like to use App Router? (recommended) … No / **Yes**
✔ Would you like to customize the default import alias (@/*)? … No / **Yes**
اکنون باید پروژه NextJS را آماده استفاده اولیه کرده باشید.
Building Backend
ابتدا باید کتابخانه ای پیدا کنیم که بتواند محتوای فایل msg را بخواند. یک بسته npm به نام @kenjiuno/msgreader وجود دارد که می تواند جزئیات را از فایل های .msg بخواند و استخراج کند.
بیایید با ایجاد و فراخوانی نقطه پایانی شروع کنیم /api/reader
که درخواست POST را از فرانت اند مدیریت می کند و داده های فایل را به خواننده پیام ارسال می کند.
/api/reader/route.ts
import { reader } from "@/app/utils/reader";
export async function POST(request: Request) {
const formData = await request.formData();
const file: any = formData.get("file");
const buffer = Buffer.from(await file.arrayBuffer());
const readerRes = await reader(buffer);
return Response.json({ reader: readerRes });
}
به سادگی، گرفتن و خواندن file
از بدنه درخواست و ذخیره بافر در داخل buffer
متغیر.
از آنجایی که نیازی به ذخیره فایل آپلود شده به صورت محلی نیست reader
می پذیرد Buffer
همچنین. این ما را از بسیاری از عملیات IO فایل نجات می دهد.
حالا بیایید a اضافه کنیم reader
تابع استفاده:
/utils/reader.ts
import MsgReader from "@kenjiuno/msgreader";
export async function reader(buffer: Buffer) {
const testMsg = new MsgReader(buffer);
const testMsgInfo = testMsg.getFileData();
return testMsgInfo;
}
ما استفاده می کنیم @kenjiuno/msgreader
کتابخانه برای استخراج جزئیات از بافر فایل.
این همه از سمت باطن است!
ساخت فرانت اند
در سمت جلو، ما از DaisyUI و برخی از اجزای Flowbite برای ساخت سریع UI استفاده می کنیم. هر دو در بالای Tailwind CSS ساخته شده اند.
در اینجا صفحه فهرستی است که همه اجزای این برنامه را در خود جای داده است:
app/page.tsx
"use client";
import { useState } from "react";
import FileInput from "./components/FileInput";
import EmailHeaders from "./components/Headers";
import AttachmentsHeaders from "./components/Attachments";
import { FieldsData } from "@kenjiuno/msgreader";
const Home: React.FC = () => {
const [details, setDetails] = useState<FieldsData | null>(null);
return (
<>
<FileInput onDataExtracted={(details: FieldsData) => setDetails(details)} />
{/* Results */}
<EmailHeaders headerDetails={details?.headers} />
<AttachmentsHeaders attachmentsDetails={details?.attachments} />
</>
);
};
export default Home;
اولین جزء خواهد بود FileInput
که به کاربر امکان می دهد فایل MSG خود را در قسمت ورودی کشیدن و رها کردن آپلود کند.
/components/FileInput.tsx
"use client";
import { FieldsData } from "@kenjiuno/msgreader";
import axios from "axios";
import { ChangeEvent, useState } from "react";
interface FileInputProps {
onDataExtracted: (details: FieldsData) => void
}
const FileInput: React.FC<FileInputProps> = ({ onDataExtracted }) => {
const [alertMessage, setAlertMessage] = useState<string>("");
const submitMsgFile = async (event: ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0];
if (file) {
try {
const formData = new FormData();
formData.append("file", file);
const res = await axios.post("/api/reader", formData);
onDataExtracted(res?.data?.reader);
console.log(res.data.reader);
setAlertMessage("Success! Check results below.");
} catch (error) {
console.log(error);
}
} else {
}
};
return (
<div className="hero min-h-screen bg-base-200">
<div className="hero-content text-center">
<div className="max-w-lg">
<h1 className="text-5xl font-bold mb-5">MSG Analyzer</h1>
<p className="mb-5">Drop your .MSG file below to get results</p>
<div className="flex items-center justify-center w-full">
<label className="flex flex-col items-center justify-center w-full h-64 border-2 border-gray-300 border-dashed rounded-lg cursor-pointer bg-gray-50 dark:hover:bg-bray-800 dark:bg-gray-700 hover:bg-gray-100 dark:border-gray-600 dark:hover:border-gray-500 dark:hover:bg-gray-600">
<div className="flex flex-col items-center justify-center pt-5 pb-6">
<svg
className="w-8 h-8 mb-4 text-gray-500 dark:text-gray-400"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 20 16"
>
<path
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M13 13h3a3 3 0 0 0 0-6h-.025A5.56 5.56 0 0 0 16 6.5 5.5 5.5 0 0 0 5.207 5.021C5.137 5.017 5.071 5 5 5a4 4 0 0 0 0 8h2.167M10 15V6m0 0L8 8m2-2 2 2"
/>
</svg>
<p className="mb-2 text-sm text-gray-500 dark:text-gray-400">
<span className="font-semibold">Click to upload</span> or drag
and drop
</p>
<p className="text-xs text-gray-500 dark:text-gray-400">
SVG, PNG, JPG or GIF (MAX. 800x400px)
</p>
</div>
<input
id="dropzone-file"
type="file"
className="hidden"
onChange={submitMsgFile}
/>
</label>
</div>
{alertMessage && (
<div role="alert" className="alert">
<svg
xmlns="http://www.w3.org/2000/svg"
className="stroke-current shrink-0 h-6 w-6"
fill="none"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
<span>{alertMessage}</span>
<div>
<a href="#results" className="btn btn-sm btn-primary">
Get Results
</a>
</div>
</div>
)}
</div>
</div>
</div>
);
};
export default FileInput;
این submitMsgFile
تابع کنترل کننده گوش می دهد onChange
رویداد از فیلد ورودی این بدان معناست که وقتی کاربر فایلی را آپلود می کند، عملکرد کنترل کننده را فعال می کند.
بعد، عبور از file
به FormData
و ارسال به نقطه پایانی
همانطور که متوجه شدید این کامپوننت دارای پشتیبان تماس است که نتیجه خواننده را به کامپوننت والد ارسال می کند. در سطح صفحه، نتیجه را به اجزای دیگر ارسال می کنیم تا نتیجه نمایش داده شود.
اکنون به سراغ Headers
مؤلفه ای که نتیجه هدر ایمیل را نمایش می دهد:
components/Headers.tsx
"use client";
interface EmailHeadersProps {
headerDetails: string | undefined;
}
const EmailHeaders: React.FC<EmailHeadersProps> = ({ headerDetails }) => {
return (
<div className="px-16 my-8" id="results">
{headerDetails && (
<>
<h3 className="text-2xl font-bold mb-2">Email Headers</h3>
<div className="mockup-code">
<pre data-prefix="~" className="text-xs text-sky-500">
<code
style={{
display: "block",
marginLeft: "50px",
whiteSpace: "pre-wrap",
wordWrap: "break-word",
overflowWrap: "break-word",
wordBreak: "break-all",
}}
>
{headerDetails}
</code>
</pre>
</div>
</>
)}
</div>
);
};
export default EmailHeaders;
و در نهایت Attachments
برای مشاهده نام فایل های پیوست شده
/components/Attachments.tsx
"use client";
interface AttachmentsInterface {
attachmentsDetails: Array<any> | undefined;
}
const AttachmentsHeaders: React.FC<AttachmentsInterface> = ({
attachmentsDetails,
}) => {
return (
<div className="px-16 my-8">
{attachmentsDetails && attachmentsDetails.length > 0 &&(
<>
<h3 className="text-2xl font-bold">Attachments</h3>
<dl className="max-w-md text-gray-900 divide-y divide-gray-200 dark:text-white dark:divide-gray-700">
{attachmentsDetails.map((item) => (
<>
<div className="flex flex-col pb-3">
<dt className="mb-1 text-gray-500 md:text-lg dark:text-gray-400">
{item.attachMimeTag}
</dt>
<dd className="text-lg font-semibold">{item.fileName}</dd>
</div>
</>
))}
</dl>
</>
)}
</div>
);
};
export default AttachmentsHeaders;
نتایج
در پایان نتیجه به شکل زیر خواهد بود:
بعدش چی؟
یک پروژه دیگر به مجموعه شما اضافه شد! به راحتی می توانید جزئیات بیشتری را نمایش دهید یا طرح را همانطور که می خواهید تغییر دهید.
شما باید NextJS خود را در Vercel مستقر کنید تا به صورت عمومی برای دیگران قابل دسترسی باشد. همچنین، به یاد داشته باشید که راه حل خود را به خوبی در فایل ReadMe توضیح دهید زیرا نشان می دهد که کار خود را مستند می کنید.
MSG Reader
ویژگی های کلیدی:
- آپلود فایل MSG: کاربران می توانند فایل های MSG را از طریق یک رابط بصری با پشتیبانی از کشیدن و رها کردن آپلود کنند.
- استخراج داده ها از فایل های MSG: این برنامه از کتابخانه @kenjiuno/msgreader برای استخراج هدرها و سایر داده ها از فایل های MSG استفاده می کند.
- نمایش هدر: داده های استخراج شده در قالبی خوانا نمایش داده می شود.
مثال استفاده:
- به صفحه اصلی برنامه بروید.
- یک فایل MSG را با استفاده از ناحیه آپلود آپلود کنید.
- هدرها و محتوای فایل نمایش داده شده روی صفحه را مشاهده کنید.