Gitlab@Informatics

Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision

Target

Select target project
  • 65160381/project-melon
1 result
Select Git revision
Show changes
Commits on Source (2)
Showing
with 494 additions and 24 deletions
...@@ -27,6 +27,7 @@ const registerController = require('./controllers/registerController'); ...@@ -27,6 +27,7 @@ const registerController = require('./controllers/registerController');
const logoutController = require('./controllers/logoutController'); const logoutController = require('./controllers/logoutController');
const productController = require('./controllers/productController'); const productController = require('./controllers/productController');
const cartController = require('./controllers/cartController'); const cartController = require('./controllers/cartController');
const reviewController = require('./controllers/reviewController');
app.get('/', indexController.getProducts); app.get('/', indexController.getProducts);
app.get('/login', loginController.showLoginPage); app.get('/login', loginController.showLoginPage);
...@@ -35,7 +36,7 @@ app.get('/register', registerController.showRegisterPage); ...@@ -35,7 +36,7 @@ app.get('/register', registerController.showRegisterPage);
app.post('/user/register', registerController.registerUser); app.post('/user/register', registerController.registerUser);
app.post('/user/register', registerController.registerUser); app.post('/user/register', registerController.registerUser);
app.get('/logout', logoutController); app.get('/logout', logoutController);
app.get('/product/:id', indexController.getProductDetail); app.get('/product/:id', productController.showProductDetails);
app.get('/addProduct', productController.showAddProductForm); app.get('/addProduct', productController.showAddProductForm);
app.post('/addProduct', productController.createProduct); app.post('/addProduct', productController.createProduct);
app.post('/delete_product/:id', productController.deleteProduct); app.post('/delete_product/:id', productController.deleteProduct);
...@@ -50,6 +51,11 @@ app.get('/orderConfirmation', (req,res) => { ...@@ -50,6 +51,11 @@ app.get('/orderConfirmation', (req,res) => {
res.render('orderConfirmation'); res.render('orderConfirmation');
}); });
app.get('/orderHistory', productController.orderHistory); app.get('/orderHistory', productController.orderHistory);
app.get('/product/:id/reviews', reviewController.showReviews);
app.post('/product/:id/reviews/add', reviewController.addReview);
app.post('/product/:id/reviews/:reviewId/delete', reviewController.deleteReview);
app.get('/product/:id/reviews/:reviewId/edit', reviewController.editReviewForm);
app.post('/product/:id/reviews/:reviewId/update', reviewController.updateReview);
const port = process.env.PORT || 3000; const port = process.env.PORT || 3000;
app.listen(port, () => { app.listen(port, () => {
......
...@@ -77,7 +77,10 @@ exports.checkout = async (req, res) => { ...@@ -77,7 +77,10 @@ exports.checkout = async (req, res) => {
const userId = user[0].id; const userId = user[0].id;
// สร้างคำสั่งซื้อใน Orders // สร้างคำสั่งซื้อใน Orders
const [orderResult] = await pool.query('INSERT INTO orders (user_id, total_amount) VALUES (?, ?)', [userId, totalAmount]); const [orderResult] = await pool.query(
'INSERT INTO orders (owner, total_amount) VALUES (?, ?)',
[userId, totalAmount]
);
const orderId = orderResult.insertId; const orderId = orderResult.insertId;
// เพิ่มรายการสินค้าลงใน Order_Items // เพิ่มรายการสินค้าลงใน Order_Items
......
...@@ -6,15 +6,27 @@ exports.showAddProductForm = (req, res) => { ...@@ -6,15 +6,27 @@ exports.showAddProductForm = (req, res) => {
exports.createProduct = async (req, res) => { exports.createProduct = async (req, res) => {
const { product_name, price, image, description } = req.body; const { product_name, price, image, description } = req.body;
const owner = req.session.userIdEmail; // เราต้องเก็บ email ตอน login ด้วยนะครับ const userEmail = req.session.userIdEmail;
try { try {
const sql = 'INSERT INTO products (product_name, price, image, description, owner) VALUES (?, ?, ?, ?, ?)'; // ดึง user ID โดยใช้ email ที่เก็บไว้ใน session
await pool.query(sql, [product_name, price, image, description, owner]); const [userRows] = await pool.query('SELECT id FROM users WHERE email = ?', [userEmail]);
res.redirect('/');
if (userRows.length === 0) {
return res.status(400).send('ไม่พบข้อมูลผู้ใช้งาน');
}
const ownerId = userRows[0].id;
// insert ข้อมูลสินค้า โดยใช้ ID ของผู้ใช้งาน
const sql = 'INSERT INTO products (product_name, price, image, description, owner) VALUES (?, ?, ?, ?, ?)';
await pool.query(sql, [product_name, price, image, description, ownerId]);
res.redirect('/');
} catch (err) { } catch (err) {
res.status(500).send('เกิดข้อผิดพลาดในการเพิ่มสินค้า: ' + err.message); res.status(500).send('เกิดข้อผิดพลาดในการเพิ่มสินค้า: ' + err.message);
} }
}; };
exports.showUpdateProductForm = async (req, res) => { exports.showUpdateProductForm = async (req, res) => {
...@@ -30,53 +42,73 @@ exports.showUpdateProductForm = async (req, res) => { ...@@ -30,53 +42,73 @@ exports.showUpdateProductForm = async (req, res) => {
} }
}; };
exports.updateProduct = async (req, res) => { exports.updateProduct = async (req, res) => {
const productId = req.params.id; const productId = req.params.id;
const { product_name, price, image, description } = req.body; const { product_name, price, image, description } = req.body;
const currentUserEmail = req.session.userIdEmail; const currentUserEmail = req.session.userIdEmail;
try { try {
const [rows] = await pool.query('SELECT * FROM products WHERE product_id = ?', [productId]); // ดึงข้อมูลสินค้าพร้อมอีเมลของเจ้าของสินค้า
const [rows] = await pool.query(`
SELECT p.*, u.email as owner_email
FROM products p
JOIN users u ON p.owner = u.id
WHERE p.product_id = ?`, [productId]);
if (rows.length === 0) { if (rows.length === 0) {
return res.status(404).send('ไม่พบสินค้านี้'); return res.status(404).send('ไม่พบสินค้านี้');
} }
const product = rows[0]; const product = rows[0];
if (product.owner !== currentUserEmail) {
// เปรียบเทียบด้วย email ที่ถูกต้อง
if (product.owner_email !== currentUserEmail) {
return res.status(403).send('คุณไม่มีสิทธิ์แก้ไขสินค้านี้'); return res.status(403).send('คุณไม่มีสิทธิ์แก้ไขสินค้านี้');
} }
// ถ้ามีสิทธิ์ก็อัปเดตข้อมูลได้
const sql = 'UPDATE products SET product_name = ?, price = ?, image = ?, description = ? WHERE product_id = ?'; const sql = 'UPDATE products SET product_name = ?, price = ?, image = ?, description = ? WHERE product_id = ?';
await pool.query(sql, [product_name, price, image, description, productId]); await pool.query(sql, [product_name, price, image, description, productId]);
res.redirect('/'); res.redirect('/');
} catch (err) { } catch (err) {
res.status(500).send('เกิดข้อผิดพลาดในการอัปเดตสินค้า: ' + err.message); res.status(500).send('เกิดข้อผิดพลาดในการอัปเดตสินค้า: ' + err.message);
} }
}; };
exports.deleteProduct = async (req, res) => { exports.deleteProduct = async (req, res) => {
const productId = req.params.id; const productId = req.params.id;
const currentUserEmail = req.session.userIdEmail; const currentUserEmail = req.session.userIdEmail;
try { try {
// ตรวจสอบว่าผู้ใช้นี้เป็นเจ้าของหรือไม่ // ดึงข้อมูลสินค้าพร้อมอีเมลเจ้าของสินค้า
const [rows] = await pool.query('SELECT * FROM products WHERE product_id = ?', [productId]); const [rows] = await pool.query(`
SELECT p.*, u.email as owner_email
FROM products p
JOIN users u ON p.owner = u.id
WHERE p.product_id = ?`, [productId]);
if (rows.length === 0) { if (rows.length === 0) {
return res.status(404).send('ไม่พบสินค้านี้'); return res.status(404).send('ไม่พบสินค้านี้');
} }
const product = rows[0]; const product = rows[0];
if (product.owner !== currentUserEmail) {
// ตรวจสอบสิทธิ์ด้วยอีเมล
if (product.owner_email !== currentUserEmail) {
return res.status(403).send('คุณไม่มีสิทธิ์ลบสินค้านี้'); return res.status(403).send('คุณไม่มีสิทธิ์ลบสินค้านี้');
} }
// ลบสินค้าได้ // ถ้าผ่านเงื่อนไข ก็สามารถลบสินค้าได้
await pool.query('DELETE FROM products WHERE product_id = ?', [productId]); await pool.query('DELETE FROM products WHERE product_id = ?', [productId]);
res.redirect('/'); res.redirect('/');
} catch (err) { } catch (err) {
res.status(500).send('Database error: ' + err.message); res.status(500).send('Database error: ' + err.message);
} }
}; };
exports.searchProducts = async (req, res) => {
exports.searchProducts = async (req, res) => {
const searchQuery = req.query.q; // รับค่าค้นหาจาก query parameter const searchQuery = req.query.q; // รับค่าค้นหาจาก query parameter
try { try {
const sql = 'SELECT * FROM products WHERE product_name LIKE ?'; const sql = 'SELECT * FROM products WHERE product_name LIKE ?';
...@@ -88,6 +120,35 @@ exports.showUpdateProductForm = async (req, res) => { ...@@ -88,6 +120,35 @@ exports.showUpdateProductForm = async (req, res) => {
} }
}; };
exports.showProductDetails = async (req, res) => {
const productId = req.params.id;
try {
const [rows] = await pool.query(`
SELECT p.*, u.email as owner_email
FROM products p
JOIN users u ON p.owner = u.id
WHERE p.product_id = ?`, [productId]);
if (rows.length === 0) {
return res.status(404).send('ไม่พบสินค้านี้');
}
const product = rows[0];
res.render('product', {
product,
currentUserEmail: req.session.userIdEmail
});
} catch (err) {
res.status(500).send('เกิดข้อผิดพลาด: ' + err.message);
}
};
exports.orderHistory = async (req, res) => { exports.orderHistory = async (req, res) => {
if (!req.session.userIdEmail) { if (!req.session.userIdEmail) {
return res.status(401).send('กรุณาเข้าสู่ระบบเพื่อดูประวัติการสั่งซื้อ'); return res.status(401).send('กรุณาเข้าสู่ระบบเพื่อดูประวัติการสั่งซื้อ');
...@@ -103,9 +164,9 @@ exports.orderHistory = async (req, res) => { ...@@ -103,9 +164,9 @@ exports.orderHistory = async (req, res) => {
} }
const userId = user[0].id; const userId = user[0].id;
// ดึงคำสั่งซื้อทั้งหมดของผู้ใช้ // ตรงนี้เปลี่ยนจาก user_id เป็น owner
const [orders] = await pool.query( const [orders] = await pool.query(
'SELECT * FROM orders WHERE user_id = ? ORDER BY created_at DESC', 'SELECT * FROM orders WHERE owner = ? ORDER BY created_at DESC',
[userId] [userId]
); );
......
const pool = require('../db');
exports.showReviews = async (req, res) => {
const productId = req.params.id;
const currentUserEmail = req.session.userIdEmail;
try {
const [product] = await pool.query('SELECT * FROM products WHERE product_id = ?', [productId]);
const [reviews] = await pool.query(`
SELECT r.*, u.email
FROM reviwe r
JOIN users u ON r.owner = u.id
WHERE r.product_id = ?`, [productId]);
res.render('reviews', { product: product[0], reviews, currentUserEmail });
} catch (err) {
res.status(500).send('เกิดข้อผิดพลาด: ' + err.message);
}
};
exports.addReview = async (req, res) => {
const productId = req.params.id;
const { content } = req.body;
const userEmail = req.session.userIdEmail;
try {
const [user] = await pool.query('SELECT id FROM users WHERE email = ?', [userEmail]);
// ตรวจสอบว่าพบผู้ใช้หรือไม่
if (!user || user.length === 0 || !user[0]) {
return res.status(404).send('ไม่พบผู้ใช้งาน');
}
await pool.query('INSERT INTO reviwe (product_id, owner, content) VALUES (?, ?, ?)', [productId, user[0].id, content]);
res.redirect(`/product/${productId}/reviews`);
} catch (err) {
res.status(500).send('เกิดข้อผิดพลาด: ' + err.message);
}
};
exports.deleteReview = async (req, res) => {
const { id, reviewId } = req.params;
const userEmail = req.session.userIdEmail;
try {
const [user] = await pool.query('SELECT id FROM users WHERE email = ?', [userEmail]);
// ตรวจสอบว่าพบผู้ใช้หรือไม่
if (!user || user.length === 0 || !user[0]) {
return res.status(404).send('ไม่พบผู้ใช้งาน');
}
await pool.query('DELETE FROM reviwe WHERE reviwe_id = ? AND owner = ?', [reviewId, user[0].id]);
res.redirect(`/product/${id}/reviews`);
} catch (err) {
res.status(500).send('เกิดข้อผิดพลาด: ' + err.message);
}
};
exports.editReviewForm = async (req, res) => {
const { id, reviewId } = req.params;
try {
const [reviews] = await pool.query('SELECT * FROM reviwe WHERE reviwe_id = ?', [reviewId]);
if (!reviews || reviews.length === 0) {
return res.status(404).send('ไม่พบรีวิวนี้');
}
res.render('editReview', { product_id: id, review: reviews[0] });
} catch (err) {
res.status(500).send('เกิดข้อผิดพลาด: ' + err.message);
}
};
exports.updateReview = async (req, res) => {
const { id, reviewId } = req.params;
const { content } = req.body;
const userEmail = req.session.userIdEmail;
try {
const [user] = await pool.query('SELECT id FROM users WHERE email = ?', [userEmail]);
// ตรวจสอบว่าพบผู้ใช้หรือไม่
if (!user || user.length === 0 || !user[0]) {
return res.status(404).send('ไม่พบผู้ใช้งาน');
}
await pool.query('UPDATE reviwe SET content = ? WHERE reviwe_id = ? AND owner = ?', [content, reviewId, user[0].id]);
res.redirect(`/product/${id}/reviews`);
} catch (err) {
res.status(500).send('เกิดข้อผิดพลาด: ' + err.message);
}
};
const mysql = require('mysql2/promise'); const mysql = require('mysql2/promise');
const pool = mysql.createPool({ const pool = mysql.createPool({
host: process.env.DB_HOST || "10.104.20.74", host: process.env.DB_HOST || "127.0.0.1",
port: process.env.DB_PORT || "3306", port: process.env.DB_PORT || "3306",
user: process.env.DB_USER || "root", user: process.env.DB_USER || "root",
password: process.env.DB_PASSWORD || "TNSypb73606", password: process.env.DB_PASSWORD || "",
database: process.env.DB_NAME || "project", database: process.env.DB_NAME || "project",
waitForConnections: true, waitForConnections: true,
connectionLimit: 10, connectionLimit: 10,
......
#!/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/../color-support/bin.js" "$@"
else
exec node "$basedir/../color-support/bin.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%\..\color-support\bin.js" %*
#!/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/../color-support/bin.js" $args
} else {
& "$basedir/node$exe" "$basedir/../color-support/bin.js" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../color-support/bin.js" $args
} else {
& "node$exe" "$basedir/../color-support/bin.js" $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/../ejs/bin/cli.js" "$@"
else
exec node "$basedir/../ejs/bin/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%\..\ejs\bin\cli.js" %*
#!/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/../ejs/bin/cli.js" $args
} else {
& "$basedir/node$exe" "$basedir/../ejs/bin/cli.js" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../ejs/bin/cli.js" $args
} else {
& "node$exe" "$basedir/../ejs/bin/cli.js" $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/../jake/bin/cli.js" "$@"
else
exec node "$basedir/../jake/bin/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%\..\jake\bin\cli.js" %*
#!/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/../jake/bin/cli.js" $args
} else {
& "$basedir/node$exe" "$basedir/../jake/bin/cli.js" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../jake/bin/cli.js" $args
} else {
& "node$exe" "$basedir/../jake/bin/cli.js" $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/../mime/cli.js" "$@"
else
exec node "$basedir/../mime/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%\..\mime\cli.js" %*
#!/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/../mime/cli.js" $args
} else {
& "$basedir/node$exe" "$basedir/../mime/cli.js" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../mime/cli.js" $args
} else {
& "node$exe" "$basedir/../mime/cli.js" $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/../mkdirp/bin/cmd.js" "$@"
else
exec node "$basedir/../mkdirp/bin/cmd.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%\..\mkdirp\bin\cmd.js" %*
#!/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/../mkdirp/bin/cmd.js" $args
} else {
& "$basedir/node$exe" "$basedir/../mkdirp/bin/cmd.js" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../mkdirp/bin/cmd.js" $args
} else {
& "node$exe" "$basedir/../mkdirp/bin/cmd.js" $args
}
$ret=$LASTEXITCODE
}
exit $ret