Gitlab@Informatics

Skip to content
Snippets Groups Projects
Commit 04ec841d authored by Theerapong Thawiwat's avatar Theerapong Thawiwat
Browse files

first commit

parents
No related branches found
No related tags found
No related merge requests found
Showing
with 541 additions and 0 deletions
.env 0 → 100644
DB_HOST=localhost
DB_USER=root
DB_PASS=
DB_NAME=mypocketapp
SESSION_SECRET=your_secret_key
const bcrypt = require('bcryptjs');
const db = require('../db');
async function registerUser(req, res) {
const { username, password } = req.body;
const hashedPassword = await bcrypt.hash(password, 10);
await db.query("INSERT INTO users (username, password) VALUES (?, ?)", [username, hashedPassword]);
res.redirect('/login');
}
async function loginUser(req, res) {
const { username, password } = req.body;
const [users] = await db.query("SELECT * FROM users WHERE username = ?", [username]);
if (users.length > 0) {
const isMatch = await bcrypt.compare(password, users[0].password);
if (isMatch) {
// เก็บข้อมูลผู้ใช้ใน session
req.session.user = users[0];
// บันทึกข้อมูลลงฐานข้อมูล เช่น บันทึกเวลาที่เข้าสู่ระบบ
const loginTime = new Date(); // เวลาปัจจุบัน
await db.query("UPDATE users SET last_login = ? WHERE id = ?", [loginTime, users[0].id]);
return res.redirect('/dashboard');
}
}
res.render('login', { error: 'Invalid credentials' });
}
async function logoutUser(req, res) {
req.session.destroy(() => res.redirect('/login'));
}
module.exports = { registerUser, loginUser, logoutUser };
\ No newline at end of file
const db = require('../db');
async function getBudget(req, res) {
if (!req.session.user) return res.redirect('/login');
const [budget] = await db.query("SELECT * FROM budgets WHERE user_id = ?", [req.session.user.id]);
res.render('budget', { budget });
}
async function setBudget(req, res) {
const { amount, month } = req.body;
await db.query("INSERT INTO budgets (user_id, amount, month) VALUES (?, ?, ?)",
[req.session.user.id, amount, month]);
res.redirect('/budget');
}
module.exports = { getBudget, setBudget };
const db = require('../db');
async function getDashboard(req, res) {
if (!req.session.user) return res.redirect('/login');
try {
const selectedMonth = req.query.month || new Date().toISOString().slice(0, 7);
const [year, month] = selectedMonth.split('-');
// Get expense summary
const query = `
SELECT
c.name AS category,
COALESCE(SUM(e.amount), 0) AS total
FROM categories c
LEFT JOIN expenses e ON c.id = e.category_id
AND e.user_id = ?
AND DATE_FORMAT(e.date, '%Y-%m') = ?
GROUP BY c.id, c.name
ORDER BY total DESC
`;
const [summary] = await db.query(query, [req.session.user.id, selectedMonth]);
// Calculate total expenses
const total = summary.reduce((acc, item) => acc + Number(item.total), 0);
// Get monthly budget (You should adjust this query based on your budget table structure)
const [budgetResult] = await db.query(
'SELECT amount FROM budgets WHERE user_id = ? AND DATE_FORMAT(month, "%Y-%m") = ?',
[req.session.user.id, selectedMonth]
);
const monthlyBudget = budgetResult.length > 0 ? budgetResult[0].amount : 0;
res.render('layout', {
content: 'dashboard',
summary: summary || [],
selectedMonth,
totalExpenses: total,
monthlyBudget,
monthTotal: total,
error: null
});
} catch (error) {
console.error('Database error:', error);
res.render('layout', {
content: 'dashboard',
summary: [],
selectedMonth: new Date().toISOString().slice(0, 7),
totalExpenses: 0,
monthlyBudget: 0,
monthTotal: 0,
error: 'เกิดข้อผิดพลาดในการดึงข้อมูล'
});
}
}
module.exports = { getDashboard };
const db = require('../db');
async function getExpenses(req, res) {
if (!req.session.user) return res.redirect('/login');
const [expenses] = await db.query(
"SELECT expenses.*, categories.name AS category FROM expenses JOIN categories ON expenses.category_id = categories.id WHERE user_id = ?",
[req.session.user.id]
);
res.render('expenses', { expenses });
}
async function addExpense(req, res) {
const { category_id, amount, description, date } = req.body;
await db.query("INSERT INTO expenses (user_id, category_id, amount, description, date) VALUES (?, ?, ?, ?, ?)",
[req.session.user.id, category_id, amount, description, date]);
res.redirect('/expenses');
}
async function deleteExpense(req, res) {
await db.query("DELETE FROM expenses WHERE id = ?", [req.params.id]);
res.redirect('/expenses');
}
module.exports = { getExpenses, addExpense, deleteExpense };
const db = require('../db');
const profileController = {
getProfile: async (req, res) => {
try {
if (!req.session.user) {
return res.redirect('/login');
}
const userId = req.session.user.id;
// ดึงข้อมูลผู้ใช้
const [users] = await db.query(
'SELECT id, username FROM users WHERE id = ?',
[userId]
);
// ดึงค่าใช้จ่ายทั้งหมด
const [totalResult] = await db.query(
'SELECT COALESCE(SUM(amount), 0) as total FROM expenses WHERE user_id = ?',
[userId]
);
// ดึงข้อมูลค่าใช้จ่ายแยกตามหมวดหมู่
const [expenseSummary] = await db.query(
`SELECT
c.name as category_name,
COALESCE(SUM(e.amount), 0) as total_amount,
COUNT(*) as transaction_count
FROM expenses e
JOIN categories c ON e.category_id = c.id
WHERE e.user_id = ?
GROUP BY c.id, c.name
ORDER BY total_amount DESC`,
[userId]
);
// ดึงข้อมูลค่าใช้จ่ายรายเดือน
const [monthlyExpenses] = await db.query(
`SELECT
DATE_FORMAT(date, '%Y-%m') as month,
COALESCE(SUM(amount), 0) as monthly_total,
COUNT(*) as transaction_count
FROM expenses
WHERE user_id = ?
GROUP BY DATE_FORMAT(date, '%Y-%m')
ORDER BY month DESC
LIMIT 12`,
[userId]
);
const totalExpenses = totalResult[0].total || 0;
res.render('layout', {
content: 'profile', // Ensure this matches the profile.ejs file
user: users[0],
totalExpenses: totalExpenses,
expenseSummary: expenseSummary,
monthlyExpenses: monthlyExpenses
});
} catch (error) {
console.error('Profile controller error:', error);
res.status(500).render('layout', {
content: 'error',
error: 'เกิดข้อผิดพลาดในการโหลดข้อมูลโปรไฟล์'
});
}
}
};
module.exports = profileController;
db.js 0 → 100644
const mysql = require('mysql2');
require('dotenv').config();
const pool = mysql.createPool({
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASS,
database: process.env.DB_NAME,
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
}).promise();
module.exports = pool;
main.js 0 → 100644
const express = require('express');
const session = require('express-session');
const bodyParser = require('body-parser');
const methodOverride = require('method-override');
const path = require('path');
// Import routes
const authRoutes = require('./routes/auth');
const expenseRoutes = require('./routes/expenses');
const budgetRoutes = require('./routes/budget');
const dashboardRoutes = require('./routes/dashboard');
const profileRouter = require('./routes/profile');
const authMiddleware = require('./middleware/authMiddleware');
require('dotenv').config();
const app = express();
// Middleware setup
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
app.use(express.static(path.join(__dirname, 'public')));
app.use('/css', express.static(path.join(__dirname, 'public/css')));
app.use(bodyParser.urlencoded({ extended: false }));
app.use(methodOverride('_method'));
// Session setup
app.use(session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: true
}));
// Make session and user data available to all templates
app.use((req, res, next) => {
res.locals.session = req.session;
res.locals.user = req.session.user || null;
next();
});
// Protected routes
app.use('/dashboard', authMiddleware.ensureAuthenticated, dashboardRoutes);
app.use('/budget', authMiddleware.ensureAuthenticated, budgetRoutes);
app.use('/profile', authMiddleware.ensureAuthenticated, profileRouter);
// Public routes
app.use(authRoutes);
app.use(expenseRoutes);
app.get('/login', (req, res) => {
res.render('layout', { content: 'login', error: req.query.error });
});
app.get('/register', (req, res) => {
res.render('layout', { content: 'register', error: req.query.error || '' });
});
app.get('/', (req, res) => {
res.render('index', { content: '' });
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});
\ No newline at end of file
module.exports = {
ensureAuthenticated: (req, res, next) => {
if (req.session.user) {
return next();
} else {
res.redirect('/login');
}
},
ensureGuest: (req, res, next) => {
if (!req.session.user) {
return next();
} else {
res.redirect('/dashboard');
}
}
};
\ No newline at end of file
const db = require('../db');
async function getBudgetByUser(userId) {
const [budget] = await db.query("SELECT * FROM budgets WHERE user_id = ?", [userId]);
return budget.length > 0 ? budget[0] : null;
}
async function setBudget(userId, amount, month) {
return db.query("INSERT INTO budgets (user_id, amount, month) VALUES (?, ?, ?)", [userId, amount, month]);
}
module.exports = { getBudgetByUser, setBudget };
const db = require('../db');
async function getAllExpenses(userId) {
const [rows] = await db.query(
"SELECT expenses.*, categories.name AS category FROM expenses JOIN categories ON expenses.category_id = categories.id WHERE user_id = ?",
[userId]
);
return rows.map(expense => ({
...expense,
rawDate: expense.date, // Keep original date format for editing
date: new Date(expense.date).toLocaleDateString('th-TH', {
year: 'numeric',
month: 'long',
day: 'numeric'
})
}));
}
async function addExpense(userId, categoryId, amount, description, date) {
await db.query("INSERT INTO expenses (user_id, category_id, amount, description, date) VALUES (?, ?, ?, ?, ?)",
[userId, categoryId, amount, description, date]);
}
async function deleteExpense(expenseId) {
await db.query("DELETE FROM expenses WHERE id = ?", [expenseId]);
}
async function updateExpense(expenseId, categoryId, amount, description, date) {
await db.query(
"UPDATE expenses SET category_id = ?, amount = ?, description = ?, date = ? WHERE id = ?",
[categoryId, amount, description, date, expenseId]
);
}
async function getCategories() {
const [rows] = await db.query("SELECT * FROM categories");
return rows;
}
async function addCategory(name) {
const query = 'INSERT INTO categories (name) VALUES ($1)';
await pool.query(query, [name]);
}
module.exports = {
getAllExpenses,
addExpense,
deleteExpense,
getCategories,
addCategory,
updateExpense
};
const db = require('../db');
async function createUser(username, password) {
return db.query("INSERT INTO users (username, password) VALUES (?, ?)", [username, password]);
}
async function findUserByUsername(username) {
const [users] = await db.query("SELECT * FROM users WHERE username = ?", [username]);
return users.length > 0 ? users[0] : null;
}
module.exports = { createUser, findUserByUsername };
\ No newline at end of file
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../autoprefixer/bin/autoprefixer" "$@"
else
exec node "$basedir/../autoprefixer/bin/autoprefixer" "$@"
fi
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\autoprefixer\bin\autoprefixer" %*
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../autoprefixer/bin/autoprefixer" $args
} else {
& "$basedir/node$exe" "$basedir/../autoprefixer/bin/autoprefixer" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../autoprefixer/bin/autoprefixer" $args
} else {
& "node$exe" "$basedir/../autoprefixer/bin/autoprefixer" $args
}
$ret=$LASTEXITCODE
}
exit $ret
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../bcryptjs/bin/bcrypt" "$@"
else
exec node "$basedir/../bcryptjs/bin/bcrypt" "$@"
fi
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\bcryptjs\bin\bcrypt" %*
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../bcryptjs/bin/bcrypt" $args
} else {
& "$basedir/node$exe" "$basedir/../bcryptjs/bin/bcrypt" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../bcryptjs/bin/bcrypt" $args
} else {
& "node$exe" "$basedir/../bcryptjs/bin/bcrypt" $args
}
$ret=$LASTEXITCODE
}
exit $ret
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../browserslist/cli.js" "$@"
else
exec node "$basedir/../browserslist/cli.js" "$@"
fi
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\browserslist\cli.js" %*
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment