diff --git a/node/express/api/app.ts b/node/express/api/app.ts index 9d65fee..02c17d0 100644 --- a/node/express/api/app.ts +++ b/node/express/api/app.ts @@ -4,17 +4,17 @@ import path from "path"; import cookieParser from "cookie-parser"; import logger from "morgan"; -//authorization -import passport from "./config/passport"; -import session from "express-session"; - // route import { router as chatRouter } from "./routes/chat"; import { router as apiBoardRouter } from "./routes/api/board"; -import { router as loginRouter } from "./routes/login"; +import { router as callbackRouter } from "./routes/callback"; +import { router as apiCallbackRouter } from "./routes/api/callback"; import { router as planRouter } from "./routes/plan"; import { router as tenantRouter } from "./routes/tenant"; +//middleware +import { AuthMiddleware } from "saasus-sdk"; + import cors from "cors"; if (process.env.NODE_ENV !== "production") { @@ -41,25 +41,22 @@ app.use( ); app.use( - session({ - secret: "secret", - resave: false, - saveUninitialized: false, - }) + ["/chat", "/api/board", "/api/post", "/api/plan", "/api/tenant"], + AuthMiddleware ); -app.use(passport.initialize()); -app.use(passport.session()); app.use("/chat", chatRouter); app.use(["/api/board", "/api/post"], apiBoardRouter); +app.use("/callback", callbackRouter); + +app.use("/api/callback", apiCallbackRouter); + app.use("/api/plan", planRouter); app.use("/api/tenant", tenantRouter); -app.use("/login", loginRouter); - app.use((req: Request, res: Response, next: NextFunction) => { next(createError(404)); }); diff --git a/node/express/api/controllers/api/board.ts b/node/express/api/controllers/api/board.ts index 9d49d43..bc26f42 100644 --- a/node/express/api/controllers/api/board.ts +++ b/node/express/api/controllers/api/board.ts @@ -1,12 +1,13 @@ import { Request, Response } from "express"; +import { UpdateMeteringUnitTimestampCountNowParam } from "saasus-sdk/dist/generated/Pricing"; const db = require("../../models/index"); -import { TENANT_ID } from "../tenant"; +import { findUpperCountByMeteringUnitName, PricingClient } from "saasus-sdk"; const getBoard = async (req: Request, res: Response) => { try { const messages = await db.Messages.findAll({ where: { - tenant_id: TENANT_ID, + tenant_id: req.userInfo?.tenants[0].id, }, }); return res.json(messages); @@ -20,13 +21,43 @@ const getBoard = async (req: Request, res: Response) => { const post = async (req: Request, res: Response) => { const mes = req.body.message; - const userName = "テストユーザー"; + const tenantId = req.userInfo?.tenants[0].id || ""; + const planId = req.userInfo?.tenants[0].plan_id || ""; + const userName = + req.userInfo?.tenants[0].user_attribute.username || "テストユーザー"; try { - await db.Messages.create({ - tenant_id: TENANT_ID, - user_id: userName, - message: mes, - }); + const pricingClient = new PricingClient(); + const pricingPlan = await pricingClient.pricingPlansApi.getPricingPlan( + planId + ); + const meteringUnitName = "comment_count"; + const meteringUnitCountData = + await pricingClient.meteringApi.getMeteringUnitDateCountByTenantIdAndUnitNameToday( + tenantId, + meteringUnitName + ); + const upper = findUpperCountByMeteringUnitName( + pricingPlan.data, + meteringUnitName + ); + if (meteringUnitCountData.data.count < upper || upper === 0) { + await db.Messages.create({ + tenant_id: tenantId, + user_id: userName, + message: mes, + }); + let param: UpdateMeteringUnitTimestampCountNowParam = { + method: "add", + count: 1, + }; + const res = + await pricingClient.meteringApi.updateMeteringUnitTimestampCountNow( + tenantId, + meteringUnitName, + param + ); + } + return res.status(201).send(); } catch (error) { console.error(error); } diff --git a/node/express/api/controllers/chat.ts b/node/express/api/controllers/chat.ts index acffd82..3146944 100644 --- a/node/express/api/controllers/chat.ts +++ b/node/express/api/controllers/chat.ts @@ -1,14 +1,15 @@ -import { SessionUser } from "config/passport"; -import { TENANT_ID, TENANT_NAME } from "./tenant"; import { Request, Response } from "express"; -import { PLANS } from "./plan"; -const db = require("./../models/index"); +import { UpdateMeteringUnitTimestampCountNowParam } from "saasus-sdk/dist/generated/Pricing"; +const db = require("../models/index"); +import { findUpperCountByMeteringUnitName, PricingClient } from "saasus-sdk"; +import { PLANS } from "../controllers/plan"; +import { TENANT_NAME } from "../controllers/tenant"; const getChats = async (req: Request, res: Response) => { try { const messages = await db.Messages.findAll({ where: { - tenant_id: TENANT_ID, + tenant_id: req.userInfo?.tenants[0].id, }, }); res.render("chat", { @@ -24,14 +25,42 @@ const getChats = async (req: Request, res: Response) => { const postChats = async (req: Request, res: Response) => { const mes = req.body.message; - const sessionUser: SessionUser = req.user || {}; - const userName = sessionUser.name; + const tenantId = req.userInfo?.tenants[0].id || ""; + const planId = req.userInfo?.tenants[0].plan_id || ""; + const userName = + req.userInfo?.tenants[0].user_attribute.username || "テストユーザー"; try { - await db.Messages.create({ - tenant_id: TENANT_ID, - user_id: userName, - message: mes, - }); + const pricingClient = new PricingClient(); + const pricingPlan = await pricingClient.pricingPlansApi.getPricingPlan( + planId + ); + const meteringUnitName = "comment_count"; + const meteringUnitCountData = + await pricingClient.meteringApi.getMeteringUnitDateCountByTenantIdAndUnitNameToday( + tenantId, + meteringUnitName + ); + const upper = findUpperCountByMeteringUnitName( + pricingPlan.data, + meteringUnitName + ); + if (meteringUnitCountData.data.count < upper || upper === 0) { + await db.Messages.create({ + tenant_id: tenantId, + user_id: userName, + message: mes, + }); + let param: UpdateMeteringUnitTimestampCountNowParam = { + method: "add", + count: 1, + }; + const res = + await pricingClient.meteringApi.updateMeteringUnitTimestampCountNow( + tenantId, + meteringUnitName, + param + ); + } } catch (error) { console.error(error); } diff --git a/node/express/api/package-lock.json b/node/express/api/package-lock.json index d79b3a8..c8816c1 100644 --- a/node/express/api/package-lock.json +++ b/node/express/api/package-lock.json @@ -25,6 +25,7 @@ "passport-local": "^1.0.0", "pg": "^8.8.0", "pg-hstore": "^2.3.4", + "saasus-sdk": "^1.2.0", "sequelize": "^6.25.5" }, "devDependencies": { @@ -3282,6 +3283,22 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/saasus-sdk": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/saasus-sdk/-/saasus-sdk-1.2.0.tgz", + "integrity": "sha512-tls3sekDdhCzxt2jAG+yDdAuJu79hNxbaMqrLYNqU8begt0XFFvEbJdsDp6cBO8agMbbliXeFck8R2hO8z0Uqw==", + "hasInstallScript": true, + "dependencies": { + "axios": "^1.1.3", + "crypto-js": "^4.1.1", + "date-and-time": "^2.4.1" + }, + "peerDependencies": { + "axios": "^1.1.3", + "crypto-js": "^4.1.1", + "date-and-time": "^2.4.1" + } + }, "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -6594,6 +6611,16 @@ "queue-microtask": "^1.2.2" } }, + "saasus-sdk": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/saasus-sdk/-/saasus-sdk-1.2.0.tgz", + "integrity": "sha512-tls3sekDdhCzxt2jAG+yDdAuJu79hNxbaMqrLYNqU8begt0XFFvEbJdsDp6cBO8agMbbliXeFck8R2hO8z0Uqw==", + "requires": { + "axios": "^1.1.3", + "crypto-js": "^4.1.1", + "date-and-time": "^2.4.1" + } + }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", diff --git a/node/express/api/package.json b/node/express/api/package.json index 2c11955..cd91b8d 100644 --- a/node/express/api/package.json +++ b/node/express/api/package.json @@ -28,6 +28,7 @@ "passport-local": "^1.0.0", "pg": "^8.8.0", "pg-hstore": "^2.3.4", + "saasus-sdk": "^1.2.0", "sequelize": "^6.25.5" }, "devDependencies": { diff --git a/node/express/api/routes/api/callback.ts b/node/express/api/routes/api/callback.ts new file mode 100644 index 0000000..b884039 --- /dev/null +++ b/node/express/api/routes/api/callback.ts @@ -0,0 +1,7 @@ +import express from "express"; +const router = express.Router(); +import { CallbackRouteFunction } from "saasus-sdk"; + +router.get("/", CallbackRouteFunction); + +export { router }; diff --git a/node/express/api/routes/callback.ts b/node/express/api/routes/callback.ts new file mode 100644 index 0000000..b884039 --- /dev/null +++ b/node/express/api/routes/callback.ts @@ -0,0 +1,7 @@ +import express from "express"; +const router = express.Router(); +import { CallbackRouteFunction } from "saasus-sdk"; + +router.get("/", CallbackRouteFunction); + +export { router }; diff --git a/node/express/api/routes/chat.ts b/node/express/api/routes/chat.ts index 2b9be20..cf78aeb 100644 --- a/node/express/api/routes/chat.ts +++ b/node/express/api/routes/chat.ts @@ -2,17 +2,7 @@ import express, { Request, Response, NextFunction } from "express"; const router = express.Router(); import { getChats, postChats } from "../controllers/chat"; -router.get( - "/", - (req: Request, res: Response, next: NextFunction) => { - if (req.isAuthenticated()) { - next(); - } else { - res.redirect(302, "/login"); - } - }, - getChats -); +router.get("/", getChats); router.post("/", postChats); diff --git a/node/express/api/views/callback.ejs b/node/express/api/views/callback.ejs new file mode 100644 index 0000000..32d6a0c --- /dev/null +++ b/node/express/api/views/callback.ejs @@ -0,0 +1,15 @@ + + + + + + + Auth Callback + + + + + + diff --git a/node/express/front/src/pages/board/index.tsx b/node/express/front/src/pages/board/index.tsx index 44dacae..0069dce 100644 --- a/node/express/front/src/pages/board/index.tsx +++ b/node/express/front/src/pages/board/index.tsx @@ -6,14 +6,33 @@ import axios from '@/lib/axios' const Board = () => { const { mutate } = useSWRConfig() - const fetcher = (url: string) => axios.get(url).then((res) => res.data) + const fetcher = (url: string) => { + // Local StorageからJWTを取得し、Bearer tokenとしてヘッダにつけてAPIコールする + const token = localStorage.getItem('SaaSusIdToken') + if (!token) return '' + return axios + .get(url, { + headers: { + Authorization: `Bearer ${token}`, + }, + }) + .then((res) => res.data) + } const { data: tenant_name, error: tenant_error } = useSWR( `/api/tenant`, fetcher ) const { data: messages, error } = useSWR(`/api/board`, fetcher, { - refreshInterval: 3000, + refreshInterval: 5000, }) + if ( + error && + error.response && + error.response.data && + error.response.data.redirect_url + ) { + location.replace(error.response.data.redirect_url) + } if (error || tenant_error) return
failed to load
if (!messages || !tenant_name) return
loading...
@@ -22,7 +41,13 @@ const Board = () => { // 再検証をせずに直ちにローカルデータを更新 mutate('/api/board', [...messages, formValue], false) // 更新するために API にリクエストを送信 - await axios.post('/api/post', formValue) + // Local StorageからJWTを取得し、Bearer tokenとしてヘッダにつけてAPIコールする + const token = localStorage.getItem('SaaSusIdToken') + await axios.post('/api/post', formValue, { + headers: { + Authorization: `Bearer ${token}`, + }, + }) } return ( @@ -36,4 +61,4 @@ const Board = () => { ) } -export default Board +export default Board \ No newline at end of file diff --git a/node/express/front/src/pages/callback/index.tsx b/node/express/front/src/pages/callback/index.tsx new file mode 100644 index 0000000..2765815 --- /dev/null +++ b/node/express/front/src/pages/callback/index.tsx @@ -0,0 +1,40 @@ +import Container from '@mui/material/Container' +import { useRouter } from 'next/router' +import { useEffect } from 'react' +import axios from '@/lib/axios' + +const Callback = () => { + const router = useRouter() + const query = router.query + const code = query.code as string + + const fetchAuthCredentials = async () => { + try { + const res = await axios.get(`/api/callback?code=${code}`) + // 渡ってきたJWTをLocal Storageに保存する + const idToken = res.data.id_token as string + localStorage.setItem('SaaSusIdToken', idToken) + router.replace('/board') + } catch (error: any) { + if ( + error.response && + error.response.data && + error.response.data.redirect_url + ) { + location.replace(error.response.data.redirect_url) + } + } + } + + useEffect(() => { + if (router.isReady) { + if (code) { + fetchAuthCredentials() + } + } + }, [query, router]) + + return +} + +export default Callback \ No newline at end of file