Browse Source

簡易更改

steve07s 1 year ago
parent
commit
1a22d9e312
8 changed files with 132 additions and 22 deletions
  1. 4 0
      .env.example
  2. BIN
      bun.lockb
  3. 1 1
      package.json
  4. 63 4
      routers/api.js
  5. 12 3
      server.js
  6. 0 1
      static/index.html
  7. 3 1
      static/js/api_calls.js
  8. 49 12
      static/js/frontend.js

+ 4 - 0
.env.example

@@ -0,0 +1,4 @@
+PORT=8000
+SESSION_KEY=
+WEATHER_API_KEY=
+WEATHER_API_URL=

BIN
bun.lockb


+ 1 - 1
package.json

@@ -15,7 +15,7 @@
     "browser-sync": "^3.0.2",
     "cookie-session": "^2.0.0",
     "date-fns": "^3.6.0",
-    "dotenv": "^16.0.3",
+    "dotenv": "^16.4.5",
     "ejs": "^3.1.9",
     "express": "^4.18.2"
   },

+ 63 - 4
routers/api.js

@@ -1,15 +1,74 @@
-let express = require("express");
+//router/api.js
+const cookieSession = require("cookie-session");
+const express = require("express");
+const bodyParser = require("body-parser");
 let db = require("../pass_db");
 
+
 const router = express.Router();
 
+router.use(bodyParser.json());
+
+const WEATHER_API_KEY = process.env.WEATHER_API_KEY;
+const WEATHER_API_URL = process.env.WEATHER_API_URL;
+
+// 註冊 API
+router.post('/signup', (req, res) => {
+  const { username, password } = req.body;
+  if (db.createUser(username, password)) {
+    // 註冊成功,進行自動登錄操作
+    req.session.username = username;
+    res.status(200).json({ success: true, data: { username } });
+  } else {
+    // 用戶名已存在
+    res.status(400).json({ success: false, error: 'Username is already taken.' });
+  }
+});
+
+// 登錄 API
+router.post('/login', (req, res) => {
+  const { username, password } = req.body;
+  const user = db.authenticateUser(username, password);
+  if (user) {
+    req.session.username = username;
+    res.status(200).json({ success: true, data: { username } });
+  } else {
+    res.status(401).json({ success: false, error: 'Invalid username or password.' });
+  }
+}); 
+
 
+// 登出 API
+router.post('/logout', (req, res) => {
+  req.session = null;
+  res.status(200).json({ success: true, data: null });
+});
 
-router.get("/test", (req, res) => {
-  res.send("tested")
-})
+// 獲取會話 API
+router.get('/getSession', (req, res) => {
+  if (req.session.username) {
+    res.status(200).json({ success: true, data: { username: req.session.username } });
+  } else {
+    res.status(200).json({ success: true, data: null });
+  }
+});
 
+// 獲取投票數據 API
+router.get('/votes/list', (req, res) => {
+  const votes = db.getVotesAllDays();
+  res.status(200).json({ success: true, data: votes });
+});
 
+// 設定投票 API (為SATIS Tier準備)
+router.post('/votes/set', (req, res) => {
+  const { username, date, vote } = req.body;
+  if (req.session.username === username) {
+    db.placeVote(username, date, vote);
+    res.status(200).json({ success: true });
+  } else {
+    res.status(403).json({ success: false, error: "Unauthorized" });
+  }
+});
 
 module.exports = router;
 

+ 12 - 3
server.js

@@ -1,6 +1,7 @@
+//server.js 專案起始點
 const express = require("express");
-const bodyParser = require("body-parser")
 const cookieSession = require("cookie-session");
+const dotenv = require('dotenv').config();
 
 const db = require('./pass_db.js');
 db.users_init_fixed()
@@ -8,10 +9,18 @@ db.vote_init_random(5);     // you COULD change this, but you could also leave i
 
 const app = express();
 
-const PORT = 8000;
+const PORT = process.env.PORT || 8000; // 允許從 .env 文件或環境變量中設定端口
 app.use(express.static("static"))
 app.set('view engine', 'ejs')
-app.use(cookieSession({ name: 'session', keys: ['every_student_will_change_this_key_because_it_would_be_embarrassing_to_leave_it'] }))
+app.use(cookieSession({
+    name: 'session',
+    keys: [process.env.SESSION_KEY || 'default_session_key'],
+    maxAge: 24 * 60 * 60 * 1000 // 24 hours
+  }))
+
+// 使用 Express 內建的中間件來解析 JSON 和 URL 編碼的資料
+app.use(express.json());
+app.use(express.urlencoded({ extended: true }));
 
 const apiRouter = require("./routers/api")
 app.use('/api/v1', apiRouter);

+ 0 - 1
static/index.html

@@ -34,7 +34,6 @@
             <input id="headerpassword" name="password" input type="password" />
             <button data-auth-action="signup" class="signup">Sign Up</button>
             <button data-auth-action="login" class="login">Log In</button>
