-ต้นแบบ โครงสร้าง ไฟล์ API เส้น /api/ttc
This commit is contained in:
40
exthernal-ttc-api/src/utils/errorList.js
Normal file
40
exthernal-ttc-api/src/utils/errorList.js
Normal file
@@ -0,0 +1,40 @@
|
||||
// utils/errorList.js
|
||||
|
||||
export function manualError(key) {
|
||||
switch (key) {
|
||||
case "invalid_input":
|
||||
return {
|
||||
code: 400,
|
||||
messageTh: "ข้อมูลที่ส่งมาไม่ถูกต้อง",
|
||||
messageEn: "Invalid input data"
|
||||
};
|
||||
|
||||
case "not_found":
|
||||
return {
|
||||
code: 404,
|
||||
messageTh: "ไม่พบข้อมูลที่ร้องขอ",
|
||||
messageEn: "Resource not found"
|
||||
};
|
||||
|
||||
case "unauthorized":
|
||||
return {
|
||||
code: 401,
|
||||
messageTh: "คุณไม่มีสิทธิ์เข้าถึงข้อมูลนี้",
|
||||
messageEn: "Unauthorized access"
|
||||
};
|
||||
|
||||
case "server_error":
|
||||
return {
|
||||
code: 500,
|
||||
messageTh: "เกิดข้อผิดพลาดภายในระบบ",
|
||||
messageEn: "Internal server error"
|
||||
};
|
||||
|
||||
default:
|
||||
return {
|
||||
code: 500,
|
||||
messageTh: "ข้อผิดพลาดที่ไม่ทราบสาเหตุ",
|
||||
messageEn: "Unknown error occurred"
|
||||
};
|
||||
}
|
||||
}
|
||||
62
exthernal-ttc-api/src/utils/mailer.js
Normal file
62
exthernal-ttc-api/src/utils/mailer.js
Normal file
@@ -0,0 +1,62 @@
|
||||
import nodemailer from 'nodemailer'
|
||||
import dotenv from 'dotenv'
|
||||
dotenv.config()
|
||||
|
||||
export async function sendMockOtpMail(to, otp) {
|
||||
const transporter = nodemailer.createTransport({
|
||||
service: 'gmail',
|
||||
auth: {
|
||||
user: process.env.SMTP_USER,
|
||||
pass: process.env.SMTP_PASS
|
||||
}
|
||||
})
|
||||
|
||||
const html = `
|
||||
<div style="
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
|
||||
background: linear-gradient(135deg, #f6f9fc 0%, #ecf3f9 100%);
|
||||
padding: 48px 24px;
|
||||
text-align: center;
|
||||
color: #1a1f36;
|
||||
">
|
||||
<div style="
|
||||
max-width: 480px;
|
||||
max-height: auto;
|
||||
margin: 0 auto;
|
||||
background-color: white;
|
||||
border-radius: 16px;
|
||||
padding: 40px;
|
||||
box-shadow: 0 4px 24px rgba(0,0,0,0.08);
|
||||
">
|
||||
<img src="https://cdn.discordapp.com/attachments/1416337856988971152/1431895137595822152/TTCLOGO-Photoroom.png?ex=68ff13c4&is=68fdc244&hm=5af0596e08b3b8a97dcdcca3d6a00d68a1081e6d642c033a4a1cbf8d03e660a6&" alt="Logo" style="height: 80px; margin-bottom: 24px;">
|
||||
<h2 style="
|
||||
color: #1a1f36;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 16px;
|
||||
">รหัส OTP สำหรับเปลี่ยนรหัสผ่าน</h2>
|
||||
<p style="color: #4f566b; font-size: 16px; line-height: 1.5;">กรุณาใส่รหัสยืนยันด้านล่างนี้</p>
|
||||
<div style="
|
||||
font-size: 32px;
|
||||
letter-spacing: 8px;
|
||||
background: linear-gradient(135deg, #fa0000ff 0%, #ff5100ff 100%);
|
||||
color: white;
|
||||
padding: 16px 32px;
|
||||
margin: 24px 0;
|
||||
border-radius: 12px;
|
||||
font-weight: 600;
|
||||
">${otp}</div>
|
||||
<p style="color: #4f566b; font-size: 14px; margin: 24px 0;">รหัสนี้จะหมดอายุใน 5 นาที</p>
|
||||
<hr style="border: none; border-top: 1px solid #e6e8eb; margin: 24px 0;">
|
||||
<p style="color: #697386; font-size: 13px;">หากคุณไม่ได้ร้องขอการเปลี่ยนรหัสผ่าน กรุณาละเว้นอีเมลนี้</p>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
|
||||
await transporter.sendMail({
|
||||
from: `"Support" <${process.env.SMTP_USER}>`,
|
||||
to,
|
||||
subject: 'OTP สำหรับเปลี่ยนรหัสผ่าน',
|
||||
html
|
||||
})
|
||||
}
|
||||
41
exthernal-ttc-api/src/utils/oftenError.js
Normal file
41
exthernal-ttc-api/src/utils/oftenError.js
Normal file
@@ -0,0 +1,41 @@
|
||||
// utils/oftenError.js
|
||||
import { manualError } from "./errorList.js";
|
||||
|
||||
export class OftenError extends Error {
|
||||
/**
|
||||
* ใช้ได้ 2 แบบ:
|
||||
* 1. throw new OftenError("not_found")
|
||||
* 2. throw new OftenError(400, "ไทย", "English")
|
||||
*/
|
||||
constructor(arg1, arg2, arg3) {
|
||||
// แบบ lookup จาก key
|
||||
if (typeof arg1 === "string" && !arg2 && !arg3) {
|
||||
const found = manualError(arg1);
|
||||
super(found.messageEn);
|
||||
this.statusCode = found.code;
|
||||
this.messageTh = found.messageTh;
|
||||
this.messageEn = found.messageEn;
|
||||
this.key = arg1;
|
||||
}
|
||||
|
||||
// แบบ manual
|
||||
else if (typeof arg1 === "number" && arg2 && arg3) {
|
||||
super(arg3);
|
||||
this.statusCode = arg1;
|
||||
this.messageTh = arg2;
|
||||
this.messageEn = arg3;
|
||||
this.key = "manual";
|
||||
}
|
||||
|
||||
// fallback
|
||||
else {
|
||||
super("Invalid error format");
|
||||
this.statusCode = 500;
|
||||
this.messageTh = "รูปแบบการสร้าง error ไม่ถูกต้อง";
|
||||
this.messageEn = "Invalid error constructor format";
|
||||
this.key = "invalid_format";
|
||||
}
|
||||
|
||||
this.name = "OftenError";
|
||||
}
|
||||
}
|
||||
3
exthernal-ttc-api/src/utils/otp.js
Normal file
3
exthernal-ttc-api/src/utils/otp.js
Normal file
@@ -0,0 +1,3 @@
|
||||
export function generateOTP(length = 6) {
|
||||
return Math.floor(100000 + Math.random() * 900000).toString()
|
||||
}
|
||||
28
exthernal-ttc-api/src/utils/redis.js
Normal file
28
exthernal-ttc-api/src/utils/redis.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import Redis from 'ioredis'
|
||||
import dotenv from 'dotenv'
|
||||
dotenv.config()
|
||||
|
||||
const redis = new Redis({
|
||||
host: process.env.REDIS_HOST,
|
||||
port: process.env.REDIS_PORT
|
||||
})
|
||||
|
||||
export async function saveOtp(email, otp) {
|
||||
const key = `otp:${email}`
|
||||
const ttl = parseInt(process.env.OTP_TTL_SECONDS || '300')
|
||||
await redis.setex(key, ttl, otp)
|
||||
}
|
||||
|
||||
export async function verifyOtp(email, otp) {
|
||||
const key = `otp:${email}`
|
||||
const stored = await redis.get(key)
|
||||
if (!stored) return false
|
||||
return stored === otp
|
||||
}
|
||||
|
||||
export async function removeOtp(email) {
|
||||
const key = `otp:${email}`
|
||||
await redis.del(key)
|
||||
}
|
||||
|
||||
export default redis
|
||||
24
exthernal-ttc-api/src/utils/response.js
Normal file
24
exthernal-ttc-api/src/utils/response.js
Normal file
@@ -0,0 +1,24 @@
|
||||
// ===================================================
|
||||
// ⚙️ Nuttakit Response Layer vFinal++++++
|
||||
// ===================================================
|
||||
|
||||
export function sendError(thMsg = 'เกิดข้อผิดพลาดไม่คาดคิดเกิดขึ้น', enMsg = 'Unexpected error', code = 400) {
|
||||
return {
|
||||
code: String(code),
|
||||
message: enMsg,
|
||||
message_th: thMsg,
|
||||
data: []
|
||||
}
|
||||
}
|
||||
|
||||
// ===================================================
|
||||
// 🔹 Auto Success Response (ใช้โดย Global Handler เท่านั้น)
|
||||
// ===================================================
|
||||
export function formatSuccessResponse(data) {
|
||||
return {
|
||||
code: "200",
|
||||
message: "successful",
|
||||
message_th: "ดำเนินการสำเร็จ",
|
||||
data: data || null
|
||||
}
|
||||
}
|
||||
16
exthernal-ttc-api/src/utils/token.js
Normal file
16
exthernal-ttc-api/src/utils/token.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import jwt from 'jsonwebtoken'
|
||||
import dotenv from 'dotenv'
|
||||
dotenv.config()
|
||||
|
||||
export function generateToken(payload) {
|
||||
return jwt.sign(payload, process.env.JWT_SECRET, { expiresIn: '24h' })
|
||||
}
|
||||
|
||||
export function verifyToken(token) {
|
||||
try {
|
||||
return jwt.verify(token, process.env.JWT_SECRET)
|
||||
} catch (err) {
|
||||
console.error("❌ JWT verify error:", err.message);
|
||||
return null
|
||||
}
|
||||
}
|
||||
11
exthernal-ttc-api/src/utils/trim.js
Normal file
11
exthernal-ttc-api/src/utils/trim.js
Normal file
@@ -0,0 +1,11 @@
|
||||
export function trim_all_array(data) {
|
||||
if (!Array.isArray(data)) return data
|
||||
for (let row of data) {
|
||||
for (let key in row) {
|
||||
if (typeof row[key] === 'string') {
|
||||
row[key] = row[key].trim()
|
||||
}
|
||||
}
|
||||
}
|
||||
return data
|
||||
}
|
||||
Reference in New Issue
Block a user