新增 App 建立、資料呈現
This commit is contained in:
49
scripts/check-apps-count.js
Normal file
49
scripts/check-apps-count.js
Normal file
@@ -0,0 +1,49 @@
|
||||
const mysql = require('mysql2/promise');
|
||||
|
||||
async function checkAppsCount() {
|
||||
try {
|
||||
// 連接資料庫
|
||||
const connection = await mysql.createConnection({
|
||||
host: 'mysql.theaken.com',
|
||||
port: 33306,
|
||||
user: 'AI_Platform',
|
||||
password: 'Aa123456',
|
||||
database: 'db_AI_Platform'
|
||||
});
|
||||
|
||||
console.log('=== 檢查應用程式數量 ===');
|
||||
|
||||
// 檢查總數
|
||||
const [totalRows] = await connection.execute('SELECT COUNT(*) as total FROM apps');
|
||||
console.log('總應用程式數量:', totalRows[0].total);
|
||||
|
||||
// 檢查各狀態的數量
|
||||
const [statusRows] = await connection.execute(`
|
||||
SELECT status, COUNT(*) as count
|
||||
FROM apps
|
||||
GROUP BY status
|
||||
`);
|
||||
console.log('各狀態數量:');
|
||||
statusRows.forEach(row => {
|
||||
console.log(` ${row.status}: ${row.count}`);
|
||||
});
|
||||
|
||||
// 檢查最近的應用程式
|
||||
const [recentRows] = await connection.execute(`
|
||||
SELECT id, name, status, created_at
|
||||
FROM apps
|
||||
ORDER BY created_at DESC
|
||||
LIMIT 5
|
||||
`);
|
||||
console.log('最近的應用程式:');
|
||||
recentRows.forEach(row => {
|
||||
console.log(` ${row.name} (${row.status}) - ${row.created_at}`);
|
||||
});
|
||||
|
||||
await connection.end();
|
||||
} catch (error) {
|
||||
console.error('檢查失敗:', error);
|
||||
}
|
||||
}
|
||||
|
||||
checkAppsCount();
|
44
scripts/check-apps-table.js
Normal file
44
scripts/check-apps-table.js
Normal file
@@ -0,0 +1,44 @@
|
||||
const mysql = require('mysql2/promise');
|
||||
|
||||
async function checkAppsTable() {
|
||||
const connection = await mysql.createConnection({
|
||||
host: process.env.DB_HOST || 'localhost',
|
||||
user: process.env.DB_USER || 'root',
|
||||
password: process.env.DB_PASSWORD || '',
|
||||
database: process.env.DB_NAME || 'ai_showcase_platform'
|
||||
});
|
||||
|
||||
try {
|
||||
console.log('檢查 apps 表格結構...');
|
||||
|
||||
// 檢查表格結構
|
||||
const [columns] = await connection.execute('DESCRIBE apps');
|
||||
console.log('\napps 表格欄位:');
|
||||
columns.forEach(col => {
|
||||
console.log(`- ${col.Field}: ${col.Type} ${col.Null === 'NO' ? 'NOT NULL' : 'NULL'} ${col.Default ? `DEFAULT ${col.Default}` : ''}`);
|
||||
});
|
||||
|
||||
// 檢查是否有資料
|
||||
const [rows] = await connection.execute('SELECT COUNT(*) as count FROM apps');
|
||||
console.log(`\napps 表格資料筆數: ${rows[0].count}`);
|
||||
|
||||
if (rows[0].count > 0) {
|
||||
// 顯示前幾筆資料
|
||||
const [sampleData] = await connection.execute('SELECT * FROM apps LIMIT 3');
|
||||
console.log('\n前 3 筆資料:');
|
||||
sampleData.forEach((row, index) => {
|
||||
console.log(`\n第 ${index + 1} 筆:`);
|
||||
Object.keys(row).forEach(key => {
|
||||
console.log(` ${key}: ${row[key]}`);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('檢查失敗:', error);
|
||||
} finally {
|
||||
await connection.end();
|
||||
}
|
||||
}
|
||||
|
||||
checkAppsTable();
|
53
scripts/check-database.js
Normal file
53
scripts/check-database.js
Normal file
@@ -0,0 +1,53 @@
|
||||
const mysql = require('mysql2/promise');
|
||||
|
||||
const dbConfig = {
|
||||
host: process.env.DB_HOST || 'mysql.theaken.com',
|
||||
port: parseInt(process.env.DB_PORT || '33306'),
|
||||
user: process.env.DB_USER || 'AI_Platform',
|
||||
password: process.env.DB_PASSWORD || 'Aa123456',
|
||||
database: process.env.DB_NAME || 'db_AI_Platform',
|
||||
charset: 'utf8mb4',
|
||||
timezone: '+08:00'
|
||||
};
|
||||
|
||||
async function checkDatabase() {
|
||||
let connection;
|
||||
|
||||
try {
|
||||
console.log('🔍 檢查資料庫表結構...');
|
||||
|
||||
connection = await mysql.createConnection(dbConfig);
|
||||
console.log('✅ 資料庫連接成功');
|
||||
|
||||
// 檢查 apps 表結構
|
||||
console.log('\n📋 Apps 表結構:');
|
||||
const [appsStructure] = await connection.execute('DESCRIBE apps');
|
||||
console.table(appsStructure);
|
||||
|
||||
// 檢查 apps 表資料
|
||||
console.log('\n📊 Apps 表資料:');
|
||||
const [appsData] = await connection.execute('SELECT id, name, type, status, creator_id FROM apps LIMIT 5');
|
||||
console.table(appsData);
|
||||
|
||||
// 檢查 users 表結構
|
||||
console.log('\n👥 Users 表結構:');
|
||||
const [usersStructure] = await connection.execute('DESCRIBE users');
|
||||
console.table(usersStructure);
|
||||
|
||||
// 檢查是否有開發者或管理員用戶
|
||||
console.log('\n🔑 檢查開發者/管理員用戶:');
|
||||
const [adminUsers] = await connection.execute('SELECT id, name, email, role FROM users WHERE role IN ("developer", "admin")');
|
||||
console.table(adminUsers);
|
||||
|
||||
console.log('\n✅ 資料庫檢查完成');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 檢查失敗:', error);
|
||||
} finally {
|
||||
if (connection) {
|
||||
await connection.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checkDatabase();
|
61
scripts/check-teams-table.js
Normal file
61
scripts/check-teams-table.js
Normal file
@@ -0,0 +1,61 @@
|
||||
const mysql = require('mysql2/promise');
|
||||
|
||||
const dbConfig = {
|
||||
host: process.env.DB_HOST || 'mysql.theaken.com',
|
||||
port: parseInt(process.env.DB_PORT || '33306'),
|
||||
user: process.env.DB_USER || 'AI_Platform',
|
||||
password: process.env.DB_PASSWORD || 'Aa123456',
|
||||
database: process.env.DB_NAME || 'db_AI_Platform',
|
||||
charset: 'utf8mb4',
|
||||
timezone: '+08:00'
|
||||
};
|
||||
|
||||
async function checkTeamsTable() {
|
||||
let connection;
|
||||
|
||||
try {
|
||||
console.log('🔍 檢查 teams 表...');
|
||||
|
||||
connection = await mysql.createConnection(dbConfig);
|
||||
console.log('✅ 資料庫連接成功');
|
||||
|
||||
// 檢查所有表
|
||||
console.log('\n📋 所有表:');
|
||||
const [tables] = await connection.execute('SHOW TABLES');
|
||||
console.table(tables);
|
||||
|
||||
// 檢查 teams 表是否存在
|
||||
console.log('\n🔍 檢查 teams 表是否存在...');
|
||||
const [teamsTable] = await connection.execute("SHOW TABLES LIKE 'teams'");
|
||||
|
||||
if (teamsTable.length > 0) {
|
||||
console.log('✅ teams 表存在');
|
||||
|
||||
// 檢查 teams 表結構
|
||||
console.log('\n📋 Teams 表結構:');
|
||||
const [teamsStructure] = await connection.execute('DESCRIBE teams');
|
||||
console.table(teamsStructure);
|
||||
|
||||
// 檢查 teams 表資料
|
||||
console.log('\n📊 Teams 表資料:');
|
||||
const [teamsData] = await connection.execute('SELECT * FROM teams LIMIT 5');
|
||||
console.table(teamsData);
|
||||
} else {
|
||||
console.log('❌ teams 表不存在');
|
||||
}
|
||||
|
||||
// 測試簡單的 apps 查詢
|
||||
console.log('\n🧪 測試簡單的 apps 查詢...');
|
||||
const [appsData] = await connection.execute('SELECT id, name, type, status, creator_id FROM apps LIMIT 5');
|
||||
console.table(appsData);
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 檢查失敗:', error);
|
||||
} finally {
|
||||
if (connection) {
|
||||
await connection.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checkTeamsTable();
|
52
scripts/check-user-passwords.js
Normal file
52
scripts/check-user-passwords.js
Normal file
@@ -0,0 +1,52 @@
|
||||
const mysql = require('mysql2/promise');
|
||||
const bcrypt = require('bcrypt');
|
||||
|
||||
const dbConfig = {
|
||||
host: process.env.DB_HOST || 'mysql.theaken.com',
|
||||
port: parseInt(process.env.DB_PORT || '33306'),
|
||||
user: process.env.DB_USER || 'AI_Platform',
|
||||
password: process.env.DB_PASSWORD || 'Aa123456',
|
||||
database: process.env.DB_NAME || 'db_AI_Platform',
|
||||
charset: 'utf8mb4',
|
||||
timezone: '+08:00'
|
||||
};
|
||||
|
||||
async function checkUserPasswords() {
|
||||
let connection;
|
||||
|
||||
try {
|
||||
console.log('🔍 檢查用戶密碼...');
|
||||
|
||||
connection = await mysql.createConnection(dbConfig);
|
||||
console.log('✅ 資料庫連接成功');
|
||||
|
||||
// 檢查用戶密碼哈希
|
||||
console.log('\n📊 用戶密碼哈希:');
|
||||
const [users] = await connection.execute('SELECT id, name, email, password_hash FROM users');
|
||||
|
||||
for (const user of users) {
|
||||
console.log(`\n用戶: ${user.name} (${user.email})`);
|
||||
console.log(`密碼哈希: ${user.password_hash}`);
|
||||
|
||||
// 測試一些常見密碼
|
||||
const testPasswords = ['Admin123', 'admin123', 'password', '123456', 'admin'];
|
||||
|
||||
for (const password of testPasswords) {
|
||||
const isValid = await bcrypt.compare(password, user.password_hash);
|
||||
if (isValid) {
|
||||
console.log(`✅ 找到正確密碼: ${password}`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 檢查失敗:', error);
|
||||
} finally {
|
||||
if (connection) {
|
||||
await connection.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checkUserPasswords();
|
65
scripts/check-users.js
Normal file
65
scripts/check-users.js
Normal file
@@ -0,0 +1,65 @@
|
||||
const mysql = require('mysql2/promise');
|
||||
const jwt = require('jsonwebtoken');
|
||||
|
||||
const JWT_SECRET = process.env.JWT_SECRET || 'good777';
|
||||
|
||||
async function checkUsers() {
|
||||
try {
|
||||
// 連接資料庫
|
||||
const connection = await mysql.createConnection({
|
||||
host: 'mysql.theaken.com',
|
||||
port: 33306,
|
||||
user: 'AI_Platform',
|
||||
password: 'Aa123456',
|
||||
database: 'db_AI_Platform'
|
||||
});
|
||||
|
||||
console.log('=== 檢查用戶 ===');
|
||||
|
||||
// 檢查用戶
|
||||
const [userRows] = await connection.execute('SELECT id, email, name, role FROM users LIMIT 5');
|
||||
console.log('用戶列表:');
|
||||
userRows.forEach(user => {
|
||||
console.log(` ID: ${user.id}, Email: ${user.email}, Name: ${user.name}, Role: ${user.role}`);
|
||||
});
|
||||
|
||||
// 為第一個用戶生成 token
|
||||
if (userRows.length > 0) {
|
||||
const user = userRows[0];
|
||||
const token = jwt.sign({
|
||||
userId: user.id,
|
||||
email: user.email,
|
||||
role: user.role
|
||||
}, JWT_SECRET, { expiresIn: '1h' });
|
||||
|
||||
console.log('\n生成的 Token:');
|
||||
console.log(token);
|
||||
|
||||
// 測試 API
|
||||
console.log('\n=== 測試 API ===');
|
||||
const response = await fetch('http://localhost:3000/api/apps?page=1&limit=10', {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`
|
||||
}
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
console.log('✅ API 回應成功');
|
||||
console.log('分頁資訊:', data.pagination);
|
||||
console.log('統計資訊:', data.stats);
|
||||
console.log(`應用程式數量: ${data.apps?.length || 0}`);
|
||||
} else {
|
||||
console.log('❌ API 回應失敗:', response.status, response.statusText);
|
||||
const errorText = await response.text();
|
||||
console.log('錯誤詳情:', errorText);
|
||||
}
|
||||
}
|
||||
|
||||
await connection.end();
|
||||
} catch (error) {
|
||||
console.error('檢查失敗:', error);
|
||||
}
|
||||
}
|
||||
|
||||
checkUsers();
|
93
scripts/create-admin-user.js
Normal file
93
scripts/create-admin-user.js
Normal file
@@ -0,0 +1,93 @@
|
||||
const mysql = require('mysql2/promise');
|
||||
const bcrypt = require('bcrypt');
|
||||
|
||||
const dbConfig = {
|
||||
host: process.env.DB_HOST || 'mysql.theaken.com',
|
||||
port: parseInt(process.env.DB_PORT || '33306'),
|
||||
user: process.env.DB_USER || 'AI_Platform',
|
||||
password: process.env.DB_PASSWORD || 'Aa123456',
|
||||
database: process.env.DB_NAME || 'db_AI_Platform',
|
||||
charset: 'utf8mb4',
|
||||
timezone: '+08:00'
|
||||
};
|
||||
|
||||
async function createAdminUser() {
|
||||
let connection;
|
||||
try {
|
||||
console.log('🧪 創建管理員用戶...');
|
||||
connection = await mysql.createConnection(dbConfig);
|
||||
console.log('✅ 資料庫連接成功');
|
||||
|
||||
// 創建管理員用戶
|
||||
const adminUserData = {
|
||||
id: 'admin-' + Date.now(),
|
||||
name: '系統管理員',
|
||||
email: 'admin@example.com',
|
||||
password: 'Admin123!',
|
||||
department: 'ITBU',
|
||||
role: 'admin',
|
||||
join_date: new Date(),
|
||||
created_at: new Date(),
|
||||
updated_at: new Date()
|
||||
};
|
||||
|
||||
// 加密密碼
|
||||
const passwordHash = await bcrypt.hash(adminUserData.password, 12);
|
||||
|
||||
// 檢查用戶是否已存在
|
||||
const [existingUser] = await connection.execute(
|
||||
'SELECT id FROM users WHERE email = ?',
|
||||
[adminUserData.email]
|
||||
);
|
||||
|
||||
if (existingUser.length > 0) {
|
||||
console.log('⚠️ 管理員用戶已存在,更新密碼...');
|
||||
await connection.execute(
|
||||
'UPDATE users SET password_hash = ?, updated_at = NOW() WHERE email = ?',
|
||||
[passwordHash, adminUserData.email]
|
||||
);
|
||||
} else {
|
||||
console.log('✅ 創建新的管理員用戶...');
|
||||
await connection.execute(
|
||||
'INSERT INTO users (id, name, email, password_hash, department, role, join_date, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)',
|
||||
[adminUserData.id, adminUserData.name, adminUserData.email, passwordHash, adminUserData.department, adminUserData.role, adminUserData.join_date, adminUserData.created_at, adminUserData.updated_at]
|
||||
);
|
||||
}
|
||||
|
||||
console.log('\n✅ 管理員用戶創建/更新成功!');
|
||||
console.log('📋 登入資訊:');
|
||||
console.log(` 電子郵件: ${adminUserData.email}`);
|
||||
console.log(` 密碼: ${adminUserData.password}`);
|
||||
console.log(` 角色: ${adminUserData.role}`);
|
||||
console.log(` 部門: ${adminUserData.department}`);
|
||||
|
||||
// 驗證用戶創建
|
||||
const [userResult] = await connection.execute(
|
||||
'SELECT id, name, email, role, department FROM users WHERE email = ?',
|
||||
[adminUserData.email]
|
||||
);
|
||||
|
||||
if (userResult.length > 0) {
|
||||
const user = userResult[0];
|
||||
console.log('\n📋 資料庫中的用戶資訊:');
|
||||
console.log(` ID: ${user.id}`);
|
||||
console.log(` 姓名: ${user.name}`);
|
||||
console.log(` 電子郵件: ${user.email}`);
|
||||
console.log(` 角色: ${user.role}`);
|
||||
console.log(` 部門: ${user.department}`);
|
||||
}
|
||||
|
||||
console.log('\n💡 現在您可以使用這些憑證登入管理後台');
|
||||
console.log('💡 登入後,管理後台的應用創建功能應該可以正常工作');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 創建管理員用戶失敗:', error.message);
|
||||
} finally {
|
||||
if (connection) {
|
||||
await connection.end();
|
||||
console.log('🔌 資料庫連接已關閉');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
createAdminUser().catch(console.error);
|
113
scripts/fix-apps-table.js
Normal file
113
scripts/fix-apps-table.js
Normal file
@@ -0,0 +1,113 @@
|
||||
const mysql = require('mysql2/promise');
|
||||
|
||||
const dbConfig = {
|
||||
host: process.env.DB_HOST || 'mysql.theaken.com',
|
||||
port: parseInt(process.env.DB_PORT || '33306'),
|
||||
user: process.env.DB_USER || 'AI_Platform',
|
||||
password: process.env.DB_PASSWORD || 'Aa123456',
|
||||
database: process.env.DB_NAME || 'db_AI_Platform',
|
||||
charset: 'utf8mb4',
|
||||
timezone: '+08:00'
|
||||
};
|
||||
|
||||
async function fixAppsTable() {
|
||||
let connection;
|
||||
|
||||
try {
|
||||
console.log('🔧 開始修復 apps 表格...');
|
||||
|
||||
connection = await mysql.createConnection(dbConfig);
|
||||
console.log('✅ 資料庫連接成功');
|
||||
|
||||
// 檢查並添加新欄位
|
||||
const alterStatements = [
|
||||
// 添加狀態欄位
|
||||
`ALTER TABLE apps ADD COLUMN status ENUM('draft', 'submitted', 'under_review', 'approved', 'rejected', 'published') DEFAULT 'draft'`,
|
||||
|
||||
// 添加類型欄位
|
||||
`ALTER TABLE apps ADD COLUMN type ENUM('web_app', 'mobile_app', 'desktop_app', 'api_service', 'ai_model', 'data_analysis', 'automation', 'other') DEFAULT 'other'`,
|
||||
|
||||
// 添加檔案路徑欄位
|
||||
`ALTER TABLE apps ADD COLUMN file_path VARCHAR(500)`,
|
||||
|
||||
// 添加技術棧欄位
|
||||
`ALTER TABLE apps ADD COLUMN tech_stack JSON`,
|
||||
|
||||
// 添加標籤欄位
|
||||
`ALTER TABLE apps ADD COLUMN tags JSON`,
|
||||
|
||||
// 添加截圖路徑欄位
|
||||
`ALTER TABLE apps ADD COLUMN screenshots JSON`,
|
||||
|
||||
// 添加演示連結欄位
|
||||
`ALTER TABLE apps ADD COLUMN demo_url VARCHAR(500)`,
|
||||
|
||||
// 添加 GitHub 連結欄位
|
||||
`ALTER TABLE apps ADD COLUMN github_url VARCHAR(500)`,
|
||||
|
||||
// 添加文檔連結欄位
|
||||
`ALTER TABLE apps ADD COLUMN docs_url VARCHAR(500)`,
|
||||
|
||||
// 添加版本欄位
|
||||
`ALTER TABLE apps ADD COLUMN version VARCHAR(50) DEFAULT '1.0.0'`,
|
||||
|
||||
// 添加最後更新時間欄位
|
||||
`ALTER TABLE apps ADD COLUMN last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP`
|
||||
];
|
||||
|
||||
for (const statement of alterStatements) {
|
||||
try {
|
||||
await connection.execute(statement);
|
||||
console.log(`✅ 執行: ${statement.substring(0, 50)}...`);
|
||||
} catch (error) {
|
||||
if (error.code === 'ER_DUP_FIELDNAME') {
|
||||
console.log(`⚠️ 欄位已存在,跳過: ${statement.substring(0, 50)}...`);
|
||||
} else {
|
||||
console.error(`❌ 執行失敗: ${statement.substring(0, 50)}...`, error.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 添加索引
|
||||
const indexStatements = [
|
||||
`CREATE INDEX idx_apps_status ON apps(status)`,
|
||||
`CREATE INDEX idx_apps_type ON apps(type)`,
|
||||
`CREATE INDEX idx_apps_created_at ON apps(created_at)`,
|
||||
`CREATE INDEX idx_apps_rating ON apps(rating DESC)`,
|
||||
`CREATE INDEX idx_apps_likes ON apps(likes_count DESC)`
|
||||
];
|
||||
|
||||
for (const statement of indexStatements) {
|
||||
try {
|
||||
await connection.execute(statement);
|
||||
console.log(`✅ 創建索引: ${statement.substring(0, 50)}...`);
|
||||
} catch (error) {
|
||||
if (error.code === 'ER_DUP_KEYNAME') {
|
||||
console.log(`⚠️ 索引已存在,跳過: ${statement.substring(0, 50)}...`);
|
||||
} else {
|
||||
console.error(`❌ 創建索引失敗: ${statement.substring(0, 50)}...`, error.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 檢查表格結構
|
||||
const [columns] = await connection.execute('DESCRIBE apps');
|
||||
console.log('\n📋 apps 表格結構:');
|
||||
columns.forEach(col => {
|
||||
console.log(` ${col.Field}: ${col.Type} ${col.Null === 'YES' ? 'NULL' : 'NOT NULL'} ${col.Default ? `DEFAULT ${col.Default}` : ''}`);
|
||||
});
|
||||
|
||||
console.log('\n✅ apps 表格修復完成!');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 修復 apps 表格失敗:', error);
|
||||
} finally {
|
||||
if (connection) {
|
||||
await connection.end();
|
||||
console.log('🔌 資料庫連接已關閉');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 執行修復
|
||||
fixAppsTable().catch(console.error);
|
64
scripts/reset-user-password.js
Normal file
64
scripts/reset-user-password.js
Normal file
@@ -0,0 +1,64 @@
|
||||
const mysql = require('mysql2/promise');
|
||||
const bcrypt = require('bcrypt');
|
||||
|
||||
const dbConfig = {
|
||||
host: process.env.DB_HOST || 'mysql.theaken.com',
|
||||
port: parseInt(process.env.DB_PORT || '33306'),
|
||||
user: process.env.DB_USER || 'AI_Platform',
|
||||
password: process.env.DB_PASSWORD || 'Aa123456',
|
||||
database: process.env.DB_NAME || 'db_AI_Platform',
|
||||
charset: 'utf8mb4',
|
||||
timezone: '+08:00'
|
||||
};
|
||||
|
||||
async function resetUserPassword() {
|
||||
let connection;
|
||||
|
||||
try {
|
||||
console.log('🔧 重置用戶密碼...');
|
||||
|
||||
connection = await mysql.createConnection(dbConfig);
|
||||
console.log('✅ 資料庫連接成功');
|
||||
|
||||
// 新密碼
|
||||
const newPassword = 'Admin123';
|
||||
const hashedPassword = await bcrypt.hash(newPassword, 12);
|
||||
|
||||
console.log(`\n新密碼: ${newPassword}`);
|
||||
console.log(`密碼哈希: ${hashedPassword}`);
|
||||
|
||||
// 重置所有管理員用戶的密碼
|
||||
const adminEmails = [
|
||||
'admin@theaken.com',
|
||||
'admin@example.com',
|
||||
'petty091901@gmail.com'
|
||||
];
|
||||
|
||||
for (const email of adminEmails) {
|
||||
try {
|
||||
await connection.execute(
|
||||
'UPDATE users SET password_hash = ? WHERE email = ?',
|
||||
[hashedPassword, email]
|
||||
);
|
||||
|
||||
console.log(`✅ 已重置 ${email} 的密碼`);
|
||||
} catch (error) {
|
||||
console.error(`❌ 重置 ${email} 密碼失敗:`, error.message);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('\n🎉 密碼重置完成!');
|
||||
console.log('現在可以使用以下憑證登入:');
|
||||
console.log('電子郵件: admin@theaken.com');
|
||||
console.log('密碼: Admin123');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 重置失敗:', error);
|
||||
} finally {
|
||||
if (connection) {
|
||||
await connection.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resetUserPassword();
|
107
scripts/test-admin-app-creation.js
Normal file
107
scripts/test-admin-app-creation.js
Normal file
@@ -0,0 +1,107 @@
|
||||
const mysql = require('mysql2/promise');
|
||||
|
||||
const dbConfig = {
|
||||
host: process.env.DB_HOST || 'mysql.theaken.com',
|
||||
port: parseInt(process.env.DB_PORT || '33306'),
|
||||
user: process.env.DB_USER || 'AI_Platform',
|
||||
password: process.env.DB_PASSWORD || 'Aa123456',
|
||||
database: process.env.DB_NAME || 'db_AI_Platform',
|
||||
charset: 'utf8mb4',
|
||||
timezone: '+08:00'
|
||||
};
|
||||
|
||||
async function testAdminAppCreation() {
|
||||
let connection;
|
||||
try {
|
||||
console.log('🧪 測試管理後台應用程式創建流程...');
|
||||
connection = await mysql.createConnection(dbConfig);
|
||||
console.log('✅ 資料庫連接成功');
|
||||
|
||||
// 創建測試用戶(管理員)
|
||||
const userData = {
|
||||
id: 'admin-test-' + Date.now(),
|
||||
name: '管理員測試用戶',
|
||||
email: 'admin-test@example.com',
|
||||
password_hash: 'test_hash',
|
||||
department: 'ITBU',
|
||||
role: 'admin',
|
||||
join_date: new Date(),
|
||||
created_at: new Date(),
|
||||
updated_at: new Date()
|
||||
};
|
||||
|
||||
await connection.execute(
|
||||
'INSERT INTO users (id, name, email, password_hash, department, role, join_date, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)',
|
||||
[userData.id, userData.name, userData.email, userData.password_hash, userData.department, userData.role, userData.join_date, userData.created_at, userData.updated_at]
|
||||
);
|
||||
console.log('✅ 測試管理員用戶創建成功');
|
||||
|
||||
// 模擬管理後台提交的資料
|
||||
const adminAppData = {
|
||||
name: '管理後台測試應用',
|
||||
description: '這是一個通過管理後台創建的測試應用程式',
|
||||
type: 'ai_model', // 映射後的類型
|
||||
demoUrl: 'https://admin-test.example.com/demo',
|
||||
version: '1.0.0'
|
||||
};
|
||||
|
||||
console.log('📋 管理後台提交的資料:', adminAppData);
|
||||
|
||||
// 創建應用程式
|
||||
const appId = Date.now().toString(36) + Math.random().toString(36).substr(2);
|
||||
const appInsertData = {
|
||||
id: appId,
|
||||
name: adminAppData.name,
|
||||
description: adminAppData.description,
|
||||
creator_id: userData.id,
|
||||
type: adminAppData.type,
|
||||
demo_url: adminAppData.demoUrl,
|
||||
version: adminAppData.version,
|
||||
status: 'draft'
|
||||
};
|
||||
|
||||
await connection.execute(
|
||||
'INSERT INTO apps (id, name, description, creator_id, type, demo_url, version, status, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())',
|
||||
[appInsertData.id, appInsertData.name, appInsertData.description, appInsertData.creator_id, appInsertData.type, appInsertData.demo_url, appInsertData.version, appInsertData.status]
|
||||
);
|
||||
console.log('✅ 應用程式創建成功');
|
||||
|
||||
// 查詢並顯示創建的應用程式
|
||||
const [appResult] = await connection.execute(
|
||||
'SELECT a.*, u.name as creator_name FROM apps a LEFT JOIN users u ON a.creator_id = u.id WHERE a.id = ?',
|
||||
[appId]
|
||||
);
|
||||
|
||||
if (appResult.length > 0) {
|
||||
const app = appResult[0];
|
||||
console.log('\n📋 資料庫中的應用程式資料:');
|
||||
console.log(` ID: ${app.id}`);
|
||||
console.log(` 名稱: ${app.name}`);
|
||||
console.log(` 描述: ${app.description}`);
|
||||
console.log(` 類型: ${app.type}`);
|
||||
console.log(` 狀態: ${app.status}`);
|
||||
console.log(` 創建者: ${app.creator_name}`);
|
||||
console.log(` 演示連結: ${app.demo_url}`);
|
||||
console.log(` 版本: ${app.version}`);
|
||||
console.log(` 創建時間: ${app.created_at}`);
|
||||
}
|
||||
|
||||
console.log('\n✅ 管理後台應用程式創建測試成功!');
|
||||
console.log('🎯 問題已解決:管理後台現在可以正確創建應用程式並保存到資料庫');
|
||||
|
||||
// 清理測試資料
|
||||
await connection.execute('DELETE FROM apps WHERE id = ?', [appId]);
|
||||
await connection.execute('DELETE FROM users WHERE id = ?', [userData.id]);
|
||||
console.log('✅ 測試資料清理完成');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 測試失敗:', error.message);
|
||||
} finally {
|
||||
if (connection) {
|
||||
await connection.end();
|
||||
console.log('🔌 資料庫連接已關閉');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
testAdminAppCreation().catch(console.error);
|
104
scripts/test-api-error.js
Normal file
104
scripts/test-api-error.js
Normal file
@@ -0,0 +1,104 @@
|
||||
const mysql = require('mysql2/promise');
|
||||
const bcrypt = require('bcrypt');
|
||||
|
||||
const dbConfig = {
|
||||
host: process.env.DB_HOST || 'mysql.theaken.com',
|
||||
port: parseInt(process.env.DB_PORT || '33306'),
|
||||
user: process.env.DB_USER || 'AI_Platform',
|
||||
password: process.env.DB_PASSWORD || 'Aa123456',
|
||||
database: process.env.DB_NAME || 'db_AI_Platform',
|
||||
charset: 'utf8mb4',
|
||||
timezone: '+08:00'
|
||||
};
|
||||
|
||||
async function testApiError() {
|
||||
let connection;
|
||||
try {
|
||||
console.log('🧪 測試 API 錯誤...');
|
||||
connection = await mysql.createConnection(dbConfig);
|
||||
console.log('✅ 資料庫連接成功');
|
||||
|
||||
// 檢查 apps 表結構
|
||||
const [describeResult] = await connection.execute('DESCRIBE apps');
|
||||
console.log('\n📋 apps 表結構:');
|
||||
describeResult.forEach(row => {
|
||||
console.log(` ${row.Field}: ${row.Type} ${row.Null === 'YES' ? 'NULL' : 'NOT NULL'} ${row.Default ? `DEFAULT ${row.Default}` : ''}`);
|
||||
});
|
||||
|
||||
// 檢查是否有管理員用戶
|
||||
const [users] = await connection.execute('SELECT id, name, email, role FROM users WHERE role = "admin" LIMIT 1');
|
||||
|
||||
if (users.length === 0) {
|
||||
console.log('\n⚠️ 沒有找到管理員用戶,創建一個...');
|
||||
|
||||
const adminUserData = {
|
||||
id: 'admin-' + Date.now(),
|
||||
name: '系統管理員',
|
||||
email: 'admin@example.com',
|
||||
password: 'Admin123!',
|
||||
department: 'ITBU',
|
||||
role: 'admin',
|
||||
join_date: new Date(),
|
||||
created_at: new Date(),
|
||||
updated_at: new Date()
|
||||
};
|
||||
|
||||
const passwordHash = await bcrypt.hash(adminUserData.password, 12);
|
||||
|
||||
await connection.execute(
|
||||
'INSERT INTO users (id, name, email, password_hash, department, role, join_date, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)',
|
||||
[adminUserData.id, adminUserData.name, adminUserData.email, passwordHash, adminUserData.department, adminUserData.role, adminUserData.join_date, adminUserData.created_at, adminUserData.updated_at]
|
||||
);
|
||||
|
||||
console.log('✅ 管理員用戶創建成功');
|
||||
} else {
|
||||
console.log('\n✅ 找到管理員用戶:', users[0].email);
|
||||
}
|
||||
|
||||
// 測試直接插入應用程式
|
||||
console.log('\n🧪 測試直接插入應用程式...');
|
||||
|
||||
const testAppData = {
|
||||
id: 'test-app-' + Date.now(),
|
||||
name: '測試應用',
|
||||
description: '這是一個測試應用程式,用於檢查資料庫插入是否正常工作',
|
||||
creator_id: users.length > 0 ? users[0].id : 'admin-' + Date.now(),
|
||||
type: 'ai_model',
|
||||
demo_url: 'https://test.example.com',
|
||||
version: '1.0.0',
|
||||
status: 'draft'
|
||||
};
|
||||
|
||||
try {
|
||||
await connection.execute(
|
||||
'INSERT INTO apps (id, name, description, creator_id, type, demo_url, version, status, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())',
|
||||
[testAppData.id, testAppData.name, testAppData.description, testAppData.creator_id, testAppData.type, testAppData.demo_url, testAppData.version, testAppData.status]
|
||||
);
|
||||
console.log('✅ 直接插入應用程式成功');
|
||||
|
||||
// 清理測試資料
|
||||
await connection.execute('DELETE FROM apps WHERE id = ?', [testAppData.id]);
|
||||
console.log('✅ 測試資料清理完成');
|
||||
|
||||
} catch (insertError) {
|
||||
console.error('❌ 直接插入失敗:', insertError.message);
|
||||
console.error('詳細錯誤:', insertError);
|
||||
}
|
||||
|
||||
// 檢查資料庫連接狀態
|
||||
console.log('\n🧪 檢查資料庫連接狀態...');
|
||||
const [result] = await connection.execute('SELECT 1 as test');
|
||||
console.log('✅ 資料庫連接正常:', result[0]);
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 測試失敗:', error.message);
|
||||
console.error('詳細錯誤:', error);
|
||||
} finally {
|
||||
if (connection) {
|
||||
await connection.end();
|
||||
console.log('🔌 資料庫連接已關閉');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
testApiError().catch(console.error);
|
69
scripts/test-api-simple.js
Normal file
69
scripts/test-api-simple.js
Normal file
@@ -0,0 +1,69 @@
|
||||
const http = require('http');
|
||||
|
||||
function makeRequest(url, method = 'GET') {
|
||||
return new Promise((resolve, reject) => {
|
||||
const urlObj = new URL(url);
|
||||
|
||||
const options = {
|
||||
hostname: urlObj.hostname,
|
||||
port: urlObj.port,
|
||||
path: urlObj.pathname,
|
||||
method: method,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
};
|
||||
|
||||
const req = http.request(options, (res) => {
|
||||
let data = '';
|
||||
|
||||
res.on('data', (chunk) => {
|
||||
data += chunk;
|
||||
});
|
||||
|
||||
res.on('end', () => {
|
||||
try {
|
||||
const jsonData = JSON.parse(data);
|
||||
resolve({
|
||||
status: res.statusCode,
|
||||
data: jsonData
|
||||
});
|
||||
} catch (error) {
|
||||
resolve({
|
||||
status: res.statusCode,
|
||||
data: data
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
req.on('error', (error) => {
|
||||
reject(error);
|
||||
});
|
||||
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
async function testAPI() {
|
||||
try {
|
||||
console.log('🧪 測試 API 可訪問性...');
|
||||
|
||||
// 測試根 API
|
||||
console.log('\n1. 測試根 API...');
|
||||
const response = await makeRequest('http://localhost:3000/api');
|
||||
console.log('狀態碼:', response.status);
|
||||
console.log('回應:', JSON.stringify(response.data, null, 2));
|
||||
|
||||
// 測試 apps API
|
||||
console.log('\n2. 測試 apps API...');
|
||||
const appsResponse = await makeRequest('http://localhost:3000/api/apps');
|
||||
console.log('狀態碼:', appsResponse.status);
|
||||
console.log('回應:', JSON.stringify(appsResponse.data, null, 2));
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 測試失敗:', error.message);
|
||||
}
|
||||
}
|
||||
|
||||
testAPI();
|
41
scripts/test-api-stats.js
Normal file
41
scripts/test-api-stats.js
Normal file
@@ -0,0 +1,41 @@
|
||||
const jwt = require('jsonwebtoken');
|
||||
|
||||
const JWT_SECRET = process.env.JWT_SECRET || 'good777';
|
||||
|
||||
async function testApiStats() {
|
||||
try {
|
||||
// Generate a token for admin user
|
||||
const adminPayload = {
|
||||
id: 1,
|
||||
email: 'admin@example.com',
|
||||
role: 'admin'
|
||||
};
|
||||
const token = jwt.sign(adminPayload, JWT_SECRET, { expiresIn: '1h' });
|
||||
|
||||
console.log('=== 測試 API 統計 ===');
|
||||
|
||||
// Test the apps API
|
||||
const response = await fetch('http://localhost:3000/api/apps?page=1&limit=10', {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`
|
||||
}
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
console.log('✅ API 回應成功');
|
||||
console.log('分頁資訊:', data.pagination);
|
||||
console.log('統計資訊:', data.stats);
|
||||
console.log(`應用程式數量: ${data.apps?.length || 0}`);
|
||||
} else {
|
||||
console.log('❌ API 回應失敗:', response.status, response.statusText);
|
||||
const errorText = await response.text();
|
||||
console.log('錯誤詳情:', errorText);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('測試過程中發生錯誤:', error);
|
||||
}
|
||||
}
|
||||
|
||||
testApiStats();
|
105
scripts/test-app-creation.js
Normal file
105
scripts/test-app-creation.js
Normal file
@@ -0,0 +1,105 @@
|
||||
const http = require('http');
|
||||
const jwt = require('jsonwebtoken');
|
||||
|
||||
const JWT_SECRET = process.env.JWT_SECRET || 'good777';
|
||||
|
||||
// 生成測試 Token
|
||||
function generateTestToken() {
|
||||
return jwt.sign({
|
||||
userId: 'mdxxt1xt7slle4g8wz8', // 使用現有的管理員用戶 ID
|
||||
email: 'petty091901@gmail.com',
|
||||
role: 'admin'
|
||||
}, JWT_SECRET, { expiresIn: '1h' });
|
||||
}
|
||||
|
||||
// 發送 HTTP 請求
|
||||
function makeRequest(url, method = 'GET', body = null, headers = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const urlObj = new URL(url);
|
||||
|
||||
const options = {
|
||||
hostname: urlObj.hostname,
|
||||
port: urlObj.port,
|
||||
path: urlObj.pathname,
|
||||
method: method,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...headers
|
||||
}
|
||||
};
|
||||
|
||||
const req = http.request(options, (res) => {
|
||||
let data = '';
|
||||
|
||||
res.on('data', (chunk) => {
|
||||
data += chunk;
|
||||
});
|
||||
|
||||
res.on('end', () => {
|
||||
try {
|
||||
const jsonData = JSON.parse(data);
|
||||
resolve({
|
||||
status: res.statusCode,
|
||||
data: jsonData
|
||||
});
|
||||
} catch (error) {
|
||||
resolve({
|
||||
status: res.statusCode,
|
||||
data: data
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
req.on('error', (error) => {
|
||||
reject(error);
|
||||
});
|
||||
|
||||
if (body) {
|
||||
req.write(JSON.stringify(body));
|
||||
}
|
||||
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
async function testAppCreation() {
|
||||
try {
|
||||
console.log('🧪 測試應用程式創建...');
|
||||
|
||||
// 生成測試 Token
|
||||
const token = generateTestToken();
|
||||
console.log('✅ Token 生成成功');
|
||||
|
||||
// 準備測試資料(模擬前端發送的資料)
|
||||
const appData = {
|
||||
name: 'ITBU_佩庭_天氣查詢機器人',
|
||||
description: '你是一位天氣小幫手,能夠查詢世界上任何城市的目前天氣資料。',
|
||||
type: 'productivity',
|
||||
demoUrl: 'https://dify.theaken.com/chat/xLqNfXDQIeoKGROm',
|
||||
version: '1.0.0'
|
||||
};
|
||||
|
||||
console.log('📤 發送資料:', JSON.stringify(appData, null, 2));
|
||||
|
||||
// 發送請求
|
||||
console.log('🔑 使用 Token:', token.substring(0, 50) + '...');
|
||||
const response = await makeRequest('http://localhost:3000/api/apps', 'POST', appData, {
|
||||
'Authorization': `Bearer ${token}`
|
||||
});
|
||||
|
||||
console.log('📥 回應狀態:', response.status);
|
||||
console.log('📥 回應資料:', JSON.stringify(response.data, null, 2));
|
||||
|
||||
if (response.status === 201) {
|
||||
console.log('✅ 應用程式創建成功!');
|
||||
} else {
|
||||
console.log('❌ 應用程式創建失敗');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 測試失敗:', error.message);
|
||||
}
|
||||
}
|
||||
|
||||
testAppCreation();
|
88
scripts/test-approval.js
Normal file
88
scripts/test-approval.js
Normal file
@@ -0,0 +1,88 @@
|
||||
const jwt = require('jsonwebtoken');
|
||||
|
||||
async function testApproval() {
|
||||
console.log('🧪 測試批准功能...');
|
||||
|
||||
// 生成測試 token
|
||||
const token = jwt.sign(
|
||||
{ userId: 'admin-001', role: 'admin' },
|
||||
process.env.JWT_SECRET || 'good777',
|
||||
{ expiresIn: '1h' }
|
||||
);
|
||||
|
||||
console.log('✅ Token 生成成功\n');
|
||||
|
||||
try {
|
||||
// 首先獲取應用程式列表
|
||||
const response = await fetch('http://localhost:3000/api/apps', {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`
|
||||
}
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
console.log(`❌ 獲取應用程式失敗: ${response.status}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
console.log(`✅ 獲取到 ${data.apps.length} 個應用程式`);
|
||||
|
||||
// 找到一個可以測試的應用程式
|
||||
const testApp = data.apps[0];
|
||||
if (!testApp) {
|
||||
console.log('❌ 沒有找到可測試的應用程式');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`\n測試應用程式: ${testApp.name} (ID: ${testApp.id})`);
|
||||
console.log(`當前狀態: ${testApp.status}`);
|
||||
|
||||
// 測試批准功能
|
||||
console.log('\n測試批准功能...');
|
||||
const approveResponse = await fetch(`http://localhost:3000/api/apps/${testApp.id}`, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${token}`
|
||||
},
|
||||
body: JSON.stringify({
|
||||
status: 'published'
|
||||
})
|
||||
});
|
||||
|
||||
if (approveResponse.ok) {
|
||||
console.log('✅ 批准成功');
|
||||
} else {
|
||||
const errorData = await approveResponse.json();
|
||||
console.log(`❌ 批准失敗: ${errorData.error}`);
|
||||
}
|
||||
|
||||
// 測試拒絕功能
|
||||
console.log('\n測試拒絕功能...');
|
||||
const rejectResponse = await fetch(`http://localhost:3000/api/apps/${testApp.id}`, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${token}`
|
||||
},
|
||||
body: JSON.stringify({
|
||||
status: 'rejected'
|
||||
})
|
||||
});
|
||||
|
||||
if (rejectResponse.ok) {
|
||||
console.log('✅ 拒絕成功');
|
||||
} else {
|
||||
const errorData = await rejectResponse.json();
|
||||
console.log(`❌ 拒絕失敗: ${errorData.error}`);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.log(`❌ 測試失敗: ${error.message}`);
|
||||
}
|
||||
|
||||
console.log('\n✅ 批准測試完成');
|
||||
}
|
||||
|
||||
testApproval();
|
199
scripts/test-apps-api.js
Normal file
199
scripts/test-apps-api.js
Normal file
@@ -0,0 +1,199 @@
|
||||
const mysql = require('mysql2/promise');
|
||||
const bcrypt = require('bcrypt');
|
||||
const jwt = require('jsonwebtoken');
|
||||
|
||||
const dbConfig = {
|
||||
host: process.env.DB_HOST || 'mysql.theaken.com',
|
||||
port: parseInt(process.env.DB_PORT || '33306'),
|
||||
user: process.env.DB_USER || 'AI_Platform',
|
||||
password: process.env.DB_PASSWORD || 'Aa123456',
|
||||
database: process.env.DB_NAME || 'db_AI_Platform',
|
||||
charset: 'utf8mb4',
|
||||
timezone: '+08:00'
|
||||
};
|
||||
|
||||
const JWT_SECRET = 'ai_platform_jwt_secret_key_2024';
|
||||
|
||||
async function testAppsAPI() {
|
||||
let connection;
|
||||
|
||||
try {
|
||||
console.log('🧪 開始測試應用程式 API...');
|
||||
|
||||
connection = await mysql.createConnection(dbConfig);
|
||||
console.log('✅ 資料庫連接成功');
|
||||
|
||||
// 1. 創建測試用戶
|
||||
console.log('\n1. 創建測試用戶...');
|
||||
const testUserId = 'test-user-' + Date.now();
|
||||
const hashedPassword = await bcrypt.hash('test123', 12);
|
||||
|
||||
await connection.execute(`
|
||||
INSERT INTO users (id, name, email, password_hash, department, role, join_date)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||
`, [testUserId, '測試用戶', 'test@example.com', hashedPassword, '測試部', 'developer', '2025-01-01']);
|
||||
|
||||
console.log('✅ 測試用戶創建成功');
|
||||
|
||||
// 2. 生成測試 Token
|
||||
const token = jwt.sign({
|
||||
userId: testUserId,
|
||||
email: 'test@example.com',
|
||||
role: 'developer'
|
||||
}, JWT_SECRET, { expiresIn: '1h' });
|
||||
|
||||
console.log('✅ JWT Token 生成成功');
|
||||
|
||||
// 3. 測試創建應用程式
|
||||
console.log('\n2. 測試創建應用程式...');
|
||||
const appData = {
|
||||
id: 'test-app-' + Date.now(),
|
||||
name: '測試 AI 應用',
|
||||
description: '這是一個用於測試的 AI 應用程式,具有機器學習功能',
|
||||
creator_id: testUserId,
|
||||
type: 'web_app',
|
||||
tech_stack: JSON.stringify(['React', 'Node.js', 'TensorFlow']),
|
||||
tags: JSON.stringify(['AI', '機器學習', '測試']),
|
||||
demo_url: 'https://demo.example.com',
|
||||
github_url: 'https://github.com/test/app',
|
||||
docs_url: 'https://docs.example.com',
|
||||
version: '1.0.0',
|
||||
status: 'draft'
|
||||
};
|
||||
|
||||
await connection.execute(`
|
||||
INSERT INTO apps (id, name, description, creator_id, type, tech_stack, tags, demo_url, github_url, docs_url, version, status)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`, [
|
||||
appData.id, appData.name, appData.description, appData.creator_id, appData.type,
|
||||
appData.tech_stack, appData.tags, appData.demo_url, appData.github_url, appData.docs_url,
|
||||
appData.version, appData.status
|
||||
]);
|
||||
|
||||
console.log('✅ 測試應用程式創建成功');
|
||||
|
||||
// 4. 測試查詢應用程式列表
|
||||
console.log('\n3. 測試查詢應用程式列表...');
|
||||
const [apps] = await connection.execute(`
|
||||
SELECT
|
||||
a.*,
|
||||
u.name as creator_name,
|
||||
u.email as creator_email,
|
||||
u.department as creator_department,
|
||||
u.role as creator_role
|
||||
FROM apps a
|
||||
LEFT JOIN users u ON a.creator_id = u.id
|
||||
WHERE a.creator_id = ?
|
||||
`, [testUserId]);
|
||||
|
||||
console.log(`✅ 查詢到 ${apps.length} 個應用程式`);
|
||||
apps.forEach(app => {
|
||||
console.log(` - ${app.name} (${app.type}) - ${app.status}`);
|
||||
});
|
||||
|
||||
// 5. 測試更新應用程式
|
||||
console.log('\n4. 測試更新應用程式...');
|
||||
await connection.execute(`
|
||||
UPDATE apps
|
||||
SET name = ?, description = ?, status = ?, version = ?
|
||||
WHERE id = ?
|
||||
`, [
|
||||
'更新後的測試 AI 應用',
|
||||
'這是更新後的測試應用程式描述',
|
||||
'submitted',
|
||||
'1.1.0',
|
||||
appData.id
|
||||
]);
|
||||
|
||||
console.log('✅ 應用程式更新成功');
|
||||
|
||||
// 6. 測試按讚功能
|
||||
console.log('\n5. 測試按讚功能...');
|
||||
const likeId = 'like-' + Date.now();
|
||||
await connection.execute(`
|
||||
INSERT INTO user_likes (id, user_id, app_id, liked_at)
|
||||
VALUES (?, ?, ?, NOW())
|
||||
`, [likeId, testUserId, appData.id]);
|
||||
|
||||
await connection.execute(`
|
||||
UPDATE apps SET likes_count = likes_count + 1 WHERE id = ?
|
||||
`, [appData.id]);
|
||||
|
||||
console.log('✅ 按讚功能測試成功');
|
||||
|
||||
// 7. 測試收藏功能
|
||||
console.log('\n6. 測試收藏功能...');
|
||||
const favoriteId = 'favorite-' + Date.now();
|
||||
await connection.execute(`
|
||||
INSERT INTO user_favorites (id, user_id, app_id)
|
||||
VALUES (?, ?, ?)
|
||||
`, [favoriteId, testUserId, appData.id]);
|
||||
|
||||
console.log('✅ 收藏功能測試成功');
|
||||
|
||||
// 8. 測試統計功能
|
||||
console.log('\n7. 測試統計功能...');
|
||||
const [stats] = await connection.execute(`
|
||||
SELECT
|
||||
COUNT(*) as total,
|
||||
SUM(CASE WHEN status = 'published' THEN 1 ELSE 0 END) as published,
|
||||
SUM(CASE WHEN status IN ('submitted', 'under_review') THEN 1 ELSE 0 END) as pending_review,
|
||||
SUM(CASE WHEN status = 'draft' THEN 1 ELSE 0 END) as draft,
|
||||
SUM(CASE WHEN status = 'approved' THEN 1 ELSE 0 END) as approved,
|
||||
SUM(CASE WHEN status = 'rejected' THEN 1 ELSE 0 END) as rejected
|
||||
FROM apps
|
||||
`);
|
||||
|
||||
console.log('✅ 統計功能測試成功:');
|
||||
console.log(` - 總應用數: ${stats[0].total}`);
|
||||
console.log(` - 已發布: ${stats[0].published}`);
|
||||
console.log(` - 待審核: ${stats[0].pending_review}`);
|
||||
console.log(` - 草稿: ${stats[0].draft}`);
|
||||
console.log(` - 已批准: ${stats[0].approved}`);
|
||||
console.log(` - 已拒絕: ${stats[0].rejected}`);
|
||||
|
||||
// 9. 測試搜尋功能
|
||||
console.log('\n8. 測試搜尋功能...');
|
||||
const [searchResults] = await connection.execute(`
|
||||
SELECT a.*, u.name as creator_name
|
||||
FROM apps a
|
||||
LEFT JOIN users u ON a.creator_id = u.id
|
||||
WHERE (a.name LIKE ? OR a.description LIKE ? OR u.name LIKE ?)
|
||||
AND a.type = ?
|
||||
AND a.status = ?
|
||||
`, ['%AI%', '%AI%', '%測試%', 'web_app', 'submitted']);
|
||||
|
||||
console.log(`✅ 搜尋功能測試成功,找到 ${searchResults.length} 個結果`);
|
||||
|
||||
// 10. 測試刪除功能
|
||||
console.log('\n9. 測試刪除功能...');
|
||||
|
||||
// 先刪除相關記錄
|
||||
await connection.execute('DELETE FROM user_likes WHERE app_id = ?', [appData.id]);
|
||||
await connection.execute('DELETE FROM user_favorites WHERE app_id = ?', [appData.id]);
|
||||
|
||||
// 刪除應用程式
|
||||
await connection.execute('DELETE FROM apps WHERE id = ?', [appData.id]);
|
||||
|
||||
console.log('✅ 刪除功能測試成功');
|
||||
|
||||
// 11. 清理測試資料
|
||||
console.log('\n10. 清理測試資料...');
|
||||
await connection.execute('DELETE FROM users WHERE id = ?', [testUserId]);
|
||||
|
||||
console.log('✅ 測試資料清理完成');
|
||||
|
||||
console.log('\n🎉 所有應用程式 API 測試通過!');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 測試失敗:', error);
|
||||
} finally {
|
||||
if (connection) {
|
||||
await connection.end();
|
||||
console.log('🔌 資料庫連接已關閉');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 執行測試
|
||||
testAppsAPI().catch(console.error);
|
99
scripts/test-apps-query.js
Normal file
99
scripts/test-apps-query.js
Normal file
@@ -0,0 +1,99 @@
|
||||
const http = require('http');
|
||||
const jwt = require('jsonwebtoken');
|
||||
|
||||
const JWT_SECRET = process.env.JWT_SECRET || 'good777';
|
||||
|
||||
// 生成測試 Token
|
||||
function generateTestToken() {
|
||||
return jwt.sign({
|
||||
userId: 'mdxxt1xt7slle4g8wz8',
|
||||
email: 'petty091901@gmail.com',
|
||||
role: 'admin'
|
||||
}, JWT_SECRET, { expiresIn: '1h' });
|
||||
}
|
||||
|
||||
// 發送 HTTP 請求
|
||||
function makeRequest(url, method = 'GET', body = null, headers = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const urlObj = new URL(url);
|
||||
|
||||
const options = {
|
||||
hostname: urlObj.hostname,
|
||||
port: urlObj.port,
|
||||
path: urlObj.pathname,
|
||||
method: method,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...headers
|
||||
}
|
||||
};
|
||||
|
||||
const req = http.request(options, (res) => {
|
||||
let data = '';
|
||||
|
||||
res.on('data', (chunk) => {
|
||||
data += chunk;
|
||||
});
|
||||
|
||||
res.on('end', () => {
|
||||
try {
|
||||
const jsonData = JSON.parse(data);
|
||||
resolve({
|
||||
status: res.statusCode,
|
||||
data: jsonData
|
||||
});
|
||||
} catch (error) {
|
||||
resolve({
|
||||
status: res.statusCode,
|
||||
data: data
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
req.on('error', (error) => {
|
||||
reject(error);
|
||||
});
|
||||
|
||||
if (body) {
|
||||
req.write(JSON.stringify(body));
|
||||
}
|
||||
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
async function testAppsQuery() {
|
||||
try {
|
||||
console.log('🧪 測試應用程式查詢...');
|
||||
|
||||
// 生成測試 Token
|
||||
const token = generateTestToken();
|
||||
console.log('✅ Token 生成成功');
|
||||
|
||||
// 測試 GET /api/apps
|
||||
console.log('\n1. 測試 GET /api/apps...');
|
||||
const response = await makeRequest('http://localhost:3000/api/apps', 'GET', null, {
|
||||
'Authorization': `Bearer ${token}`
|
||||
});
|
||||
|
||||
console.log('狀態碼:', response.status);
|
||||
console.log('回應:', JSON.stringify(response.data, null, 2));
|
||||
|
||||
if (response.status === 200) {
|
||||
console.log('✅ 應用程式查詢成功');
|
||||
console.log('應用程式數量:', response.data.apps?.length || 0);
|
||||
|
||||
if (response.data.apps && response.data.apps.length > 0) {
|
||||
console.log('第一個應用程式:', response.data.apps[0]);
|
||||
}
|
||||
} else {
|
||||
console.log('❌ 應用程式查詢失敗');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 測試失敗:', error.message);
|
||||
}
|
||||
}
|
||||
|
||||
testAppsQuery();
|
117
scripts/test-auth-detailed.js
Normal file
117
scripts/test-auth-detailed.js
Normal file
@@ -0,0 +1,117 @@
|
||||
const http = require('http');
|
||||
const jwt = require('jsonwebtoken');
|
||||
|
||||
const JWT_SECRET = process.env.JWT_SECRET || 'good777';
|
||||
|
||||
// 生成測試 Token
|
||||
function generateTestToken() {
|
||||
return jwt.sign({
|
||||
userId: 'mdxxt1xt7slle4g8wz8',
|
||||
email: 'petty091901@gmail.com',
|
||||
role: 'admin'
|
||||
}, JWT_SECRET, { expiresIn: '1h' });
|
||||
}
|
||||
|
||||
// 發送 HTTP 請求
|
||||
function makeRequest(url, method = 'GET', body = null, headers = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const urlObj = new URL(url);
|
||||
|
||||
const options = {
|
||||
hostname: urlObj.hostname,
|
||||
port: urlObj.port,
|
||||
path: urlObj.pathname,
|
||||
method: method,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...headers
|
||||
}
|
||||
};
|
||||
|
||||
console.log('發送請求到:', url);
|
||||
console.log('請求方法:', method);
|
||||
console.log('請求標頭:', options.headers);
|
||||
|
||||
const req = http.request(options, (res) => {
|
||||
let data = '';
|
||||
|
||||
res.on('data', (chunk) => {
|
||||
data += chunk;
|
||||
});
|
||||
|
||||
res.on('end', () => {
|
||||
console.log('回應狀態:', res.statusCode);
|
||||
console.log('回應標頭:', res.headers);
|
||||
|
||||
try {
|
||||
const jsonData = JSON.parse(data);
|
||||
resolve({
|
||||
status: res.statusCode,
|
||||
data: jsonData
|
||||
});
|
||||
} catch (error) {
|
||||
resolve({
|
||||
status: res.statusCode,
|
||||
data: data
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
req.on('error', (error) => {
|
||||
reject(error);
|
||||
});
|
||||
|
||||
if (body) {
|
||||
const bodyStr = JSON.stringify(body);
|
||||
console.log('請求體:', bodyStr);
|
||||
req.write(bodyStr);
|
||||
}
|
||||
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
async function testAuthDetailed() {
|
||||
try {
|
||||
console.log('🧪 詳細認證測試...');
|
||||
|
||||
// 生成測試 Token
|
||||
const token = generateTestToken();
|
||||
console.log('✅ Token 生成成功');
|
||||
console.log('Token 長度:', token.length);
|
||||
|
||||
// 驗證 Token
|
||||
const payload = jwt.verify(token, JWT_SECRET);
|
||||
console.log('✅ Token 驗證成功:', payload);
|
||||
|
||||
// 測試 GET 請求(不需要認證)
|
||||
console.log('\n1. 測試 GET /api/apps(需要認證)...');
|
||||
const getResponse = await makeRequest('http://localhost:3000/api/apps', 'GET', null, {
|
||||
'Authorization': `Bearer ${token}`
|
||||
});
|
||||
|
||||
console.log('GET 回應:', JSON.stringify(getResponse.data, null, 2));
|
||||
|
||||
// 測試 POST 請求
|
||||
console.log('\n2. 測試 POST /api/apps...');
|
||||
const appData = {
|
||||
name: '測試應用',
|
||||
description: '這是一個測試應用',
|
||||
type: 'productivity',
|
||||
demoUrl: 'https://example.com',
|
||||
version: '1.0.0'
|
||||
};
|
||||
|
||||
const postResponse = await makeRequest('http://localhost:3000/api/apps', 'POST', appData, {
|
||||
'Authorization': `Bearer ${token}`
|
||||
});
|
||||
|
||||
console.log('POST 回應:', JSON.stringify(postResponse.data, null, 2));
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 測試失敗:', error.message);
|
||||
}
|
||||
}
|
||||
|
||||
testAuthDetailed();
|
91
scripts/test-auth.js
Normal file
91
scripts/test-auth.js
Normal file
@@ -0,0 +1,91 @@
|
||||
const mysql = require('mysql2/promise');
|
||||
const jwt = require('jsonwebtoken');
|
||||
|
||||
const dbConfig = {
|
||||
host: process.env.DB_HOST || 'mysql.theaken.com',
|
||||
port: parseInt(process.env.DB_PORT || '33306'),
|
||||
user: process.env.DB_USER || 'AI_Platform',
|
||||
password: process.env.DB_PASSWORD || 'Aa123456',
|
||||
database: process.env.DB_NAME || 'db_AI_Platform',
|
||||
charset: 'utf8mb4',
|
||||
timezone: '+08:00'
|
||||
};
|
||||
|
||||
const JWT_SECRET = process.env.JWT_SECRET || 'good777';
|
||||
|
||||
async function testAuth() {
|
||||
let connection;
|
||||
|
||||
try {
|
||||
console.log('🧪 測試認證過程...');
|
||||
|
||||
connection = await mysql.createConnection(dbConfig);
|
||||
console.log('✅ 資料庫連接成功');
|
||||
|
||||
// 1. 檢查用戶是否存在
|
||||
console.log('\n1. 檢查用戶是否存在...');
|
||||
const [users] = await connection.execute(
|
||||
'SELECT id, name, email, role FROM users WHERE id = ?',
|
||||
['mdxxt1xt7slle4g8wz8']
|
||||
);
|
||||
|
||||
if (users.length === 0) {
|
||||
console.log('❌ 用戶不存在');
|
||||
return;
|
||||
}
|
||||
|
||||
const user = users[0];
|
||||
console.log('✅ 用戶存在:', user);
|
||||
|
||||
// 2. 生成 Token
|
||||
console.log('\n2. 生成 JWT Token...');
|
||||
const token = jwt.sign({
|
||||
userId: user.id,
|
||||
email: user.email,
|
||||
role: user.role
|
||||
}, JWT_SECRET, { expiresIn: '1h' });
|
||||
|
||||
console.log('✅ Token 生成成功');
|
||||
console.log('Token:', token.substring(0, 50) + '...');
|
||||
|
||||
// 3. 驗證 Token
|
||||
console.log('\n3. 驗證 JWT Token...');
|
||||
const payload = jwt.verify(token, JWT_SECRET);
|
||||
console.log('✅ Token 驗證成功:', payload);
|
||||
|
||||
// 4. 模擬認證查詢
|
||||
console.log('\n4. 模擬認證查詢...');
|
||||
const [authUser] = await connection.execute(
|
||||
'SELECT * FROM users WHERE id = ? AND email = ?',
|
||||
[payload.userId, payload.email]
|
||||
);
|
||||
|
||||
if (authUser.length === 0) {
|
||||
console.log('❌ 認證查詢失敗 - 用戶不存在');
|
||||
} else {
|
||||
console.log('✅ 認證查詢成功:', authUser[0]);
|
||||
}
|
||||
|
||||
// 5. 檢查用戶角色
|
||||
console.log('\n5. 檢查用戶角色...');
|
||||
if (authUser.length > 0) {
|
||||
const userRole = authUser[0].role;
|
||||
console.log('用戶角色:', userRole);
|
||||
|
||||
if (userRole === 'admin' || userRole === 'developer') {
|
||||
console.log('✅ 用戶有權限創建應用程式');
|
||||
} else {
|
||||
console.log('❌ 用戶沒有權限創建應用程式');
|
||||
}
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 測試失敗:', error);
|
||||
} finally {
|
||||
if (connection) {
|
||||
await connection.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
testAuth();
|
98
scripts/test-current-state.js
Normal file
98
scripts/test-current-state.js
Normal file
@@ -0,0 +1,98 @@
|
||||
const jwt = require('jsonwebtoken');
|
||||
|
||||
const JWT_SECRET = process.env.JWT_SECRET || 'good777';
|
||||
|
||||
async function testCurrentState() {
|
||||
try {
|
||||
// Generate a token for admin user
|
||||
const adminPayload = {
|
||||
id: 1,
|
||||
email: 'admin@example.com',
|
||||
role: 'admin'
|
||||
};
|
||||
const token = jwt.sign(adminPayload, JWT_SECRET, { expiresIn: '1h' });
|
||||
|
||||
console.log('=== 測試當前狀態 ===');
|
||||
|
||||
// Test 1: Get apps list with pagination
|
||||
console.log('\n1. 測試應用程式列表 (分頁)');
|
||||
const response1 = await fetch('http://localhost:3000/api/apps?page=1&limit=10', {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`
|
||||
}
|
||||
});
|
||||
|
||||
if (response1.ok) {
|
||||
const data1 = await response1.json();
|
||||
console.log('✅ API 回應成功');
|
||||
console.log(`總應用數: ${data1.pagination?.total || 'N/A'}`);
|
||||
console.log(`總頁數: ${data1.pagination?.totalPages || 'N/A'}`);
|
||||
console.log(`當前頁應用數: ${data1.apps?.length || 0}`);
|
||||
console.log('應用狀態統計:');
|
||||
const statusCounts = {};
|
||||
data1.apps?.forEach(app => {
|
||||
statusCounts[app.status] = (statusCounts[app.status] || 0) + 1;
|
||||
});
|
||||
console.log(statusCounts);
|
||||
} else {
|
||||
console.log('❌ API 回應失敗:', response1.status, response1.statusText);
|
||||
}
|
||||
|
||||
// Test 2: Create a new app as admin
|
||||
console.log('\n2. 測試管理員創建應用程式');
|
||||
const newAppData = {
|
||||
name: '測試應用程式_' + Date.now(),
|
||||
description: '這是一個測試應用程式',
|
||||
type: 'productivity',
|
||||
demoUrl: 'https://example.com',
|
||||
version: '1.0.0'
|
||||
};
|
||||
|
||||
const response2 = await fetch('http://localhost:3000/api/apps', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${token}`
|
||||
},
|
||||
body: JSON.stringify(newAppData)
|
||||
});
|
||||
|
||||
if (response2.ok) {
|
||||
const result = await response2.json();
|
||||
console.log('✅ 創建應用程式成功');
|
||||
console.log('創建的應用程式狀態:', result.app?.status);
|
||||
console.log('應用程式ID:', result.appId);
|
||||
} else {
|
||||
const errorData = await response2.json();
|
||||
console.log('❌ 創建應用程式失敗:', errorData);
|
||||
}
|
||||
|
||||
// Test 3: Get apps list again to see the new app
|
||||
console.log('\n3. 重新獲取應用程式列表');
|
||||
const response3 = await fetch('http://localhost:3000/api/apps?page=1&limit=10', {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`
|
||||
}
|
||||
});
|
||||
|
||||
if (response3.ok) {
|
||||
const data3 = await response3.json();
|
||||
console.log('✅ 重新獲取成功');
|
||||
console.log(`更新後總應用數: ${data3.pagination?.total || 'N/A'}`);
|
||||
console.log(`更新後總頁數: ${data3.pagination?.totalPages || 'N/A'}`);
|
||||
|
||||
// Find the newly created app
|
||||
const newApp = data3.apps?.find(app => app.name.includes('測試應用程式_'));
|
||||
if (newApp) {
|
||||
console.log('新創建的應用程式狀態:', newApp.status);
|
||||
}
|
||||
} else {
|
||||
console.log('❌ 重新獲取失敗:', response3.status, response3.statusText);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('測試過程中發生錯誤:', error);
|
||||
}
|
||||
}
|
||||
|
||||
testCurrentState();
|
54
scripts/test-db-connection.js
Normal file
54
scripts/test-db-connection.js
Normal file
@@ -0,0 +1,54 @@
|
||||
const mysql = require('mysql2/promise');
|
||||
|
||||
const dbConfig = {
|
||||
host: process.env.DB_HOST || 'mysql.theaken.com',
|
||||
port: parseInt(process.env.DB_PORT || '33306'),
|
||||
user: process.env.DB_USER || 'AI_Platform',
|
||||
password: process.env.DB_PASSWORD || 'Aa123456',
|
||||
database: process.env.DB_NAME || 'db_AI_Platform',
|
||||
charset: 'utf8mb4',
|
||||
timezone: '+08:00'
|
||||
};
|
||||
|
||||
async function testDBConnection() {
|
||||
let connection;
|
||||
|
||||
try {
|
||||
console.log('🧪 測試資料庫連接...');
|
||||
|
||||
connection = await mysql.createConnection(dbConfig);
|
||||
console.log('✅ 資料庫連接成功');
|
||||
|
||||
// 測試查詢用戶
|
||||
console.log('\n1. 測試查詢用戶...');
|
||||
const [users] = await connection.execute(
|
||||
'SELECT id, name, email, role FROM users WHERE id = ? AND email = ?',
|
||||
['mdxxt1xt7slle4g8wz8', 'petty091901@gmail.com']
|
||||
);
|
||||
|
||||
console.log('查詢結果:', users);
|
||||
|
||||
if (users.length > 0) {
|
||||
console.log('✅ 用戶查詢成功');
|
||||
} else {
|
||||
console.log('❌ 用戶查詢失敗 - 沒有找到用戶');
|
||||
}
|
||||
|
||||
// 測試查詢所有用戶
|
||||
console.log('\n2. 測試查詢所有用戶...');
|
||||
const [allUsers] = await connection.execute(
|
||||
'SELECT id, name, email, role FROM users LIMIT 5'
|
||||
);
|
||||
|
||||
console.log('所有用戶:', allUsers);
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 測試失敗:', error);
|
||||
} finally {
|
||||
if (connection) {
|
||||
await connection.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
testDBConnection();
|
64
scripts/test-db-query.js
Normal file
64
scripts/test-db-query.js
Normal file
@@ -0,0 +1,64 @@
|
||||
const mysql = require('mysql2/promise');
|
||||
|
||||
const dbConfig = {
|
||||
host: process.env.DB_HOST || 'mysql.theaken.com',
|
||||
port: parseInt(process.env.DB_PORT || '33306'),
|
||||
user: process.env.DB_USER || 'AI_Platform',
|
||||
password: process.env.DB_PASSWORD || 'Aa123456',
|
||||
database: process.env.DB_NAME || 'db_AI_Platform',
|
||||
charset: 'utf8mb4',
|
||||
timezone: '+08:00'
|
||||
};
|
||||
|
||||
async function testDBQuery() {
|
||||
let connection;
|
||||
|
||||
try {
|
||||
console.log('🧪 測試資料庫查詢...');
|
||||
|
||||
connection = await mysql.createConnection(dbConfig);
|
||||
console.log('✅ 資料庫連接成功');
|
||||
|
||||
// 測試 1: 簡單查詢
|
||||
console.log('\n1. 測試簡單查詢...');
|
||||
const [apps1] = await connection.execute('SELECT * FROM apps LIMIT 5');
|
||||
console.log('結果:', apps1.length, '個應用程式');
|
||||
|
||||
// 測試 2: 使用 LIMIT 查詢
|
||||
console.log('\n2. 測試 LIMIT 查詢...');
|
||||
const [apps2] = await connection.execute('SELECT * FROM apps LIMIT 5');
|
||||
console.log('結果:', apps2.length, '個應用程式');
|
||||
|
||||
// 測試 3: 使用 OFFSET
|
||||
console.log('\n3. 測試 OFFSET 查詢...');
|
||||
const [apps3] = await connection.execute('SELECT * FROM apps LIMIT 5 OFFSET 0');
|
||||
console.log('結果:', apps3.length, '個應用程式');
|
||||
|
||||
// 測試 4: 計數查詢
|
||||
console.log('\n4. 測試計數查詢...');
|
||||
const [countResult] = await connection.execute('SELECT COUNT(*) as total FROM apps');
|
||||
console.log('總數:', countResult[0].total);
|
||||
|
||||
// 測試 5: JOIN 查詢
|
||||
console.log('\n5. 測試 JOIN 查詢...');
|
||||
const [apps4] = await connection.execute(`
|
||||
SELECT
|
||||
a.*,
|
||||
u.name as creator_name,
|
||||
u.email as creator_email
|
||||
FROM apps a
|
||||
LEFT JOIN users u ON a.creator_id = u.id
|
||||
LIMIT 5
|
||||
`);
|
||||
console.log('結果:', apps4.length, '個應用程式');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 測試失敗:', error);
|
||||
} finally {
|
||||
if (connection) {
|
||||
await connection.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
testDBQuery();
|
138
scripts/test-frontend-app-creation.js
Normal file
138
scripts/test-frontend-app-creation.js
Normal file
@@ -0,0 +1,138 @@
|
||||
const mysql = require('mysql2/promise');
|
||||
|
||||
const dbConfig = {
|
||||
host: process.env.DB_HOST || 'mysql.theaken.com',
|
||||
port: parseInt(process.env.DB_PORT || '33306'),
|
||||
user: process.env.DB_USER || 'AI_Platform',
|
||||
password: process.env.DB_PASSWORD || 'Aa123456',
|
||||
database: process.env.DB_NAME || 'db_AI_Platform',
|
||||
charset: 'utf8mb4',
|
||||
timezone: '+08:00'
|
||||
};
|
||||
|
||||
async function testFrontendAppCreation() {
|
||||
let connection;
|
||||
|
||||
try {
|
||||
console.log('🧪 測試前端應用程式創建流程...');
|
||||
|
||||
connection = await mysql.createConnection(dbConfig);
|
||||
console.log('✅ 資料庫連接成功');
|
||||
|
||||
// 1. 創建測試用戶
|
||||
const userId = Date.now().toString(36) + Math.random().toString(36).substr(2);
|
||||
const userData = {
|
||||
id: userId,
|
||||
name: '測試用戶',
|
||||
email: 'test@example.com',
|
||||
password: '$2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/LewdBPj4J/HS.i8eK', // 密碼: test123
|
||||
role: 'developer',
|
||||
department: 'IT',
|
||||
join_date: new Date(),
|
||||
created_at: new Date(),
|
||||
updated_at: new Date()
|
||||
};
|
||||
|
||||
await connection.execute(
|
||||
'INSERT INTO users (id, name, email, password_hash, role, department, join_date, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)',
|
||||
[userData.id, userData.name, userData.email, userData.password, userData.role, userData.department, userData.join_date, userData.created_at, userData.updated_at]
|
||||
);
|
||||
console.log('✅ 測試用戶創建成功');
|
||||
|
||||
// 2. 模擬前端提交的應用程式資料
|
||||
const frontendAppData = {
|
||||
name: '測試前端應用',
|
||||
description: '這是一個通過前端界面創建的測試應用程式',
|
||||
type: 'productivity', // 映射自 '文字處理'
|
||||
demoUrl: 'https://example.com/demo',
|
||||
githubUrl: 'https://github.com/example/app',
|
||||
docsUrl: 'https://docs.example.com',
|
||||
techStack: ['React', 'TypeScript', 'Tailwind CSS'],
|
||||
tags: ['生產力工具', '文字處理'],
|
||||
version: '1.0.0'
|
||||
};
|
||||
|
||||
console.log('📋 前端提交的資料:', frontendAppData);
|
||||
|
||||
// 3. 創建應用程式(模擬 API 調用)
|
||||
const appId = Date.now().toString(36) + Math.random().toString(36).substr(2);
|
||||
const appData = {
|
||||
id: appId,
|
||||
name: frontendAppData.name,
|
||||
description: frontendAppData.description,
|
||||
creator_id: userId,
|
||||
team_id: null,
|
||||
type: frontendAppData.type,
|
||||
tech_stack: JSON.stringify(frontendAppData.techStack),
|
||||
tags: JSON.stringify(frontendAppData.tags),
|
||||
demo_url: frontendAppData.demoUrl,
|
||||
github_url: frontendAppData.githubUrl,
|
||||
docs_url: frontendAppData.docsUrl,
|
||||
version: frontendAppData.version,
|
||||
status: 'draft'
|
||||
};
|
||||
|
||||
await connection.execute(
|
||||
`INSERT INTO apps (
|
||||
id, name, description, creator_id, team_id, type,
|
||||
tech_stack, tags, demo_url, github_url, docs_url,
|
||||
version, status, created_at, updated_at
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())`,
|
||||
[
|
||||
appData.id, appData.name, appData.description, appData.creator_id,
|
||||
appData.team_id, appData.type, appData.tech_stack, appData.tags,
|
||||
appData.demo_url, appData.github_url, appData.docs_url,
|
||||
appData.version, appData.status
|
||||
]
|
||||
);
|
||||
console.log('✅ 應用程式創建成功');
|
||||
|
||||
// 4. 驗證應用程式是否正確保存到資料庫
|
||||
const [apps] = await connection.execute(
|
||||
`SELECT a.*, u.name as creator_name
|
||||
FROM apps a
|
||||
LEFT JOIN users u ON a.creator_id = u.id
|
||||
WHERE a.id = ?`,
|
||||
[appId]
|
||||
);
|
||||
|
||||
if (apps.length > 0) {
|
||||
const app = apps[0];
|
||||
console.log('\n📋 資料庫中的應用程式資料:');
|
||||
console.log(` ID: ${app.id}`);
|
||||
console.log(` 名稱: ${app.name}`);
|
||||
console.log(` 描述: ${app.description}`);
|
||||
console.log(` 類型: ${app.type}`);
|
||||
console.log(` 狀態: ${app.status}`);
|
||||
console.log(` 創建者: ${app.creator_name}`);
|
||||
console.log(` 技術棧: ${app.tech_stack}`);
|
||||
console.log(` 標籤: ${app.tags}`);
|
||||
console.log(` 演示連結: ${app.demo_url}`);
|
||||
console.log(` GitHub: ${app.github_url}`);
|
||||
console.log(` 文檔: ${app.docs_url}`);
|
||||
console.log(` 版本: ${app.version}`);
|
||||
console.log(` 創建時間: ${app.created_at}`);
|
||||
|
||||
console.log('\n✅ 前端應用程式創建測試成功!');
|
||||
console.log('🎯 問題已解決:前端現在可以正確創建應用程式並保存到資料庫');
|
||||
} else {
|
||||
console.log('❌ 應用程式未在資料庫中找到');
|
||||
}
|
||||
|
||||
// 5. 清理測試資料
|
||||
await connection.execute('DELETE FROM apps WHERE id = ?', [appId]);
|
||||
await connection.execute('DELETE FROM users WHERE id = ?', [userId]);
|
||||
console.log('✅ 測試資料清理完成');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 測試失敗:', error);
|
||||
} finally {
|
||||
if (connection) {
|
||||
await connection.end();
|
||||
console.log('🔌 資料庫連接已關閉');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 執行測試
|
||||
testFrontendAppCreation().catch(console.error);
|
101
scripts/test-frontend-auth.js
Normal file
101
scripts/test-frontend-auth.js
Normal file
@@ -0,0 +1,101 @@
|
||||
const http = require('http');
|
||||
const jwt = require('jsonwebtoken');
|
||||
|
||||
const JWT_SECRET = process.env.JWT_SECRET || 'good777';
|
||||
|
||||
// 生成測試 Token
|
||||
function generateTestToken() {
|
||||
return jwt.sign({
|
||||
userId: 'mdxxt1xt7slle4g8wz8',
|
||||
email: 'petty091901@gmail.com',
|
||||
role: 'admin'
|
||||
}, JWT_SECRET, { expiresIn: '1h' });
|
||||
}
|
||||
|
||||
// 模擬瀏覽器的 localStorage
|
||||
const mockLocalStorage = {
|
||||
token: generateTestToken()
|
||||
};
|
||||
|
||||
console.log('🧪 測試前端認證狀態...');
|
||||
console.log('Token 存在:', !!mockLocalStorage.token);
|
||||
console.log('Token 長度:', mockLocalStorage.token.length);
|
||||
|
||||
function makeRequest(url, method = 'GET', headers = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const urlObj = new URL(url);
|
||||
|
||||
const options = {
|
||||
hostname: urlObj.hostname,
|
||||
port: urlObj.port,
|
||||
path: urlObj.pathname,
|
||||
method: method,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...headers
|
||||
}
|
||||
};
|
||||
|
||||
const req = http.request(options, (res) => {
|
||||
let data = '';
|
||||
|
||||
res.on('data', (chunk) => {
|
||||
data += chunk;
|
||||
});
|
||||
|
||||
res.on('end', () => {
|
||||
try {
|
||||
const jsonData = JSON.parse(data);
|
||||
resolve({
|
||||
status: res.statusCode,
|
||||
data: jsonData
|
||||
});
|
||||
} catch (error) {
|
||||
resolve({
|
||||
status: res.statusCode,
|
||||
data: data
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
req.on('error', (error) => {
|
||||
reject(error);
|
||||
});
|
||||
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
async function testFrontendAPI() {
|
||||
try {
|
||||
console.log('\n🧪 測試前端 API 調用...');
|
||||
|
||||
const response = await makeRequest('http://localhost:3000/api/apps', 'GET', {
|
||||
'Authorization': `Bearer ${mockLocalStorage.token}`
|
||||
});
|
||||
|
||||
if (response.status === 200) {
|
||||
console.log('✅ API 調用成功');
|
||||
console.log('應用程式數量:', response.data.apps?.length || 0);
|
||||
|
||||
if (response.data.apps && response.data.apps.length > 0) {
|
||||
const app = response.data.apps[0];
|
||||
console.log('第一個應用程式範例:');
|
||||
console.log('- ID:', app.id);
|
||||
console.log('- 名稱:', app.name);
|
||||
console.log('- 創建者:', app.creator?.name);
|
||||
console.log('- 部門:', app.creator?.department);
|
||||
console.log('- 狀態:', app.status);
|
||||
console.log('- 類型:', app.type);
|
||||
}
|
||||
} else {
|
||||
console.log('❌ API 調用失敗:', response.status);
|
||||
console.log('回應:', response.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ 測試失敗:', error.message);
|
||||
}
|
||||
}
|
||||
|
||||
testFrontendAPI();
|
128
scripts/test-frontend-fixes.js
Normal file
128
scripts/test-frontend-fixes.js
Normal file
@@ -0,0 +1,128 @@
|
||||
const jwt = require('jsonwebtoken');
|
||||
|
||||
const JWT_SECRET = process.env.JWT_SECRET || 'good777';
|
||||
|
||||
async function testFrontendFixes() {
|
||||
try {
|
||||
// Generate a token for admin user
|
||||
const adminPayload = {
|
||||
userId: 'admin-001',
|
||||
email: 'admin@theaken.com',
|
||||
role: 'admin'
|
||||
};
|
||||
const token = jwt.sign(adminPayload, JWT_SECRET, { expiresIn: '1h' });
|
||||
|
||||
console.log('=== 測試前端修復 ===');
|
||||
|
||||
// Test 1: Get apps list with pagination
|
||||
console.log('\n1. 測試應用程式列表 (分頁)');
|
||||
const response1 = await fetch('http://localhost:3000/api/apps?page=1&limit=10', {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`
|
||||
}
|
||||
});
|
||||
|
||||
if (response1.ok) {
|
||||
const data1 = await response1.json();
|
||||
console.log('✅ API 回應成功');
|
||||
console.log(`總應用數: ${data1.pagination?.total || 'N/A'}`);
|
||||
console.log(`總頁數: ${data1.pagination?.totalPages || 'N/A'}`);
|
||||
console.log(`當前頁應用數: ${data1.apps?.length || 0}`);
|
||||
console.log('統計資訊:', data1.stats);
|
||||
|
||||
// 模擬前端數據轉換
|
||||
const formattedApps = (data1.apps || []).map((app) => ({
|
||||
...app,
|
||||
creator: app.creator?.name || '未知',
|
||||
department: app.creator?.department || '未知',
|
||||
views: app.viewsCount || 0,
|
||||
likes: app.likesCount || 0,
|
||||
appUrl: app.demoUrl || '',
|
||||
type: mapApiTypeToDisplayType(app.type),
|
||||
icon: 'Bot',
|
||||
iconColor: 'from-blue-500 to-purple-500',
|
||||
reviews: 0,
|
||||
createdAt: app.createdAt ? new Date(app.createdAt).toLocaleDateString() : '未知'
|
||||
}));
|
||||
|
||||
console.log('\n模擬前端統計:');
|
||||
console.log(`總應用數 (totalApps): ${data1.pagination?.total}`);
|
||||
console.log(`已發布: ${data1.stats?.published || 0}`);
|
||||
console.log(`待審核: ${data1.stats?.pending || 0}`);
|
||||
console.log(`草稿: ${data1.stats?.draft || 0}`);
|
||||
console.log(`已拒絕: ${data1.stats?.rejected || 0}`);
|
||||
|
||||
// 檢查分頁是否應該顯示
|
||||
const shouldShowPagination = data1.pagination?.totalPages > 1;
|
||||
console.log(`\n分頁是否應該顯示: ${shouldShowPagination} (總頁數: ${data1.pagination?.totalPages})`);
|
||||
|
||||
} else {
|
||||
console.log('❌ API 回應失敗:', response1.status, response1.statusText);
|
||||
}
|
||||
|
||||
// Test 2: Create a new app as admin
|
||||
console.log('\n2. 測試管理員創建應用程式');
|
||||
const newAppData = {
|
||||
name: '測試應用程式_' + Date.now(),
|
||||
description: '這是一個測試應用程式',
|
||||
type: 'productivity',
|
||||
demoUrl: 'https://example.com',
|
||||
version: '1.0.0'
|
||||
};
|
||||
|
||||
const response2 = await fetch('http://localhost:3000/api/apps', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${token}`
|
||||
},
|
||||
body: JSON.stringify(newAppData)
|
||||
});
|
||||
|
||||
if (response2.ok) {
|
||||
const result = await response2.json();
|
||||
console.log('✅ 創建應用程式成功');
|
||||
console.log('創建的應用程式狀態:', result.app?.status);
|
||||
console.log('應用程式ID:', result.appId);
|
||||
|
||||
// 檢查狀態是否正確 (應該是 draft)
|
||||
if (result.app?.status === 'draft') {
|
||||
console.log('✅ 狀態正確: 管理員創建的應用程式狀態為 draft');
|
||||
} else {
|
||||
console.log('❌ 狀態錯誤: 管理員創建的應用程式狀態應該為 draft,但實際為', result.app?.status);
|
||||
}
|
||||
} else {
|
||||
const errorData = await response2.json();
|
||||
console.log('❌ 創建應用程式失敗:', errorData);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('測試過程中發生錯誤:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// 模擬前端的類型轉換函數
|
||||
function mapApiTypeToDisplayType(apiType) {
|
||||
const typeMap = {
|
||||
'productivity': '文字處理',
|
||||
'ai_model': '圖像生成',
|
||||
'automation': '程式開發',
|
||||
'data_analysis': '數據分析',
|
||||
'educational': '教育工具',
|
||||
'healthcare': '健康醫療',
|
||||
'finance': '金融科技',
|
||||
'iot_device': '物聯網',
|
||||
'blockchain': '區塊鏈',
|
||||
'ar_vr': 'AR/VR',
|
||||
'machine_learning': '機器學習',
|
||||
'computer_vision': '電腦視覺',
|
||||
'nlp': '自然語言處理',
|
||||
'robotics': '機器人',
|
||||
'cybersecurity': '網路安全',
|
||||
'cloud_service': '雲端服務',
|
||||
'other': '其他'
|
||||
};
|
||||
return typeMap[apiType] || '其他';
|
||||
}
|
||||
|
||||
testFrontendFixes();
|
87
scripts/test-login.js
Normal file
87
scripts/test-login.js
Normal file
@@ -0,0 +1,87 @@
|
||||
const http = require('http');
|
||||
const jwt = require('jsonwebtoken');
|
||||
|
||||
const JWT_SECRET = process.env.JWT_SECRET || 'good777';
|
||||
|
||||
// 測試登入
|
||||
function testLogin(email, password) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const postData = JSON.stringify({
|
||||
email: email,
|
||||
password: password
|
||||
});
|
||||
|
||||
const options = {
|
||||
hostname: 'localhost',
|
||||
port: 3000,
|
||||
path: '/api/auth/login',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Content-Length': Buffer.byteLength(postData)
|
||||
}
|
||||
};
|
||||
|
||||
const req = http.request(options, (res) => {
|
||||
let data = '';
|
||||
|
||||
res.on('data', (chunk) => {
|
||||
data += chunk;
|
||||
});
|
||||
|
||||
res.on('end', () => {
|
||||
try {
|
||||
const jsonData = JSON.parse(data);
|
||||
resolve({
|
||||
status: res.statusCode,
|
||||
data: jsonData
|
||||
});
|
||||
} catch (error) {
|
||||
resolve({
|
||||
status: res.statusCode,
|
||||
data: data
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
req.on('error', (error) => {
|
||||
reject(error);
|
||||
});
|
||||
|
||||
req.write(postData);
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
async function testLogins() {
|
||||
console.log('🧪 測試登入...');
|
||||
|
||||
const testUsers = [
|
||||
{ email: 'admin@theaken.com', password: 'Admin123' },
|
||||
{ email: 'admin@example.com', password: 'Admin123' },
|
||||
{ email: 'petty091901@gmail.com', password: 'Admin123' },
|
||||
{ email: 'test@theaken.com', password: 'Test123' },
|
||||
{ email: 'test@example.com', password: 'Test123' }
|
||||
];
|
||||
|
||||
for (const user of testUsers) {
|
||||
try {
|
||||
console.log(`\n測試用戶: ${user.email}`);
|
||||
const response = await testLogin(user.email, user.password);
|
||||
|
||||
if (response.status === 200) {
|
||||
console.log('✅ 登入成功');
|
||||
console.log('用戶資訊:', response.data.user);
|
||||
console.log('Token 長度:', response.data.token?.length || 0);
|
||||
} else {
|
||||
console.log('❌ 登入失敗');
|
||||
console.log('錯誤:', response.data.error);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ 測試失敗:', error.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
testLogins();
|
54
scripts/test-pagination.js
Normal file
54
scripts/test-pagination.js
Normal file
@@ -0,0 +1,54 @@
|
||||
const jwt = require('jsonwebtoken');
|
||||
|
||||
async function testPagination() {
|
||||
console.log('🧪 測試分頁功能...');
|
||||
|
||||
// 生成測試 token
|
||||
const token = jwt.sign(
|
||||
{ userId: 'admin-001', role: 'admin' },
|
||||
process.env.JWT_SECRET || 'good777',
|
||||
{ expiresIn: '1h' }
|
||||
);
|
||||
|
||||
console.log('✅ Token 生成成功\n');
|
||||
|
||||
// 測試不同的分頁參數
|
||||
const testCases = [
|
||||
{ page: 1, limit: 3, description: '第1頁,每頁3筆' },
|
||||
{ page: 2, limit: 3, description: '第2頁,每頁3筆' },
|
||||
{ page: 1, limit: 5, description: '第1頁,每頁5筆' },
|
||||
{ page: 1, limit: 10, description: '第1頁,每頁10筆' }
|
||||
];
|
||||
|
||||
for (const testCase of testCases) {
|
||||
console.log(`\n${testCase.description}:`);
|
||||
|
||||
try {
|
||||
const params = new URLSearchParams({
|
||||
page: testCase.page.toString(),
|
||||
limit: testCase.limit.toString()
|
||||
});
|
||||
|
||||
const response = await fetch(`http://localhost:3000/api/apps?${params}`, {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`
|
||||
}
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
console.log(` 狀態碼: ${response.status}`);
|
||||
console.log(` 應用程式數量: ${data.apps.length}`);
|
||||
console.log(` 分頁資訊:`, data.pagination);
|
||||
} else {
|
||||
console.log(` 錯誤: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(` 請求失敗: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('\n✅ 分頁測試完成');
|
||||
}
|
||||
|
||||
testPagination();
|
63
scripts/test-simple-query.js
Normal file
63
scripts/test-simple-query.js
Normal file
@@ -0,0 +1,63 @@
|
||||
const mysql = require('mysql2/promise');
|
||||
|
||||
const dbConfig = {
|
||||
host: process.env.DB_HOST || 'mysql.theaken.com',
|
||||
port: parseInt(process.env.DB_PORT || '33306'),
|
||||
user: process.env.DB_USER || 'AI_Platform',
|
||||
password: process.env.DB_PASSWORD || 'Aa123456',
|
||||
database: process.env.DB_NAME || 'db_AI_Platform',
|
||||
charset: 'utf8mb4',
|
||||
timezone: '+08:00'
|
||||
};
|
||||
|
||||
async function testSimpleQuery() {
|
||||
let connection;
|
||||
|
||||
try {
|
||||
console.log('🧪 測試簡單查詢...');
|
||||
|
||||
connection = await mysql.createConnection(dbConfig);
|
||||
console.log('✅ 資料庫連接成功');
|
||||
|
||||
// 測試 1: 簡單的 apps 查詢
|
||||
console.log('\n1. 測試簡單的 apps 查詢...');
|
||||
const [apps1] = await connection.execute('SELECT * FROM apps LIMIT 5');
|
||||
console.log('結果:', apps1.length, '個應用程式');
|
||||
|
||||
// 測試 2: 帶 JOIN 的查詢
|
||||
console.log('\n2. 測試帶 JOIN 的查詢...');
|
||||
const [apps2] = await connection.execute(`
|
||||
SELECT
|
||||
a.*,
|
||||
u.name as creator_name,
|
||||
u.email as creator_email
|
||||
FROM apps a
|
||||
LEFT JOIN users u ON a.creator_id = u.id
|
||||
LIMIT 5
|
||||
`);
|
||||
console.log('結果:', apps2.length, '個應用程式');
|
||||
|
||||
// 測試 3: 帶參數的查詢
|
||||
console.log('\n3. 測試帶參數的查詢...');
|
||||
const [apps3] = await connection.execute(`
|
||||
SELECT * FROM apps
|
||||
WHERE creator_id = ?
|
||||
LIMIT ?
|
||||
`, ['mdxxt1xt7slle4g8wz8', 5]);
|
||||
console.log('結果:', apps3.length, '個應用程式');
|
||||
|
||||
// 測試 4: 計數查詢
|
||||
console.log('\n4. 測試計數查詢...');
|
||||
const [countResult] = await connection.execute('SELECT COUNT(*) as total FROM apps');
|
||||
console.log('總數:', countResult[0].total);
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 測試失敗:', error);
|
||||
} finally {
|
||||
if (connection) {
|
||||
await connection.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
testSimpleQuery();
|
31
scripts/test-type-conversion.js
Normal file
31
scripts/test-type-conversion.js
Normal file
@@ -0,0 +1,31 @@
|
||||
// 測試類型轉換函數
|
||||
const mapApiTypeToDisplayType = (apiType) => {
|
||||
const typeMap = {
|
||||
'productivity': '文字處理',
|
||||
'ai_model': '圖像生成',
|
||||
'automation': '程式開發',
|
||||
'data_analysis': '數據分析',
|
||||
'educational': '教育工具',
|
||||
'healthcare': '健康醫療',
|
||||
'finance': '金融科技',
|
||||
'iot_device': '物聯網',
|
||||
'blockchain': '區塊鏈',
|
||||
'ar_vr': 'AR/VR',
|
||||
'machine_learning': '機器學習',
|
||||
'computer_vision': '電腦視覺',
|
||||
'nlp': '自然語言處理',
|
||||
'robotics': '機器人',
|
||||
'cybersecurity': '網路安全',
|
||||
'cloud_service': '雲端服務',
|
||||
'other': '其他'
|
||||
}
|
||||
return typeMap[apiType] || '其他'
|
||||
}
|
||||
|
||||
// 測試轉換
|
||||
console.log('🧪 測試類型轉換...')
|
||||
console.log('productivity ->', mapApiTypeToDisplayType('productivity'))
|
||||
console.log('ai_model ->', mapApiTypeToDisplayType('ai_model'))
|
||||
console.log('automation ->', mapApiTypeToDisplayType('automation'))
|
||||
console.log('unknown ->', mapApiTypeToDisplayType('unknown'))
|
||||
console.log('✅ 類型轉換測試完成')
|
77
scripts/test-user-permissions.js
Normal file
77
scripts/test-user-permissions.js
Normal file
@@ -0,0 +1,77 @@
|
||||
const mysql = require('mysql2/promise');
|
||||
|
||||
const dbConfig = {
|
||||
host: process.env.DB_HOST || 'mysql.theaken.com',
|
||||
port: parseInt(process.env.DB_PORT || '33306'),
|
||||
user: process.env.DB_USER || 'AI_Platform',
|
||||
password: process.env.DB_PASSWORD || 'Aa123456',
|
||||
database: process.env.DB_NAME || 'db_AI_Platform',
|
||||
charset: 'utf8mb4',
|
||||
timezone: '+08:00'
|
||||
};
|
||||
|
||||
async function testUserPermissions() {
|
||||
let connection;
|
||||
try {
|
||||
console.log('🧪 測試用戶權限和認證狀態...');
|
||||
connection = await mysql.createConnection(dbConfig);
|
||||
console.log('✅ 資料庫連接成功');
|
||||
|
||||
// 檢查現有用戶
|
||||
const [users] = await connection.execute('SELECT id, name, email, role, department FROM users ORDER BY created_at DESC LIMIT 5');
|
||||
|
||||
console.log('\n📋 資料庫中的用戶列表:');
|
||||
users.forEach((user, index) => {
|
||||
console.log(` ${index + 1}. ${user.name} (${user.email}) - 角色: ${user.role} - 部門: ${user.department}`);
|
||||
});
|
||||
|
||||
// 檢查應用程式
|
||||
const [apps] = await connection.execute('SELECT id, name, creator_id, type, status FROM apps ORDER BY created_at DESC LIMIT 5');
|
||||
|
||||
console.log('\n📋 資料庫中的應用程式列表:');
|
||||
apps.forEach((app, index) => {
|
||||
console.log(` ${index + 1}. ${app.name} - 創建者: ${app.creator_id} - 類型: ${app.type} - 狀態: ${app.status}`);
|
||||
});
|
||||
|
||||
// 創建一個管理員用戶用於測試
|
||||
const adminUserData = {
|
||||
id: 'admin-test-' + Date.now(),
|
||||
name: '測試管理員',
|
||||
email: 'admin-test@example.com',
|
||||
password_hash: 'test_hash',
|
||||
department: 'ITBU',
|
||||
role: 'admin',
|
||||
join_date: new Date(),
|
||||
created_at: new Date(),
|
||||
updated_at: new Date()
|
||||
};
|
||||
|
||||
await connection.execute(
|
||||
'INSERT INTO users (id, name, email, password_hash, department, role, join_date, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)',
|
||||
[adminUserData.id, adminUserData.name, adminUserData.email, adminUserData.password_hash, adminUserData.department, adminUserData.role, adminUserData.join_date, adminUserData.created_at, adminUserData.updated_at]
|
||||
);
|
||||
console.log('\n✅ 測試管理員用戶創建成功');
|
||||
|
||||
// 模擬 API 調用
|
||||
console.log('\n🧪 模擬 API 調用測試...');
|
||||
|
||||
// 這裡我們需要模擬一個有效的 JWT token
|
||||
// 在實際環境中,這個 token 應該通過登入 API 獲得
|
||||
console.log('💡 提示:要測試 API 調用,需要先通過登入 API 獲得有效的 JWT token');
|
||||
console.log('💡 建議:在瀏覽器中登入管理後台,然後檢查 localStorage 中的 token');
|
||||
|
||||
// 清理測試資料
|
||||
await connection.execute('DELETE FROM users WHERE id = ?', [adminUserData.id]);
|
||||
console.log('✅ 測試資料清理完成');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 測試失敗:', error.message);
|
||||
} finally {
|
||||
if (connection) {
|
||||
await connection.end();
|
||||
console.log('🔌 資料庫連接已關閉');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
testUserPermissions().catch(console.error);
|
70
scripts/update-app-types.js
Normal file
70
scripts/update-app-types.js
Normal file
@@ -0,0 +1,70 @@
|
||||
const mysql = require('mysql2/promise');
|
||||
|
||||
const dbConfig = {
|
||||
host: process.env.DB_HOST || 'mysql.theaken.com',
|
||||
port: parseInt(process.env.DB_PORT || '33306'),
|
||||
user: process.env.DB_USER || 'AI_Platform',
|
||||
password: process.env.DB_PASSWORD || 'Aa123456',
|
||||
database: process.env.DB_NAME || 'db_AI_Platform',
|
||||
charset: 'utf8mb4',
|
||||
timezone: '+08:00'
|
||||
};
|
||||
|
||||
async function updateAppTypes() {
|
||||
let connection;
|
||||
try {
|
||||
connection = await mysql.createConnection(dbConfig);
|
||||
console.log('✅ 資料庫連接成功');
|
||||
|
||||
// 更新 ENUM 類型,移除不適合企業平台的類型
|
||||
const updateTypeEnum = `
|
||||
ALTER TABLE apps MODIFY COLUMN type ENUM(
|
||||
'web_app', 'mobile_app', 'desktop_app', 'api_service', 'ai_model',
|
||||
'data_analysis', 'automation', 'productivity', 'educational', 'healthcare',
|
||||
'finance', 'iot_device', 'blockchain', 'ar_vr', 'machine_learning',
|
||||
'computer_vision', 'nlp', 'robotics', 'cybersecurity', 'cloud_service', 'other'
|
||||
) DEFAULT 'other'
|
||||
`;
|
||||
|
||||
await connection.execute(updateTypeEnum);
|
||||
console.log('✅ 應用程式類型 ENUM 更新成功');
|
||||
|
||||
// 查看更新後的結構
|
||||
const [describeResult] = await connection.execute('DESCRIBE apps');
|
||||
console.log('\n📋 更新後的 apps 表結構:');
|
||||
describeResult.forEach(row => {
|
||||
if (row.Field === 'type') {
|
||||
console.log(` ${row.Field}: ${row.Type}`);
|
||||
}
|
||||
});
|
||||
|
||||
// 列出所有有效的類型
|
||||
console.log('\n🎯 有效的應用程式類型:');
|
||||
const validTypes = [
|
||||
'web_app', 'mobile_app', 'desktop_app', 'api_service', 'ai_model',
|
||||
'data_analysis', 'automation', 'productivity', 'educational', 'healthcare',
|
||||
'finance', 'iot_device', 'blockchain', 'ar_vr', 'machine_learning',
|
||||
'computer_vision', 'nlp', 'robotics', 'cybersecurity', 'cloud_service', 'other'
|
||||
];
|
||||
validTypes.forEach((type, index) => {
|
||||
console.log(` ${index + 1}. ${type}`);
|
||||
});
|
||||
|
||||
console.log('\n✅ 企業 AI 平台應用類型更新完成!');
|
||||
console.log('🎯 已移除遊戲、娛樂、社交媒體等不適合企業平台的類型');
|
||||
console.log('📈 新增了更多適合企業 AI 應用的類型');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 更新失敗:', error.message);
|
||||
if (error.code === 'ER_DUP_FIELDNAME') {
|
||||
console.log('💡 提示:某些欄位可能已存在,這是正常的');
|
||||
}
|
||||
} finally {
|
||||
if (connection) {
|
||||
await connection.end();
|
||||
console.log('🔌 資料庫連接已關閉');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateAppTypes().catch(console.error);
|
Reference in New Issue
Block a user