-            <button onclick="ajaxLogin()">Log In TEST</button>
           </div>
           <div class="error-message" style="color: rgb(80, 48, 48)"></div>
         </form>

+ 3 - 1
static/js/api_calls.js

@@ -1,3 +1,4 @@
+//static/js/api_calls.js
 let fake_local_session = { username: 'nobody' };
 
 let fake_local_votesdata = [
@@ -36,6 +37,7 @@ let fake_local_votesdata = [
 async function getSessionFromBackend() {
   try {
     const response = await axios.get('/api/v1/getSession');
+    console.log(response.data)
     return response.data;
   } catch (error) {
     console.error('Error fetching session from backend:', error);
@@ -45,7 +47,7 @@ async function getSessionFromBackend() {
 
 async function getVotesFromBackend() {
   try {
-    const response = await axios.get('/api/v1/votes');
+    const response = await axios.get('/api/v1/votes/list');
     return response.data;
   } catch (error) {
     console.error('Error fetching votes from backend:', error);

+ 49 - 12
static/js/frontend.js

@@ -1,3 +1,4 @@
+//static/js/frontend.js
 function setLoggedIn(loggedInBoolean) {
   let body = document.body;
   body.dataset.loggedIn = !!loggedInBoolean;
@@ -83,7 +84,10 @@ function updateVotableDays(daysWithVotes, currentSession, weatherForecasts) {
   for (let date in daysWithVotes) {
     let votes = daysWithVotes[date];
     let weather = weatherForecasts?.[date];
-    daysView.append(createOneDayCard({ date, votes }, currentSession, weather))
+    daysView.append(createOneDayCard({
+      date,
+      votes
+    }, currentSession, weather))
   }
 }
 
@@ -118,7 +122,11 @@ class FrontendState {
   }
 
   async refreshVotesState(updateView = true) {
-    let { success, data, error } = await getVotesFromBackend()
+    let {
+      success,
+      data,
+      error
+    } = await getVotesFromBackend()
     if (success) {
       this.daysWithVotes = data;
     } else {
@@ -131,7 +139,11 @@ class FrontendState {
   }
 
   async refreshWeatherState(updateView = true) {
-    let { success, data, error } = await getWeather()
+    let {
+      success,
+      data,
+      error
+    } = await getWeather()
     if (success) {
       this.weatherForecasts = data;
     } else {
@@ -144,7 +156,11 @@ class FrontendState {
   }
 
   async refreshSessionState(updateView = true) {
-    let { success, data, error } = await getSessionFromBackend()
+    let {
+      success,
+      data,
+      error
+    } = await getSessionFromBackend()
     if (success) {
       this.currentSession = data;
     } else {
@@ -194,23 +210,38 @@ async function handleAuthEvent(event) {
       signup: ajaxSignup,
       login: ajaxLogin,
       logout: ajaxLogout,
-    }[authActionName];
+    } [authActionName];
     if (authActionFunction) {
       let authResult = await authActionFunction(usernameValue, passwordValue);
       if (authResult && authResult.success) {
+        if (authActionName === 'logout') {
+          // 登出成功,清除用戶名顯示
+          updateUsernameDisplay('');
+        } else {
+          // 登入或註冊成功,更新用戶名顯示
+          updateUsernameDisplay(authResult.data.username);
+        }
         await fes.refreshSessionState();
         usernameInput.value = passwordInput.value = '';
       } else if (authResult) {
-        // yo this is crap and if you want to be better than me, replace it.
-        alert(authResult.error)
+        // 處理登入、註冊或登出失敗的情況
+        alert(authResult.error);
       } else {
-        // yo this is crap and if you want to be better than me, replace it.
-        alert("unknown network error")
+        // 處理未知網絡錯誤
+        alert("unknown network error");
       }
+
     }
   }
 }
 
+function updateUsernameDisplay(username) {
+  const usernameSpan = document.querySelector('.username');
+  if (usernameSpan) {
+    usernameSpan.textContent = username || 'nobody'; // 如果username為空,顯示'nobody'
+  }
+}
+
 const authform = document.querySelector('form.authform')
 authform.addEventListener("click", handleAuthEvent);
 
@@ -225,9 +256,15 @@ async function handleVoteEvent(event) {
 
   if (button) {
     let voteVal;
-    if (button.classList.contains('yes')) { voteVal = 'yes'; }
-    if (button.classList.contains('no')) { voteVal = 'no'; }
-    if (button.classList.contains('maybe')) { voteVal = 'maybe'; }
+    if (button.classList.contains('yes')) {
+      voteVal = 'yes';
+    }
+    if (button.classList.contains('no')) {
+      voteVal = 'no';
+    }
+    if (button.classList.contains('maybe')) {
+      voteVal = 'maybe';
+    }
     let cardDiv = button.closest("div.card");
     if (!voteVal || !cardDiv) {
       // console.log({ voteVal, cardDiv })