This commit is contained in:
2026-03-31 10:20:27 +07:00
parent 18bf19a090
commit 209b68c3f5
12 changed files with 1237 additions and 196 deletions

136
server.js
View File

@@ -10,6 +10,17 @@ const app = express();
app.use(cors());
app.use(express.json());
// Serve static files
const path = require('path');
app.use(express.static(path.join(__dirname, 'pages')));
app.use(express.static(path.join(__dirname, 'js')));
app.use(express.static(path.join(__dirname)));
// Root route
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, 'pages', 'login.html'));
});
// SQL Server Configuration
const sqlConfig = {
server: '172.20.235.176',
@@ -17,14 +28,15 @@ const sqlConfig = {
type: 'default',
options: {
userName: 'sa',
password: 'robotics@2020'
password: 'robotics@2022'
}
},
options: {
database: 'AccManager',
trustServerCertificate: true,
enableKeepAlive: true,
connectTimeout: 30000
connectTimeout: 30000,
encrypt: false
}
};
@@ -40,8 +52,8 @@ async function initializeDatabase() {
// Check and create database if not exists
const masterConnection = new sql.ConnectionPool({
server: '172.20.235.176',
authentication: { type: 'default', options: { userName: 'sa', password: 'robotics@2020' } },
options: { connectTimeout: 30000, database: 'master', trustServerCertificate: true }
authentication: { type: 'default', options: { userName: 'sa', password: 'robotics@2022' } },
options: { connectTimeout: 30000, database: 'master', trustServerCertificate: true, encrypt: false }
});
await masterConnection.connect();
@@ -91,6 +103,7 @@ async function createTables() {
Status NVARCHAR(20) DEFAULT 'online',
Icon NVARCHAR(50),
Description NVARCHAR(500),
Url NVARCHAR(255),
CreatedDate DATETIME DEFAULT GETDATE(),
UpdatedDate DATETIME DEFAULT GETDATE()
)
@@ -141,6 +154,16 @@ async function createTables() {
}
}
// Ensure new columns exist on Applications for migrations
try {
await pool.request().query(`IF COL_LENGTH('dbo.Applications','Url') IS NULL ALTER TABLE Applications ADD Url NVARCHAR(255);`);
await pool.request().query(`IF COL_LENGTH('dbo.Applications','Description') IS NULL ALTER TABLE Applications ADD Description NVARCHAR(500);`);
// Backfill Url to empty string to avoid undefined in responses
await pool.request().query(`UPDATE Applications SET Url = '' WHERE Url IS NULL;`);
} catch (err) {
console.error('Column addition error (Applications):', err.message);
}
// Insert initial admin user
try {
await pool.request()
@@ -162,12 +185,12 @@ async function createTables() {
await pool.request()
.query(`IF (SELECT COUNT(*) FROM Applications) = 0
BEGIN
INSERT INTO Applications (Name, Type, Status, Icon, Description)
INSERT INTO Applications (Name, Type, Status, Icon, Description, Url)
VALUES
('AWS', 'Cloud', 'online', 'cloud', 'Amazon Web Services'),
('GitHub', 'VCS', 'online', 'code', 'GitHub - Version Control'),
('Google Workspace', 'Collaboration', 'online', 'mail', 'Google Workspace'),
('Nginx Proxy', 'Infra', 'offline', 'dns', 'Nginx Web Server')
('AWS', 'Cloud', 'online', 'cloud', 'Amazon Web Services', 'https://aws.amazon.com'),
('GitHub', 'VCS', 'online', 'code', 'GitHub - Version Control', 'https://github.com'),
('Google Workspace', 'Collaboration', 'online', 'mail', 'Google Workspace', 'https://workspace.google.com'),
('Nginx Proxy', 'Infra', 'offline', 'dns', 'Nginx Web Server', 'https://nginx.org')
END`);
console.log('✓ Sample applications created');
} catch (err) {
@@ -275,7 +298,7 @@ app.post('/api/users', async (req, res) => {
app.get('/api/applications', async (req, res) => {
try {
const result = await pool.request()
.query('SELECT * FROM Applications ORDER BY Name');
.query('SELECT AppId, Name, Type, Status, Icon, Description, Url, CreatedDate, UpdatedDate FROM Applications ORDER BY Name');
res.json({ success: true, data: result.recordset });
} catch (err) {
res.status(500).json({ success: false, message: err.message });
@@ -285,7 +308,7 @@ app.get('/api/applications', async (req, res) => {
// Create application
app.post('/api/applications', async (req, res) => {
try {
const { name, type, status, icon, description } = req.body;
const { name, type, status, icon, description, url } = req.body;
const result = await pool.request()
.input('name', sql.NVarChar, name)
@@ -293,8 +316,9 @@ app.post('/api/applications', async (req, res) => {
.input('status', sql.NVarChar, status)
.input('icon', sql.NVarChar, icon)
.input('description', sql.NVarChar, description)
.query(`INSERT INTO Applications (Name, Type, Status, Icon, Description)
VALUES (@name, @type, @status, @icon, @description);
.input('url', sql.NVarChar, url)
.query(`INSERT INTO Applications (Name, Type, Status, Icon, Description, Url)
VALUES (@name, @type, @status, @icon, @description, @url);
SELECT SCOPE_IDENTITY() as AppId`);
res.json({ success: true, message: 'Application created', appId: result.recordset[0].AppId });
@@ -303,6 +327,48 @@ app.post('/api/applications', async (req, res) => {
}
});
// Update application
app.put('/api/applications/:id', async (req, res) => {
try {
const { name, type, status, icon, description, url } = req.body;
await pool.request()
.input('appId', sql.Int, req.params.id)
.input('name', sql.NVarChar, name)
.input('type', sql.NVarChar, type)
.input('status', sql.NVarChar, status)
.input('icon', sql.NVarChar, icon)
.input('description', sql.NVarChar, description)
.input('url', sql.NVarChar, url)
.query(`UPDATE Applications
SET Name = @name,
Type = @type,
Status = @status,
Icon = @icon,
Description = @description,
Url = @url,
UpdatedDate = GETDATE()
WHERE AppId = @appId`);
res.json({ success: true, message: 'Application updated' });
} catch (err) {
res.status(500).json({ success: false, message: err.message });
}
});
// Delete application
app.delete('/api/applications/:id', async (req, res) => {
try {
await pool.request()
.input('appId', sql.Int, req.params.id)
.query('DELETE FROM Applications WHERE AppId = @appId');
res.json({ success: true, message: 'Application deleted' });
} catch (err) {
res.status(500).json({ success: false, message: err.message });
}
});
// ==========================================
// API ROUTES - Accounts
// ==========================================
@@ -346,6 +412,50 @@ app.post('/api/accounts', async (req, res) => {
}
});
// Update account
app.put('/api/accounts/:id', async (req, res) => {
try {
const { userId, appId, accountUsername, accountPassword, email, accessLevel, notes } = req.body;
await pool.request()
.input('accountId', sql.Int, req.params.id)
.input('userId', sql.Int, userId)
.input('appId', sql.Int, appId)
.input('accountUsername', sql.NVarChar, accountUsername)
.input('accountPassword', sql.NVarChar, accountPassword)
.input('email', sql.NVarChar, email)
.input('accessLevel', sql.NVarChar, accessLevel)
.input('notes', sql.NVarChar, notes)
.query(`UPDATE Accounts
SET UserId = @userId,
AppId = @appId,
AccountUsername = @accountUsername,
AccountPassword = @accountPassword,
Email = @email,
AccessLevel = @accessLevel,
Notes = @notes,
UpdatedDate = GETDATE()
WHERE AccountId = @accountId`);
res.json({ success: true, message: 'Account updated' });
} catch (err) {
res.status(500).json({ success: false, message: err.message });
}
});
// Delete account
app.delete('/api/accounts/:id', async (req, res) => {
try {
await pool.request()
.input('accountId', sql.Int, req.params.id)
.query('DELETE FROM Accounts WHERE AccountId = @accountId');
res.json({ success: true, message: 'Account deleted' });
} catch (err) {
res.status(500).json({ success: false, message: err.message });
}
});
// ==========================================
// API ROUTES - Database Info
// ==========================================