mock login e-Court หน้า /login + identity จาก cookie oacCase แทน localStorage — dropdown ผู้ใช้ MOCK_USERS (user1–user5, utils/user.ts pure module ให้ client+server ใช้ร่วม) รหัสผ่านกลาง Demo1234 ผ่าน server action login (เช็ครายชื่อฝั่ง server เป็น defense กัน hand-craft + delay 500ms ให้เห็น "กำลังตรวจสอบ…") ตั้ง cookie oacCase ตาม format จริงของระบบศาล 16 field — u_userid/u_userlogin ต่างกันต่อคน (= ชื่อผู้ใช้) เพื่อให้สิทธิ์ "แก้ไขได้เฉพาะของตัวเอง" (guard ด้วย userId) แยกกันจริงทั้ง 5 คน httpOnly/sameSite lax/8 ชม. + middleware.ts บังคับ login ทุกหน้า (parse จริงด้วย parseOacCase ไม่ใช่แค่มี cookie — ขยะ/ว่าง/ขาด field = redirect /login; matcher ยกเว้น /login, /api/*, /uploads/*, _next และ static ใน public/ — SSE/export จึงไม่โดน 302) + lib/session.ts getSessionUser อ่าน identity ฝั่ง server ใช้ในทุกหน้า (defense ซ้อน middleware) + PDFViewer รับ user เป็น prop จาก annotate page ตั้งแต่ first paint (หมดช่วง null user ที่เคยสร้าง annotation ด้วย userId="" ได้ + ไม่มี hydration mismatch; Server Actions ไม่ต้องแก้ — vString รับ userId ใหม่อยู่แล้ว) + SessionBar แสดง "เข้าสู่ระบบเป็น <user>" + ปุ่มออกจากระบบ (ลบ cookie ด้วย path "/" ตรงตอน set + redirect ใน action เอง — client router.replace เองชนกับ re-render ของหน้าที่เพิ่งเสีย session จน navigation ไม่เกิด) แทน UserPicker mock 10 คน (ลบไฟล์พร้อม MOCK_USERS/localStorage/getLocalUser ทั้งชุด) + LoginForm การ์ด max-w-sm กลางจอ reuse brand lockup และปุ่ม primary เดิม, input text-base 16px กัน iOS zoom บน iPad, dropdown placeholder "เลือกผู้ใช้" บังคับเลือก (ไม่ preselect กัน login ผิดคนโดยไม่ตั้งใจ), error แถบเดียว role=alert "รหัสผ่านไม่ถูกต้อง" (dropdown เลือกผิดไม่ได้แล้ว), ตอนผิดล้าง password คงผู้ใช้ที่เลือกไว้ + focus+select + tests/utils/user.test.ts ล็อก format จริงของ e-Court (parse ตัวอย่าง cookie จริง 235821/tu_2, garbage/empty/ขาด field → null, round-trip, buildOacCaseCookie ครบ 16 field) + sync CLAUDE.md/PLAN.md §0 A4/README — annotation สมัย mock-user-01/UUID ไม่ใช่ของตัวเองอีก (auth จริงเทียบระบบศาล + roles ยัง out of scope; /api/* และ /uploads/* ยังไม่ต้อง login ตามขอบเขต mock)
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
parent
460cd9c600
commit
65b72cf817
16 changed files with 414 additions and 131 deletions
|
|
@ -1,51 +1,53 @@
|
|||
// anonymous identity เก็บใน localStorage สร้างครั้งเดียวต่อ browser (PLAN.md §0 A4)
|
||||
// ใช้เติม field userId/userName ในตาราง annotations/bookmarks — ไม่มีระบบ auth
|
||||
// identity ของแอป: mock login e-Court หน้า /login — อ่านจาก cookie "oacCase"
|
||||
// (userId = u_userid, userName = u_userlogin) แทน localStorage เดิม
|
||||
// ไฟล์นี้เป็น pure module — middleware (edge) และ client import ร่วมได้ ห้ามใส่ next/headers
|
||||
|
||||
export type LocalUser = { userId: string; userName: string };
|
||||
export type OacUser = { userId: string; userName: string };
|
||||
|
||||
const STORAGE_KEY = "judes-note:user";
|
||||
export const OAC_CASE_COOKIE = "oacCase";
|
||||
|
||||
// mock users สำหรับเลือกที่หน้าแรก (demo ไม่มีระบบ auth) — userId คงที่
|
||||
// เพื่อให้กรองรายคนและสิทธิ์ "แก้ไขได้เฉพาะของตัวเอง" ทำงานสม่ำเสมอข้าม refresh
|
||||
export const MOCK_USERS: LocalUser[] = [
|
||||
{ userId: "mock-user-01", userName: "ผู้พิพากษา สมชาย" },
|
||||
{ userId: "mock-user-02", userName: "ผู้พิพากษา สมหญิง" },
|
||||
{ userId: "mock-user-03", userName: "อัยการ วิชัย" },
|
||||
{ userId: "mock-user-04", userName: "เลขานุการศาล ปิยะ" },
|
||||
{ userId: "mock-user-05", userName: "ทนายโจทก์ ณัฐ" },
|
||||
{ userId: "mock-user-06", userName: "ทนายจำเลย อรุณี" },
|
||||
{ userId: "mock-user-07", userName: "ผู้ช่วยผู้พิพากษา กันต์" },
|
||||
{ userId: "mock-user-08", userName: "พนักงานสอบสวน เดชา" },
|
||||
{ userId: "mock-user-09", userName: "ผู้เชี่ยวชาญ มานะ" },
|
||||
{ userId: "mock-user-10", userName: "ผู้ช่วยเลขานุการ ฝ้าย" },
|
||||
/** ผู้ใช้ mock หน้า /login (dropdown) — LoginForm (client) + action login (server)
|
||||
* ใช้ร่วมกันผ่าน module นี้กันสองที่ drift; รหัสผ่านกลาง Demo1234 อยู่ใน action */
|
||||
export const MOCK_USERS: readonly string[] = [
|
||||
"user1",
|
||||
"user2",
|
||||
"user3",
|
||||
"user4",
|
||||
"user5",
|
||||
];
|
||||
|
||||
export function setLocalUser(user: LocalUser): void {
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(user));
|
||||
}
|
||||
|
||||
// อ่าน identity ที่เก็บไว้โดยไม่สร้างใหม่ — ใช้แสดงค่าปัจจุบันในหน้าเลือกผู้ใช้
|
||||
export function getStoredLocalUser(): LocalUser | null {
|
||||
const raw = localStorage.getItem(STORAGE_KEY);
|
||||
if (raw) {
|
||||
try {
|
||||
const parsed = JSON.parse(raw) as LocalUser;
|
||||
if (typeof parsed.userId === "string" && typeof parsed.userName === "string") {
|
||||
return parsed;
|
||||
}
|
||||
} catch {
|
||||
// ข้อมูลเก่าเสียหาย → ถือว่าไม่มีข้อมูล
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function getLocalUser(): LocalUser {
|
||||
const stored = getStoredLocalUser();
|
||||
if (stored) return stored;
|
||||
|
||||
const userId = crypto.randomUUID();
|
||||
const userName = `ผู้ใช้ ${userId.slice(0, 4).toUpperCase()}`;
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify({ userId, userName }));
|
||||
/** แยกค่า query string ของ cookie oacCase → identity
|
||||
* ขาด/ว่าง u_userid หรือ u_userlogin = ถือว่ายังไม่เข้าสู่ระบบ (null)
|
||||
* หมายเหตุ: Next (cookies().get / req.cookies.get) decode ค่า cookie กลับมาให้แล้ว
|
||||
* จึงส่งให้ URLSearchParams ตรง ๆ — ห้าม decodeURIComponent ซ้ำ */
|
||||
export function parseOacCase(raw: string | null | undefined): OacUser | null {
|
||||
if (!raw) return null;
|
||||
const params = new URLSearchParams(raw);
|
||||
const userId = params.get("u_userid")?.trim();
|
||||
const userName = params.get("u_userlogin")?.trim();
|
||||
if (!userId || !userName) return null;
|
||||
return { userId, userName };
|
||||
}
|
||||
|
||||
/** ค่า cookie oacCase ตาม format จริงของ e-Court (ฟิลด์อื่นคงค่าจากตัวอย่างจริง)
|
||||
* mock login แทนเฉพาะ u_userid/u_userlogin */
|
||||
export function buildOacCaseCookie(userId: string, userLogin: string): string {
|
||||
return [
|
||||
`u_userid=${userId}`,
|
||||
`u_userlogin=${userLogin}`,
|
||||
"u_courtid=4",
|
||||
"u_password=",
|
||||
"u_AdminStatus=",
|
||||
"u_perCardNo=5000000000006",
|
||||
"u_perCardNoEncript=1800650010005002003",
|
||||
"u_userType=4",
|
||||
"u_CidAuthen=NNNENNNNNNNNNNNNNNNN",
|
||||
"u_hSecId=NNNNNNNNNNNNNNNNNNNN",
|
||||
"u_username=",
|
||||
"u_courtName=",
|
||||
"u_AuditID=1995227",
|
||||
"u_PsGroupNum=1",
|
||||
"u_PsGroup=11",
|
||||
"u_PsGroupName=",
|
||||
].join("&");
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue