backen: jwt
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
[/dms]
|
||||
max_log = 491862
|
||||
number = 1
|
||||
max_log = 494130
|
||||
number = 3
|
||||
finish = 1
|
||||
|
||||
13463
.qsync/meta/qmeta0
13463
.qsync/meta/qmeta0
File diff suppressed because it is too large
Load Diff
13476
.qsync/meta/qmeta1
Normal file
13476
.qsync/meta/qmeta1
Normal file
File diff suppressed because it is too large
Load Diff
7732
.qsync/meta/qmeta2
Normal file
7732
.qsync/meta/qmeta2
Normal file
File diff suppressed because it is too large
Load Diff
483
Bearer-Token.patch.diff
Executable file
483
Bearer-Token.patch.diff
Executable file
@@ -0,0 +1,483 @@
|
||||
diff --git a/backend/src/middleware/requireBearer.js b/backend/src/middleware/requireBearer.js
|
||||
new file mode 100644
|
||||
index 0000000..1111111
|
||||
--- /dev/null
|
||||
+++ b/backend/src/middleware/requireBearer.js
|
||||
@@ -0,0 +1,44 @@
|
||||
+// backend/src/middleware/requireBearer.js
|
||||
+import jwt from "jsonwebtoken";
|
||||
+import { findUserById } from "../db/models/users.js";
|
||||
+
|
||||
+export async function requireBearer(req, res, next) {
|
||||
+ const hdr = req.get("Authorization") || "";
|
||||
+ const m = hdr.match(/^Bearer\s+(.+)$/i);
|
||||
+ if (!m) return res.status(401).json({ error: "Unauthenticated" });
|
||||
+ try {
|
||||
+ const payload = jwt.verify(m[1], process.env.JWT_ACCESS_SECRET, {
|
||||
+ issuer: "dms-backend",
|
||||
+ });
|
||||
+ const user = await findUserById(payload.user_id);
|
||||
+ if (!user) return res.status(401).json({ error: "Unauthenticated" });
|
||||
+ req.user = {
|
||||
+ user_id: user.user_id,
|
||||
+ username: user.username,
|
||||
+ email: user.email,
|
||||
+ first_name: user.first_name,
|
||||
+ last_name: user.last_name,
|
||||
+ };
|
||||
+ next();
|
||||
+ } catch {
|
||||
+ return res.status(401).json({ error: "Unauthenticated" });
|
||||
+ }
|
||||
+}
|
||||
diff --git a/backend/src/routes/auth.js b/backend/src/routes/auth.js
|
||||
index 2222222..3333333 100644
|
||||
--- a/backend/src/routes/auth.js
|
||||
+++ b/backend/src/routes/auth.js
|
||||
@@ -1,99 +1,109 @@
|
||||
-// (เดิม) ผูกกับคุกกี้ / ส่ง ok:true ฯลฯ
|
||||
+// backend/src/routes/auth.js — Bearer Token ล้วน
|
||||
import { Router } from "express";
|
||||
import jwt from "jsonwebtoken";
|
||||
-import { findUserByUsername } from "../db/models/users.js";
|
||||
+import { findUserByUsername, findUserById } from "../db/models/users.js";
|
||||
import { verifyPassword } from "../utils/passwords.js";
|
||||
-// NOTE: ลบการใช้งาน res.cookie(...) ทั้งหมด
|
||||
+// NOTE: ไม่มีการใช้ res.cookie(...) อีกต่อไป
|
||||
|
||||
const router = Router();
|
||||
|
||||
function signAccessToken(user) {
|
||||
return jwt.sign(
|
||||
{ user_id: user.user_id, username: user.username },
|
||||
process.env.JWT_ACCESS_SECRET,
|
||||
- { issuer: "dms-backend", expiresIn: "30m" } // ปรับได้
|
||||
+ { issuer: "dms-backend", expiresIn: "30m" }
|
||||
);
|
||||
}
|
||||
function signRefreshToken(user) {
|
||||
return jwt.sign(
|
||||
- { user_id: user.user_id, username: user.username },
|
||||
+ { user_id: user.user_id, username: user.username, t: "refresh" },
|
||||
process.env.JWT_REFRESH_SECRET,
|
||||
{ issuer: "dms-backend", expiresIn: "30d" }
|
||||
);
|
||||
}
|
||||
|
||||
router.post("/login", async (req, res) => {
|
||||
const { username, password } = req.body || {};
|
||||
const user = await findUserByUsername(username);
|
||||
if (!user || !(await verifyPassword(password, user.password_hash))) {
|
||||
return res.status(401).json({ error: "INVALID_CREDENTIALS" });
|
||||
}
|
||||
const token = signAccessToken(user);
|
||||
const refresh_token = signRefreshToken(user);
|
||||
return res.json({
|
||||
token,
|
||||
refresh_token,
|
||||
user: {
|
||||
user_id: user.user_id,
|
||||
username: user.username,
|
||||
email: user.email,
|
||||
first_name: user.first_name,
|
||||
last_name: user.last_name,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
+router.post("/refresh", async (req, res) => {
|
||||
+ const hdr = req.get("Authorization") || "";
|
||||
+ const m = hdr.match(/^Bearer\s+(.+)$/i);
|
||||
+ const r = m?.[1];
|
||||
+ if (!r) return res.status(401).json({ error: "NO_REFRESH_TOKEN" });
|
||||
+ try {
|
||||
+ const payload = jwt.verify(r, process.env.JWT_REFRESH_SECRET, {
|
||||
+ issuer: "dms-backend",
|
||||
+ });
|
||||
+ const user = await findUserById(payload.user_id);
|
||||
+ if (!user) return res.status(401).json({ error: "USER_NOT_FOUND" });
|
||||
+ const token = signAccessToken(user);
|
||||
+ return res.json({ token });
|
||||
+ } catch {
|
||||
+ return res.status(401).json({ error: "INVALID_REFRESH_TOKEN" });
|
||||
+ }
|
||||
+});
|
||||
+
|
||||
export default router;
|
||||
diff --git a/backend/src/index.js b/backend/src/index.js
|
||||
index 4444444..5555555 100644
|
||||
--- a/backend/src/index.js
|
||||
+++ b/backend/src/index.js
|
||||
@@ -1,60 +1,69 @@
|
||||
import express from "express";
|
||||
import cors from "cors";
|
||||
import authRouter from "./routes/auth.js";
|
||||
+import { requireBearer } from "./middleware/requireBearer.js";
|
||||
-// import routers อื่น ๆ ตามจริง เช่น rfasRouter, transmittalsRouter
|
||||
|
||||
const app = express();
|
||||
|
||||
-// CORS เดิม (อาจมี credentials)
|
||||
-app.use(cors({
|
||||
- origin: true,
|
||||
- credentials: true,
|
||||
-}));
|
||||
+// ✅ CORS สำหรับ Bearer: ไม่ต้อง credentials, อนุญาต Authorization header
|
||||
+app.use(cors({
|
||||
+ origin: [
|
||||
+ "https://lcbp3.np-dms.work",
|
||||
+ "http://localhost:3000"
|
||||
+ ],
|
||||
+ methods: ["GET","POST","PUT","PATCH","DELETE","OPTIONS"],
|
||||
+ allowedHeaders: ["Authorization","Content-Type","Accept","Origin","Referer","User-Agent","X-Requested-With","Cache-Control","Pragma"],
|
||||
+ exposedHeaders: ["Content-Disposition","Content-Length"]
|
||||
+}));
|
||||
|
||||
app.use(express.json());
|
||||
|
||||
-// routes เดิม
|
||||
-app.use("/api/auth", authRouter);
|
||||
-// app.use("/api/rfas", rfasRouter);
|
||||
-// app.use("/api/transmittals", transmittalsRouter);
|
||||
+// ✅ เส้นทาง auth (ไม่ต้องมี token)
|
||||
+app.use("/api/auth", authRouter);
|
||||
+
|
||||
+// ✅ ตั้ง guard สำหรับเส้นทางที่เหลือต้องล็อกอิน
|
||||
+app.use("/api", requireBearer);
|
||||
+// แล้วค่อย mount routers protected ใต้ /api
|
||||
+// app.use("/api/rfas", rfasRouter);
|
||||
+// app.use("/api/transmittals", transmittalsRouter);
|
||||
|
||||
app.use((err, _req, res, _next) => {
|
||||
console.error(err);
|
||||
res.status(500).json({ error: "INTERNAL_SERVER_ERROR" });
|
||||
});
|
||||
|
||||
const port = process.env.PORT || 4000;
|
||||
app.listen(port, () => console.log(`backend listening on :${port}`));
|
||||
diff --git a/frontend/app/(auth)/login/page.jsx b/frontend/app/(auth)/login/page.jsx
|
||||
index 6666666..7777777 100644
|
||||
--- a/frontend/app/(auth)/login/page.jsx
|
||||
+++ b/frontend/app/(auth)/login/page.jsx
|
||||
@@ -1,200 +1,236 @@
|
||||
// File: frontend/app/(auth)/login/page.jsx
|
||||
"use client";
|
||||
|
||||
-// เวอร์ชันเดิม
|
||||
+// ✅ Bearer-only + Debug toggle (NEXT_PUBLIC_DEBUG_AUTH)
|
||||
import { useState, useMemo, Suspense } from "react";
|
||||
import { useSearchParams, useRouter } from "next/navigation";
|
||||
import {
|
||||
Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter,
|
||||
} from "@/components/ui/card";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Alert, AlertDescription } from "@/components/ui/alert";
|
||||
|
||||
-const API_BASE = process.env.NEXT_PUBLIC_API_BASE?.replace(/\/$/, "") || "";
|
||||
+const API_BASE = process.env.NEXT_PUBLIC_API_BASE?.replace(/\/$/, "") || "";
|
||||
+const DEBUG =
|
||||
+ String(process.env.NEXT_PUBLIC_DEBUG_AUTH || "").trim() !== "" &&
|
||||
+ process.env.NEXT_PUBLIC_DEBUG_AUTH !== "0" &&
|
||||
+ process.env.NEXT_PUBLIC_DEBUG_AUTH !== "false";
|
||||
+function dlog(...args) {
|
||||
+ if (DEBUG && typeof window !== "undefined") console.debug("[login]", ...args);
|
||||
+}
|
||||
|
||||
function LoginForm() {
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
const nextPath = useMemo(
|
||||
() => searchParams.get("next") || "/dashboard",
|
||||
[searchParams]
|
||||
);
|
||||
|
||||
const [username, setUsername] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
const [showPw, setShowPw] = useState(false);
|
||||
const [remember, setRemember] = useState(false);
|
||||
const [submitting, setSubmitting] = useState(false);
|
||||
const [err, setErr] = useState("");
|
||||
|
||||
async function onSubmit(e) {
|
||||
e.preventDefault();
|
||||
setErr("");
|
||||
if (!username.trim() || !password) {
|
||||
setErr("กรอกชื่อผู้ใช้และรหัสผ่านให้ครบ");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
setSubmitting(true);
|
||||
+ dlog("API_BASE =", API_BASE || "(empty → relative)");
|
||||
+ dlog("nextPath =", nextPath, "remember =", remember);
|
||||
|
||||
const res = await fetch(`${API_BASE}/api/auth/login`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ username, password }),
|
||||
cache: "no-store",
|
||||
});
|
||||
- const data = await res.json().catch(() => ({}));
|
||||
+ dlog("response.status =", res.status);
|
||||
+ dlog("response.headers.content-type =", res.headers.get("content-type"));
|
||||
+ let data = {};
|
||||
+ try { data = await res.json(); } catch (e) { dlog("response.json() error =", e); }
|
||||
+ dlog("response.body =", data);
|
||||
|
||||
if (!res.ok) {
|
||||
- setErr(data?.error || "เข้าสู่ระบบไม่สำเร็จ");
|
||||
+ const msg =
|
||||
+ data?.error === "INVALID_CREDENTIALS"
|
||||
+ ? "ชื่อผู้ใช้หรือรหัสผ่านไม่ถูกต้อง"
|
||||
+ : data?.error || `เข้าสู่ระบบไม่สำเร็จ (HTTP ${res.status})`;
|
||||
+ dlog("login FAILED →", msg);
|
||||
+ setErr(msg);
|
||||
return;
|
||||
}
|
||||
+ if (!data?.token) {
|
||||
+ dlog("login FAILED → data.token not found");
|
||||
+ setErr("รูปแบบข้อมูลตอบกลับไม่ถูกต้อง (ไม่มี token)");
|
||||
+ return;
|
||||
+ }
|
||||
|
||||
const storage = remember ? window.localStorage : window.sessionStorage;
|
||||
storage.setItem("dms.token", data.token);
|
||||
storage.setItem("dms.refresh_token", data.refresh_token);
|
||||
storage.setItem("dms.user", JSON.stringify(data.user || {}));
|
||||
+ dlog("token stored in", remember ? "localStorage" : "sessionStorage");
|
||||
|
||||
try {
|
||||
window.dispatchEvent(
|
||||
new StorageEvent("storage", { key: "dms.auth", newValue: "login" })
|
||||
);
|
||||
} catch {}
|
||||
- router.replace(nextPath);
|
||||
+ dlog("navigating →", nextPath);
|
||||
+ router.replace(nextPath);
|
||||
} catch (e) {
|
||||
+ dlog("exception =", e);
|
||||
setErr("เชื่อมต่อเซิร์ฟเวอร์ไม่ได้ กรุณาลองใหม่");
|
||||
} finally {
|
||||
setSubmitting(false);
|
||||
+ dlog("done");
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="grid min-h-[calc(100vh-4rem)] place-items-center p-4">
|
||||
<Card className="w-full max-w-md border-0 shadow-xl ring-1 ring-black/5 bg-white/90 backdrop-blur">
|
||||
<CardHeader className="space-y-1">
|
||||
<CardTitle className="text-2xl font-bold text-sky-800">เข้าสู่ระบบ</CardTitle>
|
||||
<CardDescription className="text-sky-700">Document Management System • LCBP3</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
{err ? (
|
||||
<Alert className="mb-4"><AlertDescription>{err}</AlertDescription></Alert>
|
||||
) : null}
|
||||
<form onSubmit={onSubmit} className="grid gap-4">
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="username">ชื่อผู้ใช้</Label>
|
||||
<Input id="username" autoFocus autoComplete="username" value={username}
|
||||
onChange={(e) => setUsername(e.target.value)} placeholder="เช่น superadmin" disabled={submitting}/>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="password">รหัสผ่าน</Label>
|
||||
<div className="relative">
|
||||
<Input id="password" type={showPw ? "text" : "password"} autoComplete="current-password"
|
||||
value={password} onChange={(e) => setPassword(e.target.value)} placeholder="••••••••"
|
||||
disabled={submitting} className="pr-10"/>
|
||||
<button type="button" onClick={() => setShowPw((v) => !v)}
|
||||
className="absolute inset-y-0 px-2 my-auto text-xs bg-white border rounded-md right-2 hover:bg-slate-50"
|
||||
aria-label={showPw ? "ซ่อนรหัสผ่าน" : "แสดงรหัสผ่าน"} disabled={submitting}>
|
||||
{showPw ? "Hide" : "Show"}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center justify-between pt-1">
|
||||
<label className="inline-flex items-center gap-2 text-sm text-slate-600">
|
||||
<input type="checkbox" className="size-4 accent-sky-700"
|
||||
checked={remember} onChange={(e) => setRemember(e.target.checked)} disabled={submitting}/>
|
||||
จดจำฉันไว้ในเครื่องนี้
|
||||
</label>
|
||||
<a href="/forgot-password" className="text-sm text-sky-700 hover:text-sky-900 hover:underline">ลืมรหัสผ่าน?</a>
|
||||
</div>
|
||||
<Button type="submit" disabled={submitting} className="mt-2 bg-sky-700 hover:bg-sky-800">
|
||||
{submitting ? (<span className="inline-flex items-center gap-2"><Spinner /> กำลังเข้าสู่ระบบ…</span>) : ("เข้าสู่ระบบ")}
|
||||
</Button>
|
||||
+ {DEBUG ? (
|
||||
+ <p className="mt-2 text-xs text-slate-500">
|
||||
+ DEBUG: NEXT_PUBLIC_API_BASE = <code>{API_BASE || "(empty)"}</code>
|
||||
+ </p>
|
||||
+ ) : null}
|
||||
</form>
|
||||
</CardContent>
|
||||
<CardFooter className="text-xs text-center text-slate-500">
|
||||
© {new Date().getFullYear()} np-dms.work
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default function LoginPage() {
|
||||
return (
|
||||
<Suspense fallback={<LoginPageSkeleton />}>
|
||||
<LoginForm />
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
|
||||
function LoginPageSkeleton() {
|
||||
return (
|
||||
<div className="grid min-h-[calc(100vh-4rem)] place-items-center p-4">
|
||||
<Card className="w-full max-w-md border-0 shadow-xl ring-1 ring-black/5 bg-white/90 backdrop-blur">
|
||||
<CardHeader className="space-y-1">
|
||||
<CardTitle className="text-2xl font-bold text-sky-800">เข้าสู่ระบบ</CardTitle>
|
||||
<CardDescription className="text-sky-700">Document Management System • LCBP3</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="grid gap-4 animate-pulse">
|
||||
<div className="h-10 rounded bg-slate-200"></div>
|
||||
<div className="h-10 rounded bg-slate-200"></div>
|
||||
<div className="h-10 rounded bg-slate-200"></div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function Spinner() {
|
||||
return (
|
||||
<svg className="animate-spin size-4" viewBox="0 0 24 24" fill="none" aria-hidden="true">
|
||||
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
|
||||
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
diff --git a/frontend/app/(protected)/layout.jsx b/frontend/app/(protected)/layout.jsx
|
||||
new file mode 100644
|
||||
index 0000000..8888888
|
||||
--- /dev/null
|
||||
+++ b/frontend/app/(protected)/layout.jsx
|
||||
@@ -0,0 +1,38 @@
|
||||
+"use client";
|
||||
+import { useEffect, useState } from "react";
|
||||
+import { usePathname, useRouter } from "next/navigation";
|
||||
+
|
||||
+export default function ProtectedLayout({ children }) {
|
||||
+ const router = useRouter();
|
||||
+ const pathname = usePathname();
|
||||
+ const [ready, setReady] = useState(false);
|
||||
+
|
||||
+ useEffect(() => {
|
||||
+ try {
|
||||
+ const token =
|
||||
+ (typeof window !== "undefined" &&
|
||||
+ (localStorage.getItem("dms.token") ||
|
||||
+ sessionStorage.getItem("dms.token"))) ||
|
||||
+ null;
|
||||
+ if (!token) {
|
||||
+ const next = encodeURIComponent(pathname || "/dashboard");
|
||||
+ router.replace(`/login?next=${next}`);
|
||||
+ return;
|
||||
+ }
|
||||
+ } finally {
|
||||
+ setReady(true);
|
||||
+ }
|
||||
+ }, [pathname, router]);
|
||||
+
|
||||
+ if (!ready) {
|
||||
+ return (
|
||||
+ <div className="grid min-h-[calc(100vh-4rem)] place-items-center p-6 text-slate-600">
|
||||
+ กำลังตรวจสิทธิ์…
|
||||
+ </div>
|
||||
+ );
|
||||
+ }
|
||||
+ return <>{children}</>;
|
||||
+}
|
||||
diff --git a/frontend/lib/api.js b/frontend/lib/api.js
|
||||
new file mode 100644
|
||||
index 0000000..9999999
|
||||
--- /dev/null
|
||||
+++ b/frontend/lib/api.js
|
||||
@@ -0,0 +1,45 @@
|
||||
+// frontend/lib/api.js
|
||||
+const API_BASE = process.env.NEXT_PUBLIC_API_BASE?.replace(/\/$/, "") || "";
|
||||
+
|
||||
+function getToken() {
|
||||
+ if (typeof window === "undefined") return null;
|
||||
+ return localStorage.getItem("dms.token") || sessionStorage.getItem("dms.token");
|
||||
+}
|
||||
+
|
||||
+export async function apiFetch(path, options = {}) {
|
||||
+ const token = getToken();
|
||||
+ const headers = new Headers(options.headers || {});
|
||||
+ headers.set("Accept", "application/json");
|
||||
+ if (!headers.has("Content-Type")) headers.set("Content-Type", "application/json");
|
||||
+ if (token) headers.set("Authorization", `Bearer ${token}`);
|
||||
+
|
||||
+ const res = await fetch(`${API_BASE}${path}`, { ...options, headers, cache: "no-store" });
|
||||
+
|
||||
+ if (res.status === 401) {
|
||||
+ const refresh =
|
||||
+ localStorage.getItem("dms.refresh_token") || sessionStorage.getItem("dms.refresh_token");
|
||||
+ if (refresh) {
|
||||
+ const r = await fetch(`${API_BASE}/api/auth/refresh`, {
|
||||
+ method: "POST",
|
||||
+ headers: { Authorization: `Bearer ${refresh}` },
|
||||
+ });
|
||||
+ if (r.ok) {
|
||||
+ const { token: newToken } = await r.json();
|
||||
+ const store = localStorage.getItem("dms.refresh_token") ? localStorage : sessionStorage;
|
||||
+ store.setItem("dms.token", newToken);
|
||||
+ const headers2 = new Headers(headers);
|
||||
+ headers2.set("Authorization", `Bearer ${newToken}`);
|
||||
+ return fetch(`${API_BASE}${path}`, { ...options, headers: headers2, cache: "no-store" });
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ return res;
|
||||
+}
|
||||
diff --git a/frontend/middleware.ts b/frontend/middleware.ts
|
||||
index aaaaaaa..bbbbbbb 100644
|
||||
--- a/frontend/middleware.ts
|
||||
+++ b/frontend/middleware.ts
|
||||
@@ -1,15 +1,14 @@
|
||||
-import { NextResponse } from "next/server";
|
||||
-import type { NextRequest } from "next/server";
|
||||
-
|
||||
-// เดิม: ตรวจคุกกี้แล้ว redirect /dashboard
|
||||
-export function middleware(req: NextRequest) {
|
||||
- // ... logic เดิมที่ใช้คุกกี้
|
||||
- return NextResponse.next();
|
||||
-}
|
||||
-
|
||||
-export const config = {
|
||||
- matcher: ["/(protected/:path*)","/dashboard","/users/:path*","/api/:path*"],
|
||||
-};
|
||||
+import { NextResponse } from "next/server";
|
||||
+// ✅ ไม่บล็อกเพจอีกต่อไป (Bearer อยู่ใน storage ฝั่ง client)
|
||||
+export function middleware() {
|
||||
+ return NextResponse.next();
|
||||
+}
|
||||
+// จำกัดให้ทำงานเฉพาะ /api ถ้าต้องการใช้ในอนาคต (ตอนนี้ผ่านเฉย ๆ)
|
||||
+export const config = { matcher: ["/api/:path*"] };
|
||||
diff --git a/frontend/app/(protected)/dashboard/page.jsx b/frontend/app/(protected)/dashboard/page.jsx
|
||||
new file mode 100644
|
||||
index 0000000..ccccccc
|
||||
--- /dev/null
|
||||
+++ b/frontend/app/(protected)/dashboard/page.jsx
|
||||
@@ -0,0 +1,11 @@
|
||||
+"use client";
|
||||
+export default function DashboardPage() {
|
||||
+ return (
|
||||
+ <main className="p-6">
|
||||
+ <h1 className="text-2xl font-semibold text-sky-800">Dashboard</h1>
|
||||
+ <p className="text-slate-600 mt-2">
|
||||
+ ยินดีต้อนรับสู่ DMS
|
||||
+ </p>
|
||||
+ </main>
|
||||
+ );
|
||||
+}
|
||||
64
backend/fix-bearer-index.patch.diff
Executable file
64
backend/fix-bearer-index.patch.diff
Executable file
@@ -0,0 +1,64 @@
|
||||
diff --git a/src/index.js b/src/index.js
|
||||
--- a/src/index.js
|
||||
+++ b/src/index.js
|
||||
@@ -1,9 +1,8 @@
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import express from "express";
|
||||
-import cookieParser from "cookie-parser";
|
||||
import cors from "cors";
|
||||
|
||||
import sql from "./db/index.js";
|
||||
import healthRouter from "./routes/health.js";
|
||||
import { authJwt } from "./middleware/authJwt.js";
|
||||
@@ -64,7 +63,7 @@
|
||||
// ✅ อยู่หลัง NPM/Reverse proxy → ให้ trust proxy เพื่อให้ cookie secure / proto ทำงานถูก
|
||||
app.set("trust proxy", 1);
|
||||
|
||||
-// CORS แบบกำหนด origin ตามรายการที่อนุญาต + อนุญาต credentials (จำเป็นสำหรับ cookie)
|
||||
+// ✅ CORS สำหรับ Bearer token: ไม่ต้องใช้ credentials (ไม่มีคุกกี้)
|
||||
app.use(
|
||||
cors({
|
||||
origin(origin, cb) {
|
||||
if (!origin) return cb(null, true); // server-to-server / curl
|
||||
return cb(null, ALLOW_ORIGINS.includes(origin));
|
||||
},
|
||||
- credentials: true,
|
||||
+ credentials: false,
|
||||
methods: ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"],
|
||||
- allowedHeaders: ["Content-Type", "Authorization", "X-Requested-With"],
|
||||
+ allowedHeaders: [
|
||||
+ "Content-Type",
|
||||
+ "Authorization",
|
||||
+ "X-Requested-With",
|
||||
+ "Accept",
|
||||
+ "Origin",
|
||||
+ "Referer",
|
||||
+ "User-Agent",
|
||||
+ "Cache-Control",
|
||||
+ "Pragma"
|
||||
+ ],
|
||||
exposedHeaders: ["Content-Disposition", "Content-Length"],
|
||||
})
|
||||
);
|
||||
// preflight
|
||||
app.options(
|
||||
"*",
|
||||
cors({
|
||||
origin(origin, cb) {
|
||||
if (!origin) return cb(null, true);
|
||||
return cb(null, ALLOW_ORIGINS.includes(origin));
|
||||
},
|
||||
- credentials: true,
|
||||
+ credentials: false,
|
||||
})
|
||||
);
|
||||
|
||||
-app.use(cookieParser());
|
||||
+// ❌ ไม่ต้อง parse cookie แล้ว (เราไม่ใช้คุกกี้สำหรับ auth)
|
||||
+// app.use(cookieParser());
|
||||
|
||||
// Payload limits
|
||||
app.use(express.json({ limit: "10mb" }));
|
||||
app.use(express.urlencoded({ extended: true, limit: "10mb" }));
|
||||
|
||||
@@ -84,7 +84,7 @@ services:
|
||||
JWT_SECRET: "8b0df02e4aee9f9f79a4f2d8ba77b0b82c1ee3446b68cb0bae94ab54d60f8d9e"
|
||||
JWT_EXPIRES_IN: "12h"
|
||||
PASSWORD_SALT_ROUNDS: "10"
|
||||
FRONTEND_ORIGIN: "https://lcbp3.mycloudnas.com"
|
||||
FRONTEND_ORIGIN: "https://lcbp3.np-dms.work"
|
||||
CORS_ORIGINS: "https://backend.np-dms.work,http://localhost:3000,http://127.0.0.1:3000"
|
||||
RATE_LIMIT_WINDOW_MS: "900000"
|
||||
RATE_LIMIT_MAX: "200"
|
||||
@@ -129,8 +129,11 @@ services:
|
||||
# NEXT_PUBLIC_API_BASE: "/api"
|
||||
CHOKIDAR_USEPOLLING: "1"
|
||||
WATCHPACK_POLLING: "true"
|
||||
NEXT_PUBLIC_API_BASE: "https://lcbp3.np-dms.work/api"
|
||||
NEXT_PUBLIC_API_BASE: "https://lcbp3.np-dms.work"
|
||||
NEXT_PUBLIC_DEBUG_AUTH: "1"
|
||||
NEXT_TELEMETRY_DISABLED: "1"
|
||||
JWT_ACCESS_SECRET: "change-this-access-secret"
|
||||
JWT_REFRESH_SECRET: "change-this-refresh-secret"
|
||||
expose:
|
||||
- "3000"
|
||||
networks: [dmsnet]
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
// - ไม่ใช้ credentials: "include" อีกต่อไป
|
||||
// - เอา RootLayout/metadata ออก เพราะไฟล์เพจเป็น client component
|
||||
// - เพิ่มการอ่าน NEXT_PUBLIC_API_BASE และ error handling ให้ตรงกับ backend
|
||||
// - เพิ่มโหมดดีบัก เปิดด้วย NEXT_PUBLIC_DEBUG_AUTH=1
|
||||
|
||||
import { useState, useMemo, Suspense } from "react";
|
||||
import { useSearchParams, useRouter } from "next/navigation";
|
||||
@@ -25,6 +26,16 @@ import { Button } from "@/components/ui/button";
|
||||
import { Alert, AlertDescription } from "@/components/ui/alert";
|
||||
|
||||
const API_BASE = process.env.NEXT_PUBLIC_API_BASE?.replace(/\/$/, "") || "";
|
||||
const DEBUG =
|
||||
String(process.env.NEXT_PUBLIC_DEBUG_AUTH || "").trim() !== "" &&
|
||||
process.env.NEXT_PUBLIC_DEBUG_AUTH !== "0" &&
|
||||
process.env.NEXT_PUBLIC_DEBUG_AUTH !== "false";
|
||||
|
||||
function dlog(...args) {
|
||||
if (DEBUG && typeof window !== "undefined") {
|
||||
console.debug("[login]", ...args);
|
||||
}
|
||||
}
|
||||
|
||||
function LoginForm() {
|
||||
const router = useRouter();
|
||||
@@ -53,6 +64,12 @@ function LoginForm() {
|
||||
try {
|
||||
setSubmitting(true);
|
||||
|
||||
// ── DEBUG: ค่าเบื้องต้น
|
||||
dlog("API_BASE =", API_BASE || "(empty → จะเรียก path relative)");
|
||||
dlog("nextPath =", nextPath);
|
||||
dlog("remember =", remember);
|
||||
dlog("payload =", { username: "[hidden]", password: "[hidden]" });
|
||||
|
||||
const res = await fetch(`${API_BASE}/api/auth/login`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
@@ -60,14 +77,30 @@ function LoginForm() {
|
||||
cache: "no-store",
|
||||
});
|
||||
|
||||
const data = await res.json().catch(() => ({}));
|
||||
dlog("response.status =", res.status);
|
||||
dlog("response.headers.content-type =", res.headers.get("content-type"));
|
||||
|
||||
let data = {};
|
||||
try {
|
||||
data = await res.json();
|
||||
} catch (e) {
|
||||
dlog("response.json() error =", e);
|
||||
}
|
||||
dlog("response.body =", data);
|
||||
|
||||
if (!res.ok) {
|
||||
// รองรับข้อความ error จาก backend เช่น INVALID_CREDENTIALS
|
||||
setErr(
|
||||
const msg =
|
||||
data?.error === "INVALID_CREDENTIALS"
|
||||
? "ชื่อผู้ใช้หรือรหัสผ่านไม่ถูกต้อง"
|
||||
: data?.error || "เข้าสู่ระบบไม่สำเร็จ"
|
||||
);
|
||||
: data?.error || `เข้าสู่ระบบไม่สำเร็จ (HTTP ${res.status})`;
|
||||
dlog("login FAILED →", msg);
|
||||
setErr(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!data?.token) {
|
||||
dlog("login FAILED → data.token not found");
|
||||
setErr("รูปแบบข้อมูลตอบกลับไม่ถูกต้อง (ไม่มี token)");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -76,6 +109,7 @@ function LoginForm() {
|
||||
storage.setItem("dms.token", data.token);
|
||||
storage.setItem("dms.refresh_token", data.refresh_token);
|
||||
storage.setItem("dms.user", JSON.stringify(data.user || {}));
|
||||
dlog("token stored in", remember ? "localStorage" : "sessionStorage");
|
||||
|
||||
// (ออปชัน) เผยแพร่ event ให้แท็บอื่นทราบ
|
||||
try {
|
||||
@@ -84,11 +118,14 @@ function LoginForm() {
|
||||
);
|
||||
} catch {}
|
||||
|
||||
dlog("navigating →", nextPath);
|
||||
router.replace(nextPath);
|
||||
} catch (e) {
|
||||
dlog("exception =", e);
|
||||
setErr("เชื่อมต่อเซิร์ฟเวอร์ไม่ได้ กรุณาลองใหม่");
|
||||
} finally {
|
||||
setSubmitting(false);
|
||||
dlog("done");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,6 +220,12 @@ function LoginForm() {
|
||||
"เข้าสู่ระบบ"
|
||||
)}
|
||||
</Button>
|
||||
|
||||
{DEBUG ? (
|
||||
<p className="mt-2 text-xs text-slate-500">
|
||||
DEBUG: NEXT_PUBLIC_API_BASE = <code>{API_BASE || "(empty)"}</code>
|
||||
</p>
|
||||
) : null}
|
||||
</form>
|
||||
</CardContent>
|
||||
|
||||
@@ -251,4 +294,4 @@ function Spinner() {
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
123
frontend/package-lock.json
generated
123
frontend/package-lock.json
generated
@@ -19,6 +19,7 @@
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"framer-motion": "^11.2.10",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"lucide-react": "^0.451.0",
|
||||
"next": "15.0.3",
|
||||
"postcss": "8.4.47",
|
||||
@@ -2742,6 +2743,12 @@
|
||||
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer-equal-constant-time": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
|
||||
"integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/busboy": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
|
||||
@@ -3191,6 +3198,15 @@
|
||||
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ecdsa-sig-formatter": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
|
||||
"integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.5.227",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.227.tgz",
|
||||
@@ -4951,6 +4967,28 @@
|
||||
"json5": "lib/cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/jsonwebtoken": {
|
||||
"version": "9.0.2",
|
||||
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
|
||||
"integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"jws": "^3.2.2",
|
||||
"lodash.includes": "^4.3.0",
|
||||
"lodash.isboolean": "^3.0.3",
|
||||
"lodash.isinteger": "^4.0.4",
|
||||
"lodash.isnumber": "^3.0.3",
|
||||
"lodash.isplainobject": "^4.0.6",
|
||||
"lodash.isstring": "^4.0.1",
|
||||
"lodash.once": "^4.0.0",
|
||||
"ms": "^2.1.1",
|
||||
"semver": "^7.5.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12",
|
||||
"npm": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/jsx-ast-utils": {
|
||||
"version": "3.3.5",
|
||||
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
|
||||
@@ -4967,6 +5005,27 @@
|
||||
"node": ">=4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/jwa": {
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz",
|
||||
"integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"buffer-equal-constant-time": "^1.0.1",
|
||||
"ecdsa-sig-formatter": "1.0.11",
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/jws": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
|
||||
"integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"jwa": "^1.4.1",
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/keyv": {
|
||||
"version": "4.5.4",
|
||||
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
|
||||
@@ -5042,6 +5101,42 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/lodash.includes": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
|
||||
"integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.isboolean": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
|
||||
"integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.isinteger": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
|
||||
"integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.isnumber": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
|
||||
"integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.isplainobject": {
|
||||
"version": "4.0.6",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
|
||||
"integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.isstring": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
|
||||
"integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.merge": {
|
||||
"version": "4.6.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
||||
@@ -5049,6 +5144,12 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.once": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
|
||||
"integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/loose-envify": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||
@@ -5159,7 +5260,6 @@
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/mz": {
|
||||
@@ -6066,6 +6166,26 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/safe-push-apply": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz",
|
||||
@@ -6114,7 +6234,6 @@
|
||||
"version": "7.7.2",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
|
||||
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
|
||||
"devOptional": true,
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"framer-motion": "^11.2.10",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"lucide-react": "^0.451.0",
|
||||
"next": "15.0.3",
|
||||
"postcss": "8.4.47",
|
||||
|
||||
6
mariadb/data/.my-healthcheck.cnf
Normal file
6
mariadb/data/.my-healthcheck.cnf
Normal file
@@ -0,0 +1,6 @@
|
||||
[mariadb-client]
|
||||
port=3306
|
||||
socket=/run/mysqld/mysqld.sock
|
||||
user=healthcheck
|
||||
password=jhc12PlUnlAebL|p7OxiYwMyuC<<E0D+
|
||||
|
||||
BIN
mariadb/data/aria_log.00000001
Normal file
BIN
mariadb/data/aria_log.00000001
Normal file
Binary file not shown.
BIN
mariadb/data/aria_log_control
Normal file
BIN
mariadb/data/aria_log_control
Normal file
Binary file not shown.
BIN
mariadb/data/dms/approve_codes.frm
Normal file
BIN
mariadb/data/dms/approve_codes.frm
Normal file
Binary file not shown.
BIN
mariadb/data/dms/approve_codes.ibd
Normal file
BIN
mariadb/data/dms/approve_codes.ibd
Normal file
Binary file not shown.
BIN
mariadb/data/dms/audit_logs.frm
Normal file
BIN
mariadb/data/dms/audit_logs.frm
Normal file
Binary file not shown.
BIN
mariadb/data/dms/audit_logs.ibd
Normal file
BIN
mariadb/data/dms/audit_logs.ibd
Normal file
Binary file not shown.
BIN
mariadb/data/dms/cir_status_codes.frm
Normal file
BIN
mariadb/data/dms/cir_status_codes.frm
Normal file
Binary file not shown.
BIN
mariadb/data/dms/cir_status_codes.ibd
Normal file
BIN
mariadb/data/dms/cir_status_codes.ibd
Normal file
Binary file not shown.
8
mariadb/data/dms/cir_users.TRG
Normal file
8
mariadb/data/dms/cir_users.TRG
Normal file
@@ -0,0 +1,8 @@
|
||||
TYPE=TRIGGERS
|
||||
triggers='CREATE DEFINER=`root`@`localhost` TRIGGER trg_cir_users_bi_flags\nBEFORE INSERT ON cir_users\nFOR EACH ROW\nBEGIN\n SET NEW.is_main = IFNULL(NEW.is_main, 0);\n SET NEW.is_action = IFNULL(NEW.is_action, 0);\nEND' 'CREATE DEFINER=`root`@`localhost` TRIGGER trg_cir_users_bu_flags\nBEFORE UPDATE ON cir_users\nFOR EACH ROW\nBEGIN\n SET NEW.is_main = IFNULL(NEW.is_main, 0);\n SET NEW.is_action = IFNULL(NEW.is_action, 0);\nEND'
|
||||
sql_modes=1411383296 1411383296
|
||||
definers='root@localhost' 'root@localhost'
|
||||
client_cs_names='utf8mb4' 'utf8mb4'
|
||||
connection_cl_names='utf8mb4_general_ci' 'utf8mb4_general_ci'
|
||||
db_cl_names='utf8mb4_general_ci' 'utf8mb4_general_ci'
|
||||
created=1759220379993565 1759220380105898
|
||||
BIN
mariadb/data/dms/cir_users.frm
Normal file
BIN
mariadb/data/dms/cir_users.frm
Normal file
Binary file not shown.
BIN
mariadb/data/dms/cir_users.ibd
Normal file
BIN
mariadb/data/dms/cir_users.ibd
Normal file
Binary file not shown.
BIN
mariadb/data/dms/circulations.frm
Normal file
BIN
mariadb/data/dms/circulations.frm
Normal file
Binary file not shown.
BIN
mariadb/data/dms/circulations.ibd
Normal file
BIN
mariadb/data/dms/circulations.ibd
Normal file
Binary file not shown.
8
mariadb/data/dms/contract_dwg.TRG
Normal file
8
mariadb/data/dms/contract_dwg.TRG
Normal file
@@ -0,0 +1,8 @@
|
||||
TYPE=TRIGGERS
|
||||
triggers='CREATE DEFINER=`root`@`localhost` TRIGGER trg_cdwg_bi_normalize\nBEFORE INSERT ON contract_dwg\nFOR EACH ROW\nBEGIN\n SET NEW.condwg_no = TRIM(NEW.condwg_no);\n SET NEW.title = NULLIF(TRIM(NEW.title), \'\');\n\n IF NEW.project_id IS NULL OR NEW.sub_cat_id IS NULL THEN\n SIGNAL SQLSTATE \'45000\' SET MESSAGE_TEXT=\'project_id and sub_cat_id are required for contract_dwg\';\n END IF;\n IF NEW.condwg_no IS NULL OR NEW.condwg_no=\'\' THEN\n SIGNAL SQLSTATE \'45000\' SET MESSAGE_TEXT=\'condwg_no is required\';\n END IF;\nEND' 'CREATE DEFINER=`root`@`localhost` TRIGGER trg_dwg_before_insert\nBEFORE INSERT ON contract_dwg\nFOR EACH ROW\nBEGIN\n DECLARE v_cnt INT DEFAULT 0;\n\n \n SET NEW.condwg_no = TRIM(NEW.condwg_no);\n IF NEW.title IS NOT NULL THEN\n SET NEW.title = TRIM(NEW.title);\n END IF;\n IF NEW.remark IS NOT NULL THEN\n SET NEW.remark = TRIM(NEW.remark);\n END IF;\n\n \n SELECT COUNT(*) INTO v_cnt\n FROM contract_dwg_sub_cat sc\n WHERE sc.sub_cat_id = NEW.sub_cat_id\n AND sc.project_id = NEW.project_id;\n IF v_cnt = 0 THEN\n SIGNAL SQLSTATE \'45000\'\n SET MESSAGE_TEXT = \'Invalid sub_cat_id: must belong to same project\';\n END IF;\n\n \n SELECT COUNT(*) INTO v_cnt\n FROM contract_dwg_volume v\n WHERE v.volume_id = NEW.volume_id\n AND v.project_id = NEW.project_id;\n IF v_cnt = 0 THEN\n SIGNAL SQLSTATE \'45000\'\n SET MESSAGE_TEXT = \'Invalid volume_id: must belong to same project\';\n END IF;\n\n SET NEW.created_at = CURRENT_TIMESTAMP;\nEND' 'CREATE DEFINER=`root`@`localhost` TRIGGER trg_cdwg_bu_normalize\nBEFORE UPDATE ON contract_dwg\nFOR EACH ROW\nBEGIN\n SET NEW.condwg_no = TRIM(NEW.condwg_no);\n SET NEW.title = NULLIF(TRIM(NEW.title), \'\');\nEND' 'CREATE DEFINER=`root`@`localhost` TRIGGER trg_dwg_before_update\nBEFORE UPDATE ON contract_dwg\nFOR EACH ROW\nBEGIN\n DECLARE v_cnt INT DEFAULT 0;\n\n \n IF NEW.condwg_no IS NOT NULL THEN\n SET NEW.condwg_no = TRIM(NEW.condwg_no);\n END IF;\n IF NEW.title IS NOT NULL THEN\n SET NEW.title = TRIM(NEW.title);\n END IF;\n IF NEW.remark IS NOT NULL THEN\n SET NEW.remark = TRIM(NEW.remark);\n END IF;\n\n \n IF NEW.project_id <> OLD.project_id THEN\n SIGNAL SQLSTATE \'45000\'\n SET MESSAGE_TEXT = \'Changing drawing project_id is not allowed\';\n END IF;\n\n \n SELECT COUNT(*) INTO v_cnt\n FROM contract_dwg_sub_cat sc\n WHERE sc.sub_cat_id = NEW.sub_cat_id\n AND sc.project_id = NEW.project_id;\n IF v_cnt = 0 THEN\n SIGNAL SQLSTATE \'45000\'\n SET MESSAGE_TEXT = \'Invalid sub_cat_id after update: must be same project\';\n END IF;\n\n \n SELECT COUNT(*) INTO v_cnt\n FROM contract_dwg_volume v\n WHERE v.volume_id = NEW.volume_id\n AND v.project_id = NEW.project_id;\n IF v_cnt = 0 THEN\n SIGNAL SQLSTATE \'45000\'\n SET MESSAGE_TEXT = \'Invalid volume_id after update: must be same project\';\n END IF;\n\n SET NEW.updated_at = CURRENT_TIMESTAMP;\nEND' 'CREATE DEFINER=`root`@`localhost` TRIGGER trg_dwg_before_delete\nBEFORE DELETE ON contract_dwg\nFOR EACH ROW\nBEGIN\n \n \nEND'
|
||||
sql_modes=1411383296 1411383296 1411383296 1411383296 1411383296
|
||||
definers='root@localhost' 'root@localhost' 'root@localhost' 'root@localhost' 'root@localhost'
|
||||
client_cs_names='utf8mb4' 'utf8mb4' 'utf8mb4' 'utf8mb4' 'utf8mb4'
|
||||
connection_cl_names='utf8mb4_general_ci' 'utf8mb4_general_ci' 'utf8mb4_general_ci' 'utf8mb4_general_ci' 'utf8mb4_general_ci'
|
||||
db_cl_names='utf8mb4_general_ci' 'utf8mb4_general_ci' 'utf8mb4_general_ci' 'utf8mb4_general_ci' 'utf8mb4_general_ci'
|
||||
created=1759220379595746 1759220382757985 1759220379725392 1759220383012145 1759220383498581
|
||||
BIN
mariadb/data/dms/contract_dwg.frm
Normal file
BIN
mariadb/data/dms/contract_dwg.frm
Normal file
Binary file not shown.
BIN
mariadb/data/dms/contract_dwg.ibd
Normal file
BIN
mariadb/data/dms/contract_dwg.ibd
Normal file
Binary file not shown.
8
mariadb/data/dms/contract_dwg_cat.TRG
Normal file
8
mariadb/data/dms/contract_dwg_cat.TRG
Normal file
@@ -0,0 +1,8 @@
|
||||
TYPE=TRIGGERS
|
||||
triggers='CREATE DEFINER=`root`@`localhost` TRIGGER trg_cdwg_cat_bi_norm\nBEFORE INSERT ON contract_dwg_cat\nFOR EACH ROW\nBEGIN\n SET NEW.cat_name = TRIM(NEW.cat_name);\n IF NEW.cat_name IS NULL OR NEW.cat_name=\'\' THEN\n SIGNAL SQLSTATE \'45000\' SET MESSAGE_TEXT=\'cat_name is required\';\n END IF;\nEND' 'CREATE DEFINER=`root`@`localhost` TRIGGER trg_cat_before_insert\nBEFORE INSERT ON contract_dwg_cat\nFOR EACH ROW\nBEGIN\n \n SET NEW.cat_name = TRIM(NEW.cat_name);\n IF NEW.cat_code IS NOT NULL THEN\n SET NEW.cat_code = TRIM(NEW.cat_code);\n END IF;\n\n \n SET NEW.created_at = CURRENT_TIMESTAMP;\nEND' 'CREATE DEFINER=`root`@`localhost` TRIGGER trg_cat_before_update\nBEFORE UPDATE ON contract_dwg_cat\nFOR EACH ROW\nBEGIN\n DECLARE v_map_cnt INT DEFAULT 0;\n \n IF NEW.cat_name IS NOT NULL THEN\n SET NEW.cat_name = TRIM(NEW.cat_name);\n END IF;\n IF NEW.cat_code IS NOT NULL THEN\n SET NEW.cat_code = TRIM(NEW.cat_code);\n END IF;\n\n \n IF NEW.project_id <> OLD.project_id THEN\n SELECT COUNT(*) INTO v_map_cnt\n FROM contract_dwg_subcat_cat_map m\n WHERE m.project_id = OLD.project_id\n AND m.cat_id = OLD.cat_id;\n IF v_map_cnt > 0 THEN\n SIGNAL SQLSTATE \'45000\'\n SET MESSAGE_TEXT = \'Cannot change category project_id: mappings exist in subcat↔cat map\';\n END IF;\n END IF;\n\n \n SET NEW.updated_at = CURRENT_TIMESTAMP;\nEND' 'CREATE DEFINER=`root`@`localhost` TRIGGER trg_cat_before_delete\nBEFORE DELETE ON contract_dwg_cat\nFOR EACH ROW\nBEGIN\n \n DECLARE v_map_cnt INT DEFAULT 0;\n SELECT COUNT(*) INTO v_map_cnt\n FROM contract_dwg_subcat_cat_map m\n WHERE m.project_id = OLD.project_id\n AND m.cat_id = OLD.cat_id;\n\n IF v_map_cnt > 0 THEN\n SIGNAL SQLSTATE \'45000\'\n SET MESSAGE_TEXT = \'Cannot delete category: mapped by sub-categories in this project\';\n END IF;\nEND'
|
||||
sql_modes=1411383296 1411383296 1411383296 1411383296
|
||||
definers='root@localhost' 'root@localhost' 'root@localhost' 'root@localhost'
|
||||
client_cs_names='utf8mb4' 'utf8mb4' 'utf8mb4' 'utf8mb4'
|
||||
connection_cl_names='utf8mb4_general_ci' 'utf8mb4_general_ci' 'utf8mb4_general_ci' 'utf8mb4_general_ci'
|
||||
db_cl_names='utf8mb4_general_ci' 'utf8mb4_general_ci' 'utf8mb4_general_ci' 'utf8mb4_general_ci'
|
||||
created=1759220379895653 1759220380272498 1759220380492708 1759220380712245
|
||||
BIN
mariadb/data/dms/contract_dwg_cat.frm
Normal file
BIN
mariadb/data/dms/contract_dwg_cat.frm
Normal file
Binary file not shown.
BIN
mariadb/data/dms/contract_dwg_cat.ibd
Normal file
BIN
mariadb/data/dms/contract_dwg_cat.ibd
Normal file
Binary file not shown.
8
mariadb/data/dms/contract_dwg_sub_cat.TRG
Normal file
8
mariadb/data/dms/contract_dwg_sub_cat.TRG
Normal file
@@ -0,0 +1,8 @@
|
||||
TYPE=TRIGGERS
|
||||
triggers='CREATE DEFINER=`root`@`localhost` TRIGGER trg_subcat_before_insert\nBEFORE INSERT ON contract_dwg_sub_cat\nFOR EACH ROW\nBEGIN\n SET NEW.sub_cat_name = TRIM(NEW.sub_cat_name);\n IF NEW.sub_cat_code IS NOT NULL THEN\n SET NEW.sub_cat_code = TRIM(NEW.sub_cat_code);\n END IF;\n\n SET NEW.created_at = CURRENT_TIMESTAMP;\nEND' 'CREATE DEFINER=`root`@`localhost` TRIGGER trg_subcat_before_update\nBEFORE UPDATE ON contract_dwg_sub_cat\nFOR EACH ROW\nBEGIN\n DECLARE v_map_cnt INT DEFAULT 0;\n DECLARE v_dwg_cnt INT DEFAULT 0;\n IF NEW.sub_cat_name IS NOT NULL THEN\n SET NEW.sub_cat_name = TRIM(NEW.sub_cat_name);\n END IF;\n IF NEW.sub_cat_code IS NOT NULL THEN\n SET NEW.sub_cat_code = TRIM(NEW.sub_cat_code);\n END IF;\n\n \n IF NEW.project_id <> OLD.project_id THEN\n SELECT COUNT(*) INTO v_map_cnt\n FROM contract_dwg_subcat_cat_map m\n WHERE m.project_id = OLD.project_id\n AND m.sub_cat_id = OLD.sub_cat_id;\n\n SELECT COUNT(*) INTO v_dwg_cnt\n FROM contract_dwg d\n WHERE d.project_id = OLD.project_id\n AND d.sub_cat_id = OLD.sub_cat_id;\n\n IF v_map_cnt > 0 OR v_dwg_cnt > 0 THEN\n SIGNAL SQLSTATE \'45000\'\n SET MESSAGE_TEXT = \'Cannot change sub-category project_id: drawings or mappings exist\';\n END IF;\n END IF;\n\n SET NEW.updated_at = CURRENT_TIMESTAMP;\nEND' 'CREATE DEFINER=`root`@`localhost` TRIGGER trg_subcat_before_delete\nBEFORE DELETE ON contract_dwg_sub_cat\nFOR EACH ROW\nBEGIN\n DECLARE v_dwg_cnt INT DEFAULT 0;\n DECLARE v_map_cnt INT DEFAULT 0;\n\n SELECT COUNT(*) INTO v_dwg_cnt\n FROM contract_dwg d\n WHERE d.project_id = OLD.project_id\n AND d.sub_cat_id = OLD.sub_cat_id;\n\n SELECT COUNT(*) INTO v_map_cnt\n FROM contract_dwg_subcat_cat_map m\n WHERE m.project_id = OLD.project_id\n AND m.sub_cat_id = OLD.sub_cat_id;\n\n IF v_dwg_cnt > 0 THEN\n SIGNAL SQLSTATE \'45000\'\n SET MESSAGE_TEXT = \'Cannot delete sub-category: drawings exist in this sub-category\';\n END IF;\n\n IF v_map_cnt > 0 THEN\n SIGNAL SQLSTATE \'45000\'\n SET MESSAGE_TEXT = \'Cannot delete sub-category: it is mapped to categories\';\n END IF;\nEND'
|
||||
sql_modes=1411383296 1411383296 1411383296
|
||||
definers='root@localhost' 'root@localhost' 'root@localhost'
|
||||
client_cs_names='utf8mb4' 'utf8mb4' 'utf8mb4'
|
||||
connection_cl_names='utf8mb4_general_ci' 'utf8mb4_general_ci' 'utf8mb4_general_ci'
|
||||
db_cl_names='utf8mb4_general_ci' 'utf8mb4_general_ci' 'utf8mb4_general_ci'
|
||||
created=1759220381156227 1759220381265061 1759220381497493
|
||||
BIN
mariadb/data/dms/contract_dwg_sub_cat.frm
Normal file
BIN
mariadb/data/dms/contract_dwg_sub_cat.frm
Normal file
Binary file not shown.
BIN
mariadb/data/dms/contract_dwg_sub_cat.ibd
Normal file
BIN
mariadb/data/dms/contract_dwg_sub_cat.ibd
Normal file
Binary file not shown.
8
mariadb/data/dms/contract_dwg_subcat_cat_map.TRG
Normal file
8
mariadb/data/dms/contract_dwg_subcat_cat_map.TRG
Normal file
@@ -0,0 +1,8 @@
|
||||
TYPE=TRIGGERS
|
||||
triggers='CREATE DEFINER=`root`@`localhost` TRIGGER trg_map_before_insert\nBEFORE INSERT ON contract_dwg_subcat_cat_map\nFOR EACH ROW\nBEGIN\n DECLARE v_cnt INT DEFAULT 0;\n\n \n SELECT COUNT(*) INTO v_cnt\n FROM contract_dwg_sub_cat sc\n WHERE sc.sub_cat_id = NEW.sub_cat_id\n AND sc.project_id = NEW.project_id;\n IF v_cnt = 0 THEN\n SIGNAL SQLSTATE \'45000\'\n SET MESSAGE_TEXT = \'Invalid sub_cat_id: must belong to the same project (map)\';\n END IF;\n\n \n SELECT COUNT(*) INTO v_cnt\n FROM contract_dwg_cat c\n WHERE c.cat_id = NEW.cat_id\n AND c.project_id = NEW.project_id;\n IF v_cnt = 0 THEN\n SIGNAL SQLSTATE \'45000\'\n SET MESSAGE_TEXT = \'Invalid cat_id: must belong to the same project (map)\';\n END IF;\nEND' 'CREATE DEFINER=`root`@`localhost` TRIGGER trg_map_before_update\nBEFORE UPDATE ON contract_dwg_subcat_cat_map\nFOR EACH ROW\nBEGIN\n DECLARE v_cnt INT DEFAULT 0;\n\n \n IF NEW.project_id <> OLD.project_id THEN\n SIGNAL SQLSTATE \'45000\'\n SET MESSAGE_TEXT = \'Changing project_id on mapping is not allowed\';\n END IF;\n\n \n SELECT COUNT(*) INTO v_cnt\n FROM contract_dwg_sub_cat sc\n WHERE sc.sub_cat_id = NEW.sub_cat_id\n AND sc.project_id = NEW.project_id;\n IF v_cnt = 0 THEN\n SIGNAL SQLSTATE \'45000\'\n SET MESSAGE_TEXT = \'Invalid sub_cat_id after update: must be same project\';\n END IF;\n\n SELECT COUNT(*) INTO v_cnt\n FROM contract_dwg_cat c\n WHERE c.cat_id = NEW.cat_id\n AND c.project_id = NEW.project_id;\n IF v_cnt = 0 THEN\n SIGNAL SQLSTATE \'45000\'\n SET MESSAGE_TEXT = \'Invalid cat_id after update: must be same project\';\n END IF;\nEND' 'CREATE DEFINER=`root`@`localhost` TRIGGER trg_map_before_delete\nBEFORE DELETE ON contract_dwg_subcat_cat_map\nFOR EACH ROW\nBEGIN\n \n \nEND'
|
||||
sql_modes=1411383296 1411383296 1411383296
|
||||
definers='root@localhost' 'root@localhost' 'root@localhost'
|
||||
client_cs_names='utf8mb4' 'utf8mb4' 'utf8mb4'
|
||||
connection_cl_names='utf8mb4_general_ci' 'utf8mb4_general_ci' 'utf8mb4_general_ci'
|
||||
db_cl_names='utf8mb4_general_ci' 'utf8mb4_general_ci' 'utf8mb4_general_ci'
|
||||
created=1759220381718496 1759220381824403 1759220382028445
|
||||
BIN
mariadb/data/dms/contract_dwg_subcat_cat_map.frm
Normal file
BIN
mariadb/data/dms/contract_dwg_subcat_cat_map.frm
Normal file
Binary file not shown.
BIN
mariadb/data/dms/contract_dwg_subcat_cat_map.ibd
Normal file
BIN
mariadb/data/dms/contract_dwg_subcat_cat_map.ibd
Normal file
Binary file not shown.
8
mariadb/data/dms/contract_dwg_volume.TRG
Normal file
8
mariadb/data/dms/contract_dwg_volume.TRG
Normal file
@@ -0,0 +1,8 @@
|
||||
TYPE=TRIGGERS
|
||||
triggers='CREATE DEFINER=`root`@`localhost` TRIGGER trg_volume_before_insert\nBEFORE INSERT ON contract_dwg_volume\nFOR EACH ROW\nBEGIN\n SET NEW.volume_code = TRIM(NEW.volume_code);\n IF NEW.volume_name IS NOT NULL THEN\n SET NEW.volume_name = TRIM(NEW.volume_name);\n END IF;\n\n SET NEW.created_at = CURRENT_TIMESTAMP;\nEND' 'CREATE DEFINER=`root`@`localhost` TRIGGER trg_volume_before_update\nBEFORE UPDATE ON contract_dwg_volume\nFOR EACH ROW\nBEGIN\n DECLARE v_dwg_cnt INT DEFAULT 0;\n IF NEW.volume_code IS NOT NULL THEN\n SET NEW.volume_code = TRIM(NEW.volume_code);\n END IF;\n IF NEW.volume_name IS NOT NULL THEN\n SET NEW.volume_name = TRIM(NEW.volume_name);\n END IF;\n\n \n IF NEW.project_id <> OLD.project_id THEN \n SELECT COUNT(*) INTO v_dwg_cnt\n FROM contract_dwg d\n WHERE d.project_id = OLD.project_id\n AND d.volume_id = OLD.volume_id;\n\n IF v_dwg_cnt > 0 THEN\n SIGNAL SQLSTATE \'45000\'\n SET MESSAGE_TEXT = \'Cannot change volume project_id: drawings exist in this volume\';\n END IF;\n END IF;\n\n SET NEW.updated_at = CURRENT_TIMESTAMP;\nEND' 'CREATE DEFINER=`root`@`localhost` TRIGGER trg_volume_before_delete\nBEFORE DELETE ON contract_dwg_volume\nFOR EACH ROW\nBEGIN\n DECLARE v_dwg_cnt INT DEFAULT 0;\n SELECT COUNT(*) INTO v_dwg_cnt\n FROM contract_dwg d\n WHERE d.project_id = OLD.project_id\n AND d.volume_id = OLD.volume_id;\n\n IF v_dwg_cnt > 0 THEN\n SIGNAL SQLSTATE \'45000\'\n SET MESSAGE_TEXT = \'Cannot delete volume: drawings exist in this volume\';\n END IF;\nEND'
|
||||
sql_modes=1411383296 1411383296 1411383296
|
||||
definers='root@localhost' 'root@localhost' 'root@localhost'
|
||||
client_cs_names='utf8mb4' 'utf8mb4' 'utf8mb4'
|
||||
connection_cl_names='utf8mb4_general_ci' 'utf8mb4_general_ci' 'utf8mb4_general_ci'
|
||||
db_cl_names='utf8mb4_general_ci' 'utf8mb4_general_ci' 'utf8mb4_general_ci'
|
||||
created=1759220382195544 1759220382282307 1759220382459142
|
||||
BIN
mariadb/data/dms/contract_dwg_volume.frm
Normal file
BIN
mariadb/data/dms/contract_dwg_volume.frm
Normal file
Binary file not shown.
BIN
mariadb/data/dms/contract_dwg_volume.ibd
Normal file
BIN
mariadb/data/dms/contract_dwg_volume.ibd
Normal file
Binary file not shown.
8
mariadb/data/dms/correspondence_cc_recipients.TRG
Normal file
8
mariadb/data/dms/correspondence_cc_recipients.TRG
Normal file
@@ -0,0 +1,8 @@
|
||||
TYPE=TRIGGERS
|
||||
triggers='CREATE DEFINER=`root`@`localhost` TRIGGER trg_corcc_bi_guard_party\nBEFORE INSERT ON correspondence_cc_recipients\nFOR EACH ROW\nBEGIN\n DECLARE v_project_id INT;\n SELECT project_id INTO v_project_id FROM correspondences WHERE corr_id = NEW.corr_id;\n IF v_project_id IS NULL THEN\n SIGNAL SQLSTATE \'45000\' SET MESSAGE_TEXT=\'Correspondence not found\';\n END IF;\n\n IF NOT EXISTS (\n SELECT 1 FROM project_parties\n WHERE project_id = v_project_id AND org_id = NEW.org_id AND deleted_at IS NULL\n ) THEN\n SIGNAL SQLSTATE \'45000\' SET MESSAGE_TEXT=\'CC org is not in project parties\';\n END IF;\nEND' 'CREATE DEFINER=`root`@`localhost` TRIGGER trg_corcc_bu_guard_party\nBEFORE UPDATE ON correspondence_cc_recipients\nFOR EACH ROW\nBEGIN\n DECLARE v_project_id INT;\n SELECT project_id INTO v_project_id FROM correspondences WHERE corr_id = NEW.corr_id;\n IF v_project_id IS NULL THEN\n SIGNAL SQLSTATE \'45000\' SET MESSAGE_TEXT=\'Correspondence not found\';\n END IF;\n\n IF NOT EXISTS (\n SELECT 1 FROM project_parties\n WHERE project_id = v_project_id AND org_id = NEW.org_id AND deleted_at IS NULL\n ) THEN\n SIGNAL SQLSTATE \'45000\' SET MESSAGE_TEXT=\'CC org is not in project parties\';\n END IF;\nEND'
|
||||
sql_modes=1411383296 1411383296
|
||||
definers='root@localhost' 'root@localhost'
|
||||
client_cs_names='utf8mb4' 'utf8mb4'
|
||||
connection_cl_names='utf8mb4_general_ci' 'utf8mb4_general_ci'
|
||||
db_cl_names='utf8mb4_general_ci' 'utf8mb4_general_ci'
|
||||
created=1759220376112820 1759220376245144
|
||||
BIN
mariadb/data/dms/correspondence_cc_recipients.frm
Normal file
BIN
mariadb/data/dms/correspondence_cc_recipients.frm
Normal file
Binary file not shown.
BIN
mariadb/data/dms/correspondence_cc_recipients.ibd
Normal file
BIN
mariadb/data/dms/correspondence_cc_recipients.ibd
Normal file
Binary file not shown.
8
mariadb/data/dms/correspondence_references.TRG
Normal file
8
mariadb/data/dms/correspondence_references.TRG
Normal file
@@ -0,0 +1,8 @@
|
||||
TYPE=TRIGGERS
|
||||
triggers='CREATE DEFINER=`root`@`localhost` TRIGGER trg_correfl_bi_guard_self\nBEFORE INSERT ON correspondence_references\nFOR EACH ROW\nBEGIN\n IF NEW.src_corr_id = NEW.tgt_corr_id THEN\n SIGNAL SQLSTATE \'45000\' SET MESSAGE_TEXT=\'Cannot reference a correspondence to itself\';\n END IF;\nEND' 'CREATE DEFINER=`root`@`localhost` TRIGGER trg_correfl_bu_guard_self\nBEFORE UPDATE ON correspondence_references\nFOR EACH ROW\nBEGIN\n IF NEW.src_corr_id = NEW.tgt_corr_id THEN\n SIGNAL SQLSTATE \'45000\' SET MESSAGE_TEXT=\'Cannot reference a correspondence to itself\';\n END IF;\nEND'
|
||||
sql_modes=1411383296 1411383296
|
||||
definers='root@localhost' 'root@localhost'
|
||||
client_cs_names='utf8mb4' 'utf8mb4'
|
||||
connection_cl_names='utf8mb4_general_ci' 'utf8mb4_general_ci'
|
||||
db_cl_names='utf8mb4_general_ci' 'utf8mb4_general_ci'
|
||||
created=1759220376654188 1759220376770663
|
||||
BIN
mariadb/data/dms/correspondence_references.frm
Normal file
BIN
mariadb/data/dms/correspondence_references.frm
Normal file
Binary file not shown.
BIN
mariadb/data/dms/correspondence_references.ibd
Normal file
BIN
mariadb/data/dms/correspondence_references.ibd
Normal file
Binary file not shown.
BIN
mariadb/data/dms/correspondence_status.frm
Normal file
BIN
mariadb/data/dms/correspondence_status.frm
Normal file
Binary file not shown.
BIN
mariadb/data/dms/correspondence_status.ibd
Normal file
BIN
mariadb/data/dms/correspondence_status.ibd
Normal file
Binary file not shown.
BIN
mariadb/data/dms/correspondence_status_transitions.frm
Normal file
BIN
mariadb/data/dms/correspondence_status_transitions.frm
Normal file
Binary file not shown.
BIN
mariadb/data/dms/correspondence_status_transitions.ibd
Normal file
BIN
mariadb/data/dms/correspondence_status_transitions.ibd
Normal file
Binary file not shown.
BIN
mariadb/data/dms/correspondence_types.frm
Normal file
BIN
mariadb/data/dms/correspondence_types.frm
Normal file
Binary file not shown.
BIN
mariadb/data/dms/correspondence_types.ibd
Normal file
BIN
mariadb/data/dms/correspondence_types.ibd
Normal file
Binary file not shown.
8
mariadb/data/dms/correspondences.TRG
Normal file
8
mariadb/data/dms/correspondences.TRG
Normal file
@@ -0,0 +1,8 @@
|
||||
TYPE=TRIGGERS
|
||||
triggers='CREATE DEFINER=`root`@`localhost` TRIGGER trg_cor_bi_normalize\nBEFORE INSERT ON correspondences\nFOR EACH ROW\nBEGIN\n SET NEW.correspondence_number = TRIM(NEW.correspondence_number);\n SET NEW.title = TRIM(NEW.title);\n SET NEW.keywords = NULLIF(TRIM(NEW.keywords), \'\');\n SET NEW.revision = NULLIF(TRIM(NEW.revision), \'\');\n SET NEW.is_internal_communication = IFNULL(NEW.is_internal_communication, 0);\n\n IF NEW.project_id IS NULL OR NEW.correspondence_type_id IS NULL OR NEW.correspondence_status_id IS NULL THEN\n SIGNAL SQLSTATE \'45000\' SET MESSAGE_TEXT=\'project_id/type_id/status_id is required\';\n END IF;\n IF NEW.correspondence_number IS NULL OR NEW.correspondence_number=\'\' THEN\n SIGNAL SQLSTATE \'45000\' SET MESSAGE_TEXT=\'correspondence_number is required\';\n END IF;\n\n \nEND' 'CREATE DEFINER=`root`@`localhost` TRIGGER trg_cor_ai_set_root\nAFTER INSERT ON correspondences\nFOR EACH ROW\nBEGIN\n IF NEW.root_id IS NULL THEN\n UPDATE correspondences SET root_id = NEW.corr_id WHERE corr_id = NEW.corr_id;\n END IF;\nEND' 'CREATE DEFINER=`root`@`localhost` TRIGGER trg_cor_bu_normalize\nBEFORE UPDATE ON correspondences\nFOR EACH ROW\nBEGIN\n SET NEW.correspondence_number = TRIM(NEW.correspondence_number);\n SET NEW.title = TRIM(NEW.title);\n SET NEW.keywords = NULLIF(TRIM(NEW.keywords), \'\');\n SET NEW.revision = NULLIF(TRIM(NEW.revision), \'\');\n SET NEW.is_internal_communication = IFNULL(NEW.is_internal_communication, 0);\n\n \n IF NEW.root_id <> OLD.root_id THEN\n SIGNAL SQLSTATE \'45000\' SET MESSAGE_TEXT=\'root_id is immutable\';\n END IF;\nEND' 'CREATE DEFINER=`root`@`localhost` TRIGGER trg_cor_bd_no_delete_root_with_children\nBEFORE DELETE ON correspondences\nFOR EACH ROW\nBEGIN\n IF EXISTS (SELECT 1 FROM correspondences WHERE root_id = OLD.corr_id AND corr_id <> OLD.corr_id) THEN\n SIGNAL SQLSTATE \'45000\' SET MESSAGE_TEXT=\'Cannot delete root correspondence with existing revisions\';\n END IF;\nEND'
|
||||
sql_modes=1411383296 1411383296 1411383296 1411383296
|
||||
definers='root@localhost' 'root@localhost' 'root@localhost' 'root@localhost'
|
||||
client_cs_names='utf8mb4' 'utf8mb4' 'utf8mb4' 'utf8mb4'
|
||||
connection_cl_names='utf8mb4_general_ci' 'utf8mb4_general_ci' 'utf8mb4_general_ci' 'utf8mb4_general_ci'
|
||||
db_cl_names='utf8mb4_general_ci' 'utf8mb4_general_ci' 'utf8mb4_general_ci' 'utf8mb4_general_ci'
|
||||
created=1759220375434299 1759220375781124 1759220375559604 1759220375957839
|
||||
BIN
mariadb/data/dms/correspondences.frm
Normal file
BIN
mariadb/data/dms/correspondences.frm
Normal file
Binary file not shown.
BIN
mariadb/data/dms/correspondences.ibd
Normal file
BIN
mariadb/data/dms/correspondences.ibd
Normal file
Binary file not shown.
2
mariadb/data/dms/db.opt
Normal file
2
mariadb/data/dms/db.opt
Normal file
@@ -0,0 +1,2 @@
|
||||
default-character-set=utf8mb4
|
||||
default-collation=utf8mb4_general_ci
|
||||
BIN
mariadb/data/dms/doc_no_sequences.frm
Normal file
BIN
mariadb/data/dms/doc_no_sequences.frm
Normal file
Binary file not shown.
BIN
mariadb/data/dms/doc_no_sequences.ibd
Normal file
BIN
mariadb/data/dms/doc_no_sequences.ibd
Normal file
Binary file not shown.
BIN
mariadb/data/dms/document_status_codes.frm
Normal file
BIN
mariadb/data/dms/document_status_codes.frm
Normal file
Binary file not shown.
BIN
mariadb/data/dms/document_status_codes.ibd
Normal file
BIN
mariadb/data/dms/document_status_codes.ibd
Normal file
Binary file not shown.
BIN
mariadb/data/dms/document_types.frm
Normal file
BIN
mariadb/data/dms/document_types.frm
Normal file
Binary file not shown.
BIN
mariadb/data/dms/document_types.ibd
Normal file
BIN
mariadb/data/dms/document_types.ibd
Normal file
Binary file not shown.
8
mariadb/data/dms/dwgdoc_contract_dwg.TRG
Normal file
8
mariadb/data/dms/dwgdoc_contract_dwg.TRG
Normal file
@@ -0,0 +1,8 @@
|
||||
TYPE=TRIGGERS
|
||||
triggers='CREATE DEFINER=`root`@`localhost` TRIGGER trg_scd_bi_guard\nBEFORE INSERT ON dwgdoc_contract_dwg\nFOR EACH ROW\nBEGIN\n DECLARE v_doc_proj INT;\n DECLARE v_doc_type_code VARCHAR(20);\n DECLARE v_dwg_proj INT;\n\n \n SELECT t.project_id, dt.code\n INTO v_doc_proj, v_doc_type_code\n FROM technicaldocs t\n JOIN document_types dt ON dt.document_types_id = t.document_type_id\n WHERE t.id = NEW.technical_doc_id;\n\n IF v_doc_proj IS NULL THEN\n SIGNAL SQLSTATE \'45000\' SET MESSAGE_TEXT=\'technical_doc not found\';\n END IF;\n IF v_doc_type_code <> \'DWG\' THEN\n SIGNAL SQLSTATE \'45000\' SET MESSAGE_TEXT=\'technical_doc must be type DWG\';\n END IF;\n\n \n SELECT project_id INTO v_dwg_proj FROM contract_dwg WHERE condwg_id = NEW.condwg_id;\n IF v_dwg_proj IS NULL THEN\n SIGNAL SQLSTATE \'45000\' SET MESSAGE_TEXT=\'contract_dwg not found\';\n END IF;\n IF v_dwg_proj <> v_doc_proj THEN\n SIGNAL SQLSTATE \'45000\' SET MESSAGE_TEXT=\'DWG doc and contract_dwg must be in the same project\';\n END IF;\nEND' 'CREATE DEFINER=`root`@`localhost` TRIGGER trg_scd_bu_block_update\nBEFORE UPDATE ON dwgdoc_contract_dwg\nFOR EACH ROW\nBEGIN\n SIGNAL SQLSTATE \'45000\' SET MESSAGE_TEXT=\'Update not allowed; delete then insert\';\nEND'
|
||||
sql_modes=1411383296 1411383296
|
||||
definers='root@localhost' 'root@localhost'
|
||||
client_cs_names='utf8mb4' 'utf8mb4'
|
||||
connection_cl_names='utf8mb4_general_ci' 'utf8mb4_general_ci'
|
||||
db_cl_names='utf8mb4_general_ci' 'utf8mb4_general_ci'
|
||||
created=1759220383708744 1759220383819565
|
||||
BIN
mariadb/data/dms/dwgdoc_contract_dwg.frm
Normal file
BIN
mariadb/data/dms/dwgdoc_contract_dwg.frm
Normal file
Binary file not shown.
BIN
mariadb/data/dms/dwgdoc_contract_dwg.ibd
Normal file
BIN
mariadb/data/dms/dwgdoc_contract_dwg.ibd
Normal file
Binary file not shown.
BIN
mariadb/data/dms/email_details.frm
Normal file
BIN
mariadb/data/dms/email_details.frm
Normal file
Binary file not shown.
BIN
mariadb/data/dms/email_details.ibd
Normal file
BIN
mariadb/data/dms/email_details.ibd
Normal file
Binary file not shown.
8
mariadb/data/dms/global_default_roles.TRG
Normal file
8
mariadb/data/dms/global_default_roles.TRG
Normal file
@@ -0,0 +1,8 @@
|
||||
TYPE=TRIGGERS
|
||||
triggers='CREATE DEFINER=`root`@`localhost` TRIGGER trg_gdr_bi_match_org_primary\nBEFORE INSERT ON global_default_roles\nFOR EACH ROW\nBEGIN\n DECLARE v_primary VARCHAR(20);\n SELECT primary_role INTO v_primary FROM organizations WHERE org_id = NEW.org_id;\n IF v_primary IS NULL THEN\n SIGNAL SQLSTATE \'45000\' SET MESSAGE_TEXT=\'Organization not found for global_default_roles\';\n END IF;\n IF NEW.role <> v_primary THEN\n SIGNAL SQLSTATE \'45000\' SET MESSAGE_TEXT=\'global_default_roles.role must match organizations.primary_role\';\n END IF;\nEND' 'CREATE DEFINER=`root`@`localhost` TRIGGER trg_gdr_bu_match_org_primary\nBEFORE UPDATE ON global_default_roles\nFOR EACH ROW\nBEGIN\n DECLARE v_primary VARCHAR(20);\n SELECT primary_role INTO v_primary FROM organizations WHERE org_id = NEW.org_id;\n IF v_primary IS NULL THEN\n SIGNAL SQLSTATE \'45000\' SET MESSAGE_TEXT=\'Organization not found for global_default_roles\';\n END IF;\n IF NEW.role <> v_primary THEN\n SIGNAL SQLSTATE \'45000\' SET MESSAGE_TEXT=\'global_default_roles.role must match organizations.primary_role\';\n END IF;\nEND'
|
||||
sql_modes=1411383296 1411383296
|
||||
definers='root@localhost' 'root@localhost'
|
||||
client_cs_names='utf8mb4' 'utf8mb4'
|
||||
connection_cl_names='utf8mb4_general_ci' 'utf8mb4_general_ci'
|
||||
db_cl_names='utf8mb4_general_ci' 'utf8mb4_general_ci'
|
||||
created=1759220379175294 1759220379347439
|
||||
BIN
mariadb/data/dms/global_default_roles.frm
Normal file
BIN
mariadb/data/dms/global_default_roles.frm
Normal file
Binary file not shown.
BIN
mariadb/data/dms/global_default_roles.ibd
Normal file
BIN
mariadb/data/dms/global_default_roles.ibd
Normal file
Binary file not shown.
BIN
mariadb/data/dms/instruction_details.frm
Normal file
BIN
mariadb/data/dms/instruction_details.frm
Normal file
Binary file not shown.
BIN
mariadb/data/dms/instruction_details.ibd
Normal file
BIN
mariadb/data/dms/instruction_details.ibd
Normal file
Binary file not shown.
BIN
mariadb/data/dms/letter_details.frm
Normal file
BIN
mariadb/data/dms/letter_details.frm
Normal file
Binary file not shown.
BIN
mariadb/data/dms/letter_details.ibd
Normal file
BIN
mariadb/data/dms/letter_details.ibd
Normal file
Binary file not shown.
BIN
mariadb/data/dms/memorandum_details.frm
Normal file
BIN
mariadb/data/dms/memorandum_details.frm
Normal file
Binary file not shown.
BIN
mariadb/data/dms/memorandum_details.ibd
Normal file
BIN
mariadb/data/dms/memorandum_details.ibd
Normal file
Binary file not shown.
BIN
mariadb/data/dms/minutes_of_meeting_details.frm
Normal file
BIN
mariadb/data/dms/minutes_of_meeting_details.frm
Normal file
Binary file not shown.
BIN
mariadb/data/dms/minutes_of_meeting_details.ibd
Normal file
BIN
mariadb/data/dms/minutes_of_meeting_details.ibd
Normal file
Binary file not shown.
BIN
mariadb/data/dms/organizations.frm
Normal file
BIN
mariadb/data/dms/organizations.frm
Normal file
Binary file not shown.
BIN
mariadb/data/dms/organizations.ibd
Normal file
BIN
mariadb/data/dms/organizations.ibd
Normal file
Binary file not shown.
BIN
mariadb/data/dms/permissions.frm
Normal file
BIN
mariadb/data/dms/permissions.frm
Normal file
Binary file not shown.
BIN
mariadb/data/dms/permissions.ibd
Normal file
BIN
mariadb/data/dms/permissions.ibd
Normal file
Binary file not shown.
8
mariadb/data/dms/project_parties.TRG
Normal file
8
mariadb/data/dms/project_parties.TRG
Normal file
@@ -0,0 +1,8 @@
|
||||
TYPE=TRIGGERS
|
||||
triggers='CREATE DEFINER=`root`@`localhost` TRIGGER trg_pp_bi_guard\nBEFORE INSERT ON project_parties\nFOR EACH ROW\nBEGIN\n SET NEW.role = UPPER(NEW.role);\n\n IF NEW.role = \'CONTRACTOR\' AND\n EXISTS (SELECT 1 FROM project_parties\n WHERE project_id = NEW.project_id\n AND role = \'CONTRACTOR\'\n AND deleted_at IS NULL) THEN\n SIGNAL SQLSTATE \'45000\' SET MESSAGE_TEXT=\'This project already has a CONTRACTOR\';\n END IF;\nEND' 'CREATE DEFINER=`root`@`localhost` TRIGGER trg_pp_bu_guard\nBEFORE UPDATE ON project_parties\nFOR EACH ROW\nBEGIN\n SET NEW.role = UPPER(NEW.role);\n\n IF NEW.role = \'CONTRACTOR\' AND\n EXISTS (SELECT 1 FROM project_parties\n WHERE project_id = NEW.project_id\n AND role = \'CONTRACTOR\'\n AND deleted_at IS NULL\n AND NOT (org_id = OLD.org_id AND role = \'CONTRACTOR\')) THEN\n SIGNAL SQLSTATE \'45000\' SET MESSAGE_TEXT=\'This project already has a CONTRACTOR\';\n END IF;\nEND'
|
||||
sql_modes=1411383296 1411383296
|
||||
definers='root@localhost' 'root@localhost'
|
||||
client_cs_names='utf8mb4' 'utf8mb4'
|
||||
connection_cl_names='utf8mb4_general_ci' 'utf8mb4_general_ci'
|
||||
db_cl_names='utf8mb4_general_ci' 'utf8mb4_general_ci'
|
||||
created=1759220378876780 1759220379009579
|
||||
BIN
mariadb/data/dms/project_parties.frm
Normal file
BIN
mariadb/data/dms/project_parties.frm
Normal file
Binary file not shown.
BIN
mariadb/data/dms/project_parties.ibd
Normal file
BIN
mariadb/data/dms/project_parties.ibd
Normal file
Binary file not shown.
BIN
mariadb/data/dms/projects.frm
Normal file
BIN
mariadb/data/dms/projects.frm
Normal file
Binary file not shown.
BIN
mariadb/data/dms/projects.ibd
Normal file
BIN
mariadb/data/dms/projects.ibd
Normal file
Binary file not shown.
8
mariadb/data/dms/rfa_items.TRG
Normal file
8
mariadb/data/dms/rfa_items.TRG
Normal file
@@ -0,0 +1,8 @@
|
||||
TYPE=TRIGGERS
|
||||
triggers='CREATE DEFINER=`root`@`localhost` TRIGGER trg_rfa_items_bi_guard\nBEFORE INSERT ON rfa_items\nFOR EACH ROW\nBEGIN\n DECLARE v_type_code VARCHAR(20);\n DECLARE v_hdr_proj INT;\n DECLARE v_doc_proj INT;\n\n SELECT t.type_code, c.project_id\n INTO v_type_code, v_hdr_proj\n FROM correspondences c\n JOIN correspondence_types t ON t.type_id = c.correspondence_type_id\n WHERE c.corr_id = NEW.rfa_corr_id;\n\n IF v_type_code IS NULL THEN\n SIGNAL SQLSTATE \'45000\' SET MESSAGE_TEXT=\'RFA header not found\';\n END IF;\n IF v_type_code <> \'RFA\' THEN\n SIGNAL SQLSTATE \'45000\' SET MESSAGE_TEXT=\'rfa_corr_id must be a correspondence of type RFA\';\n END IF;\n\n SELECT project_id INTO v_doc_proj FROM technicaldocs WHERE id = NEW.technical_doc_id;\n IF v_doc_proj IS NULL THEN\n SIGNAL SQLSTATE \'45000\' SET MESSAGE_TEXT=\'technical document not found\';\n END IF;\n\n IF v_hdr_proj <> v_doc_proj THEN\n SIGNAL SQLSTATE \'45000\' SET MESSAGE_TEXT=\'RFA header and technicaldoc must be in the same project\';\n END IF;\nEND' 'CREATE DEFINER=`root`@`localhost` TRIGGER trg_rfa_items_bu_guard\nBEFORE UPDATE ON rfa_items\nFOR EACH ROW\nBEGIN\n SIGNAL SQLSTATE \'45000\' SET MESSAGE_TEXT=\'Update on rfa_items is not allowed; delete and re-insert\';\nEND'
|
||||
sql_modes=1411383296 1411383296
|
||||
definers='root@localhost' 'root@localhost'
|
||||
client_cs_names='utf8mb4' 'utf8mb4'
|
||||
connection_cl_names='utf8mb4_general_ci' 'utf8mb4_general_ci'
|
||||
db_cl_names='utf8mb4_general_ci' 'utf8mb4_general_ci'
|
||||
created=1759220377624801 1759220377737882
|
||||
BIN
mariadb/data/dms/rfa_items.frm
Normal file
BIN
mariadb/data/dms/rfa_items.frm
Normal file
Binary file not shown.
BIN
mariadb/data/dms/rfa_items.ibd
Normal file
BIN
mariadb/data/dms/rfa_items.ibd
Normal file
Binary file not shown.
BIN
mariadb/data/dms/rfi_details.frm
Normal file
BIN
mariadb/data/dms/rfi_details.frm
Normal file
Binary file not shown.
BIN
mariadb/data/dms/rfi_details.ibd
Normal file
BIN
mariadb/data/dms/rfi_details.ibd
Normal file
Binary file not shown.
BIN
mariadb/data/dms/role_permissions.frm
Normal file
BIN
mariadb/data/dms/role_permissions.frm
Normal file
Binary file not shown.
BIN
mariadb/data/dms/role_permissions.ibd
Normal file
BIN
mariadb/data/dms/role_permissions.ibd
Normal file
Binary file not shown.
BIN
mariadb/data/dms/roles.frm
Normal file
BIN
mariadb/data/dms/roles.frm
Normal file
Binary file not shown.
BIN
mariadb/data/dms/roles.ibd
Normal file
BIN
mariadb/data/dms/roles.ibd
Normal file
Binary file not shown.
8
mariadb/data/dms/technicaldocs.TRG
Normal file
8
mariadb/data/dms/technicaldocs.TRG
Normal file
@@ -0,0 +1,8 @@
|
||||
TYPE=TRIGGERS
|
||||
triggers='CREATE DEFINER=`root`@`localhost` TRIGGER trg_tdoc_bi_normalize\nBEFORE INSERT ON technicaldocs\nFOR EACH ROW\nBEGIN\n DECLARE v_orig_proj INT;\n\n SET NEW.title = TRIM(NEW.title);\n SET NEW.revision = NULLIF(TRIM(NEW.revision), \'\');\n SET NEW.pdf_path = NULLIF(TRIM(NEW.pdf_path), \'\');\n\n IF NEW.project_id IS NULL OR NEW.document_type_id IS NULL OR NEW.status_code_id IS NULL THEN\n SIGNAL SQLSTATE \'45000\' SET MESSAGE_TEXT=\'project_id/document_type_id/status_code_id is required\';\n END IF;\n IF NEW.revision IS NULL OR NEW.revision=\'\' THEN\n SIGNAL SQLSTATE \'45000\' SET MESSAGE_TEXT=\'technicaldoc revision is required\';\n END IF;\n\n SET v_orig_proj = NULL;\n IF NEW.original_id IS NOT NULL AND NEW.original_id <> 0 THEN\n SELECT project_id INTO v_orig_proj FROM technicaldocs WHERE id = NEW.original_id;\n IF v_orig_proj IS NULL THEN\n SIGNAL SQLSTATE \'45000\' SET MESSAGE_TEXT=\'original_id not found\';\n END IF;\n IF v_orig_proj <> NEW.project_id THEN\n SIGNAL SQLSTATE \'45000\' SET MESSAGE_TEXT=\'original and new revision must be in the same project\';\n END IF;\n END IF;\nEND' 'CREATE DEFINER=`root`@`localhost` TRIGGER trg_tdoc_ai_set_original\nAFTER INSERT ON technicaldocs\nFOR EACH ROW\nBEGIN\n IF NEW.original_id IS NULL OR NEW.original_id = 0 THEN\n UPDATE technicaldocs SET original_id = NEW.id WHERE id = NEW.id;\n END IF;\nEND' 'CREATE DEFINER=`root`@`localhost` TRIGGER trg_tdoc_bu_normalize\nBEFORE UPDATE ON technicaldocs\nFOR EACH ROW\nBEGIN\n SET NEW.title = TRIM(NEW.title);\n SET NEW.revision = NULLIF(TRIM(NEW.revision), \'\');\n SET NEW.pdf_path = NULLIF(TRIM(NEW.pdf_path), \'\');\n\n \n IF NEW.original_id <> OLD.original_id THEN\n SIGNAL SQLSTATE \'45000\' SET MESSAGE_TEXT=\'original_id is immutable\';\n END IF;\n IF NEW.project_id <> OLD.project_id THEN\n SIGNAL SQLSTATE \'45000\' SET MESSAGE_TEXT=\'project_id is immutable for a doc family\';\n END IF;\nEND'
|
||||
sql_modes=1411383296 1411383296 1411383296
|
||||
definers='root@localhost' 'root@localhost' 'root@localhost'
|
||||
client_cs_names='utf8mb4' 'utf8mb4' 'utf8mb4'
|
||||
connection_cl_names='utf8mb4_general_ci' 'utf8mb4_general_ci' 'utf8mb4_general_ci'
|
||||
db_cl_names='utf8mb4_general_ci' 'utf8mb4_general_ci' 'utf8mb4_general_ci'
|
||||
created=1759220377008102 1759220377345616 1759220377107766
|
||||
BIN
mariadb/data/dms/technicaldocs.frm
Normal file
BIN
mariadb/data/dms/technicaldocs.frm
Normal file
Binary file not shown.
BIN
mariadb/data/dms/technicaldocs.ibd
Normal file
BIN
mariadb/data/dms/technicaldocs.ibd
Normal file
Binary file not shown.
8
mariadb/data/dms/transmittal_items.TRG
Normal file
8
mariadb/data/dms/transmittal_items.TRG
Normal file
@@ -0,0 +1,8 @@
|
||||
TYPE=TRIGGERS
|
||||
triggers='CREATE DEFINER=`root`@`localhost` TRIGGER trg_tra_items_bi_guard\nBEFORE INSERT ON transmittal_items\nFOR EACH ROW\nBEGIN\n DECLARE v_type_code VARCHAR(20);\n DECLARE v_hdr_proj INT;\n DECLARE v_item_proj INT;\n\n IF NEW.transmittal_corr_id = NEW.item_corr_id THEN\n SIGNAL SQLSTATE \'45000\' SET MESSAGE_TEXT=\'transmittal cannot include itself as an item\';\n END IF;\n\n SELECT t.type_code, c.project_id\n INTO v_type_code, v_hdr_proj\n FROM correspondences c\n JOIN correspondence_types t ON t.type_id = c.correspondence_type_id\n WHERE c.corr_id = NEW.transmittal_corr_id;\n\n IF v_type_code IS NULL THEN\n SIGNAL SQLSTATE \'45000\' SET MESSAGE_TEXT=\'Transmittal header not found\';\n END IF;\n IF v_type_code <> \'TRANSMITTAL\' THEN\n SIGNAL SQLSTATE \'45000\' SET MESSAGE_TEXT=\'transmittal_corr_id must be type TRANSMITTAL\';\n END IF;\n\n SELECT project_id INTO v_item_proj FROM correspondences WHERE corr_id = NEW.item_corr_id;\n IF v_item_proj IS NULL THEN\n SIGNAL SQLSTATE \'45000\' SET MESSAGE_TEXT=\'item correspondence not found\';\n END IF;\n\n IF v_hdr_proj <> v_item_proj THEN\n SIGNAL SQLSTATE \'45000\' SET MESSAGE_TEXT=\'Transmittal header and item must be in the same project\';\n END IF;\nEND' 'CREATE DEFINER=`root`@`localhost` TRIGGER trg_tra_items_bu_guard\nBEFORE UPDATE ON transmittal_items\nFOR EACH ROW\nBEGIN\n SIGNAL SQLSTATE \'45000\' SET MESSAGE_TEXT=\'Update on transmittal_items is not allowed; delete and re-insert\';\nEND'
|
||||
sql_modes=1411383296 1411383296
|
||||
definers='root@localhost' 'root@localhost'
|
||||
client_cs_names='utf8mb4' 'utf8mb4'
|
||||
connection_cl_names='utf8mb4_general_ci' 'utf8mb4_general_ci'
|
||||
db_cl_names='utf8mb4_general_ci' 'utf8mb4_general_ci'
|
||||
created=1759220378602006 1759220378710787
|
||||
BIN
mariadb/data/dms/transmittal_items.frm
Normal file
BIN
mariadb/data/dms/transmittal_items.frm
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user