diff --git a/Api/Controllers/poamUpload.controller.js b/Api/Controllers/Import.js similarity index 60% rename from Api/Controllers/poamUpload.controller.js rename to Api/Controllers/Import.js index 31e5c62d..64fd3a42 100644 --- a/Api/Controllers/poamUpload.controller.js +++ b/Api/Controllers/Import.js @@ -1,15 +1,18 @@ /* !####################################################################### ! C-PATTM SOFTWARE -! CRANE C-PATTM plan of action and milestones software. Use is governed by the Open Source Academic Research License Agreement contained in the file +! CRANE C-PATTM plan of action and milestones software. Use is governed by the +! Open Source Academic Research License Agreement contained in the file ! crane_C_PAT.1_license.txt, which is part of this software package. BY ! USING OR MODIFYING THIS SOFTWARE, YOU ARE AGREEING TO THE TERMS AND ! CONDITIONS OF THE LICENSE. !######################################################################## */ +const express = require('express'); +const db = require('../utils/sequelize'); +const router = express.Router(); const ExcelJS = require('exceljs'); -const { db } = require('../utils/sequelize.js'); const { poamAsset, Poam } = require('../utils/sequelize.js'); const excelColumnToDbColumnMapping = { @@ -57,7 +60,7 @@ function convertToMySQLDate(excelDate) { return convertedDate; } -exports.uploadPoamFile = async (req, res) => { +module.exports.uploadPoamFile = exports.uploadPoamFile = async (req, res) => { if (!req.file) { return res.status(400).send({ message: "Please upload an Excel file!" }); } @@ -120,8 +123,8 @@ exports.uploadPoamFile = async (req, res) => { const createdBatch = await Poam.bulkCreate(batch, { returning: true }); createdPoams.push(...createdBatch); } - // Process devicesAffected for each createdPoam... - for (const poamEntry of createdPoams) { + // Process devicesAffected for each createdPoam... + for (const poamEntry of createdPoams) { if (!poamEntry || !poamEntry.poamId) { console.error('Invalid poamEntry or missing poamId:', poamEntry); continue; @@ -151,4 +154,94 @@ exports.uploadPoamFile = async (req, res) => { error: error.message, }); } -}; \ No newline at end of file +} +module.exports.importAssets = async function importAssets(req, res) { + try { + const { assets } = req.body; + + // Handle Assets + for (const asset of assets) { + const collection = asset.collection || {}; + const assetData = { + assetId: asset.assetId, + assetName: asset.name, + fullyQualifiedDomainName: asset.fqdn || '', + description: asset.description || '', + ipAddress: asset.ip || '', + macAddress: asset.mac || '', + nonComputing: asset.noncomputing ? 1 : 0, + collectionId: collection.collectionId || null, + metadata: asset.metadata ? JSON.stringify(asset.metadata) : '{}', + }; + + // Find or create the asset + const [assetRecord, assetCreated] = await db.Asset.findOrCreate({ + where: { assetName: asset.name }, + defaults: assetData + }); + + if (!assetCreated) { + await assetRecord.update(assetData); + } + } + + res.status(200).json({ message: 'Assets Imported Successfully' }); + } catch (error) { + console.error(error); + res.status(500).json({ message: 'Internal Server Error' }); + } +} + +module.exports.importCollectionAndAssets = async function importCollectionAndAssets(req, res) { + try { + const { collection, assets } = req.body; + + // Handle Collection + const collectionData = { + collectionId: collection.collectionId, + collectionName: collection.name, + description: collection.description || '', + metadata: collection.metadata ? JSON.stringify(collection.metadata) : '{}', + settings: collection.settings ? JSON.stringify(collection.settings) : '{}' + }; + + const [collectionRecord, created] = await db.Collection.findOrCreate({ + where: { collectionName: collection.name }, + defaults: collectionData + }); + + if (!created) { + await collectionRecord.update(collectionData); + } + + // Handle Assets + for (const asset of assets) { + const assetData = { + assetId: asset.assetId, + assetName: asset.name, + fullyQualifiedDomainName: asset.fqdn || '', + description: asset.description || '', + ipAddress: asset.ip || '', + macAddress: asset.mac || '', + nonComputing: asset.noncomputing ? 1 : 0, + collectionId: collectionRecord.collectionId, // Ensure this is correctly assigned + metadata: asset.metadata ? JSON.stringify(asset.metadata) : '{}', + }; + + const [assetRecord, assetCreated] = await db.Asset.findOrCreate({ + where: { assetName: asset.name }, // Assuming assetName is unique + defaults: assetData + }); + + if (!assetCreated) { + await assetRecord.update(assetData); + } + } + + res.status(200).json({ message: 'Collection and Assets Imported Successfully' }); + } catch (error) { + // Log the error and send a server error response + console.error(error); + res.status(500).json({ message: 'Internal Server Error' }); + } +} diff --git a/Api/Controllers/Permissions.js b/Api/Controllers/Permissions.js index f5086ff3..383b979f 100644 --- a/Api/Controllers/Permissions.js +++ b/Api/Controllers/Permissions.js @@ -10,11 +10,12 @@ const permissionService = require('../Services/mysql/permissionsService') -module.exports.getPermissions_User = async function getPermissions_User(req, res, next){ - //res.status(201).json({message: "getPermissions_User Method Called successfully"}) - var permissions = await permissionService.getPermissions_User(req,res,next); - res.status(201).json(permissions) -} +//User permissions are now included in the user object, try getCurrentUser or getUsers instead +//module.exports.getPermissions_User = async function getPermissions_User(req, res, next){ +// //res.status(201).json({message: "getPermissions_User Method Called successfully"}) +// var permissions = await permissionService.getPermissions_User(req,res,next); +// res.status(201).json(permissions) +//} module.exports.getPermissions_Collection = async function getPermissions_Collection(req, res, next){ //res.status(201).json({message: "getPermissions_Collection Method called successfully"}) diff --git a/Api/Controllers/STIGMANAsset.controller.js b/Api/Controllers/STIGMANAsset.controller.js deleted file mode 100644 index 21de203e..00000000 --- a/Api/Controllers/STIGMANAsset.controller.js +++ /dev/null @@ -1,44 +0,0 @@ -const express = require('express'); -const db = require('../utils/sequelize'); -const router = express.Router(); - -async function importAssets(req, res) { - try { - const { assets } = req.body; - - // Handle Assets - for (const asset of assets) { - const collection = asset.collection || {}; - const assetData = { - assetId: asset.assetId, - assetName: asset.name, - fullyQualifiedDomainName: asset.fqdn || '', - description: asset.description || '', - ipAddress: asset.ip || '', - macAddress: asset.mac || '', - nonComputing: asset.noncomputing ? 1 : 0, - collectionId: collection.collectionId || null, - metadata: asset.metadata ? JSON.stringify(asset.metadata) : '{}', - }; - - // Find or create the asset - const [assetRecord, assetCreated] = await db.Asset.findOrCreate({ - where: { assetName: asset.name }, - defaults: assetData - }); - - if (!assetCreated) { - await assetRecord.update(assetData); - } - } - - res.status(200).json({ message: 'Assets Imported Successfully' }); - } catch (error) { - console.error(error); - res.status(500).json({ message: 'Internal Server Error' }); - } -} - -module.exports = { - importAssets -}; diff --git a/Api/Controllers/STIGMANCollection.controller.js b/Api/Controllers/STIGMANCollection.controller.js deleted file mode 100644 index c73c1bfb..00000000 --- a/Api/Controllers/STIGMANCollection.controller.js +++ /dev/null @@ -1,61 +0,0 @@ -const express = require('express'); -const db = require('../utils/sequelize.js'); -const router = express.Router(); - -async function importCollectionAndAssets(req, res) { - try { - const { collection, assets } = req.body; - - // Handle Collection - const collectionData = { - collectionId: collection.collectionId, - collectionName: collection.name, - description: collection.description || '', - metadata: collection.metadata ? JSON.stringify(collection.metadata) : '{}', - settings: collection.settings ? JSON.stringify(collection.settings) : '{}' - }; - - const [collectionRecord, created] = await db.Collection.findOrCreate({ - where: { collectionName: collection.name }, - defaults: collectionData - }); - - if (!created) { - await collectionRecord.update(collectionData); - } - - // Handle Assets - for (const asset of assets) { - const assetData = { - assetId: asset.assetId, - assetName: asset.name, - fullyQualifiedDomainName: asset.fqdn || '', - description: asset.description || '', - ipAddress: asset.ip || '', - macAddress: asset.mac || '', - nonComputing: asset.noncomputing ? 1 : 0, - collectionId: collectionRecord.collectionId, // Ensure this is correctly assigned - metadata: asset.metadata ? JSON.stringify(asset.metadata) : '{}', - }; - - const [assetRecord, assetCreated] = await db.Asset.findOrCreate({ - where: { assetName: asset.name }, // Assuming assetName is unique - defaults: assetData - }); - - if (!assetCreated) { - await assetRecord.update(assetData); - } - } - - res.status(200).json({ message: 'Collection and Assets Imported Successfully' }); - } catch (error) { - // Log the error and send a server error response - console.error(error); - res.status(500).json({ message: 'Internal Server Error' }); - } -}; - -module.exports = { - importCollectionAndAssets -}; diff --git a/Api/Controllers/User.js b/Api/Controllers/User.js index 3a80aa79..fe725594 100644 --- a/Api/Controllers/User.js +++ b/Api/Controllers/User.js @@ -19,12 +19,23 @@ module.exports.getUsers = async function getUsers(req, res, next) { res.status(201).json(users) } +module.exports.getCurrentUser = async function getCurrentUser(req, res) { + const result = await userService.getCurrentUser(req); + + if (result.error) { + res.status(result.status).json({ message: result.error }); + } else { + res.status(200).json(result.data); + } +} + + module.exports.getUserByUserID = async function getUserByUserID(req, res, next) { - // console.log("getUserByUserID: ", req.params.userID) - let userID = req.params.userID - // console.log(userID) - var user = await userService.getUserByUserID(userID) + // console.log("getUserByUserID: ", req.params.userId) + let userId = req.params.userId + // console.log(userId) + var user = await userService.getUserByUserID(userId) // console.log(user) res.status(201).json(user) @@ -41,8 +52,8 @@ module.exports.updateUser = async function updateUser(req, res, next) { module.exports.deleteUser = async function deleteUser(req, res, next) { - let userID = req.params.userID - var deletedUser = await userService.deleteUserByUserID(userID) + let userId = req.params.userId + var deletedUser = await userService.deleteUserByUserID(userId) res.status(201).json(deletedUser) diff --git a/Api/Controllers/auth.js b/Api/Controllers/auth.js index 2fc65bf2..dc24af64 100644 --- a/Api/Controllers/auth.js +++ b/Api/Controllers/auth.js @@ -35,7 +35,7 @@ module.exports.authRegister = async function authRegister(req, res, next){ module.exports.changeWorkspace = async function changeWorkspace(req, res, next){ console.log("changeWorkspace...req.body: ", req.body) // var userAuth = await authService.login(req,res,next) - // //let test = {userID: '1' ,userName: "tyler.forajter", email: 't1@ttt.com'} + // //let test = {userId: '1' ,userName: "tyler.forajter", email: 't1@ttt.com'} // console.log("controller login returning userAuth: ",userAuth) // console.log("controller login returning res: ",res.body) // res.status(201).json(userAuth) diff --git a/Api/Routes/poamUpload.routes.js b/Api/Routes/poamUpload.routes.js deleted file mode 100644 index 1649bd6c..00000000 --- a/Api/Routes/poamUpload.routes.js +++ /dev/null @@ -1,18 +0,0 @@ -/* -!####################################################################### -! C-PATTM SOFTWARE -! CRANE C-PATTM plan of action and milestones software. Use is governed by the Open Source Academic Research License Agreement contained in the file -! crane_C_PAT.1_license.txt, which is part of this software package. BY -! USING OR MODIFYING THIS SOFTWARE, YOU ARE AGREEING TO THE TERMS AND -! CONDITIONS OF THE LICENSE. -!######################################################################## -*/ - -const express = require("express"); -const router = express.Router(); -const poamUploadController = require("../Controllers/poamUpload.controller"); -const upload = require("../Middleware/upload"); - -router.post('/', upload.single('file'), poamUploadController.uploadPoamFile); - -module.exports = router; \ No newline at end of file diff --git a/Api/Services/mysql/assetService.js b/Api/Services/mysql/assetService.js index 0633f9cc..721606fb 100644 --- a/Api/Services/mysql/assetService.js +++ b/Api/Services/mysql/assetService.js @@ -183,7 +183,7 @@ exports.postAsset = async function posAsset(req, res, next) { console.log("rowAsset: ", rowAsset[0]) await connection.release() - // console.log("userID: ", user[0].userId) + // console.log("userId: ", user[0].userId) if (req.body.labels) { let labels = req.body.labels; // console.log("collectionRequest: ",collectionRequest) diff --git a/Api/Services/mysql/authService.js b/Api/Services/mysql/authService.js index 92ac6aa8..9892421a 100644 --- a/Api/Services/mysql/authService.js +++ b/Api/Services/mysql/authService.js @@ -249,7 +249,7 @@ exports.register = async function register(req, res, next) { stack: new Error().stack, }) } - // console.log("userID: ", user[0].userId) + // console.log("userId: ", user[0].userId) if (req.body.collectionAccessRequest) { let collectionRequest = req.body.collectionAccessRequest; // console.log("collectionRequest: ",collectionRequest) diff --git a/Api/Services/mysql/permissionsService.js b/Api/Services/mysql/permissionsService.js index 383dea9b..0b38c4bd 100644 --- a/Api/Services/mysql/permissionsService.js +++ b/Api/Services/mysql/permissionsService.js @@ -13,59 +13,60 @@ const config = require('../../utils/config') const dbUtils = require('./utils') const mysql = require('mysql2') -exports.getPermissions_User = async function getPermissions_User(req, res, next) { - //console.log("getPermissions_User (Service) body: ",req.params.userId); - - if (!req.params.userId) { - console.info('getPermissions_User userId not provided.'); - return next({ - status: 422, - errors: { - userId: 'is required', - } - }); - } - - try { - let connection - connection = await dbUtils.pool.getConnection() - let sql = "SELECT * FROM poamtracking.collectionpermissions WHERE userId=" + req.params.userId + ";" - // console.log("getPermissions_User sql: ", sql) - - let [rowPermissions] = await connection.query(sql) - // console.log("rowPermissions: ", rowPermissions[0]) - await connection.release() - - var size = Object.keys(rowPermissions).length - - var permissions = { - permissions: [] - } - - for (let counter = 0; counter < size; counter++) { - // console.log("Before setting permissions size: ", size, ", counter: ",counter); - - permissions.permissions.push({ - "userId": rowPermissions[counter].userId, - "collectionId": rowPermissions[counter].collectionId, - "canOwn": rowPermissions[counter].canOwn, - "canMaintain": rowPermissions[counter].canMaintain, - "canApprove": rowPermissions[counter].canApprove - }); - // console.log("After setting permissions size: ", size, ", counter: ",counter); - // if (counter + 1 >= size) break; - } - - //console.log("returning: ",permissions) - return { permissions }; - - } - catch (error) { - let errorResponse = { null: "null" } - await connection.release() - return errorResponse; - } -} +//User permissions are now included in the user object, try getCurrentUser or getUsers instead +//exports.getPermissions_User = async function getPermissions_User(req, res, next) { +// //console.log("getPermissions_User (Service) body: ",req.params.userId); + +// if (!req.params.userId) { +// console.info('getPermissions_User userId not provided.'); +// return next({ +// status: 422, +// errors: { +// userId: 'is required', +// } +// }); +// } + +// try { +// let connection +// connection = await dbUtils.pool.getConnection() +// let sql = "SELECT * FROM poamtracking.collectionpermissions WHERE userId=" + req.params.userId + ";" +// // console.log("getPermissions_User sql: ", sql) + +// let [rowPermissions] = await connection.query(sql) +// // console.log("rowPermissions: ", rowPermissions[0]) +// await connection.release() + +// var size = Object.keys(rowPermissions).length + +// var permissions = { +// permissions: [] +// } + +// for (let counter = 0; counter < size; counter++) { +// // console.log("Before setting permissions size: ", size, ", counter: ",counter); + +// permissions.permissions.push({ +// "userId": rowPermissions[counter].userId, +// "collectionId": rowPermissions[counter].collectionId, +// "canOwn": rowPermissions[counter].canOwn, +// "canMaintain": rowPermissions[counter].canMaintain, +// "canApprove": rowPermissions[counter].canApprove +// }); +// // console.log("After setting permissions size: ", size, ", counter: ",counter); +// // if (counter + 1 >= size) break; +// } + +// //console.log("returning: ",permissions) +// return { permissions }; + +// } +// catch (error) { +// let errorResponse = { null: "null" } +// await connection.release() +// return errorResponse; +// } +//} exports.getPermissions_Collection = async function getPermissions_Collection(req, res, next) { // res.status(201).json({ message: "getPermissions_Collection (Service) Method called successfully" }); diff --git a/Api/Services/mysql/usersService.js b/Api/Services/mysql/usersService.js index e90e21ce..1ff631c5 100644 --- a/Api/Services/mysql/usersService.js +++ b/Api/Services/mysql/usersService.js @@ -17,8 +17,6 @@ const auth = require('../../utils/auth'); const writeLog = require('../../utils/poam_logger') exports.getUserObject = async function getUserObject(body, projection, userObject) { - res.status(201).json({ message: "getUser (Service) Method Called successfully" }) - // console.log("Require passed") var con = mysql.createConnection({ host: process.env.USERSERVICE_DB_HOST, @@ -34,14 +32,13 @@ exports.getUserObject = async function getUserObject(body, projection, userObjec // console.log('Entry added') if (err) throw err; }) - - + res.status(201).json({ message: "getUser (Service) Method Called successfully" }) } -exports.refresh = async function refresh(userID, body, projection, userOnject) { +exports.refresh = async function refresh(userId, body, projection, userOnject) { let connection - let sql = 'SELECT * FROM `user` WHERE `userId`=' + userID + let sql = 'SELECT * FROM `user` WHERE `userId`=' + userId connection = await dbUtils.pool.getConnection() let [row] = await connection.query(sql) @@ -49,10 +46,10 @@ exports.refresh = async function refresh(userID, body, projection, userOnject) { return (row[0]) } -exports.getUserByUserID = async function getUserByUserID(userID, body, projection, userObject) { +exports.getUserByUserID = async function getUserByUserID(userId, body, projection, userObject) { let connection - let sql = 'SELECT * FROM `user` WHERE `userId`=' + userID + let sql = 'SELECT * FROM `user` WHERE `userId`=' + userId connection = await dbUtils.pool.getConnection() let [row] = await connection.query(sql) @@ -61,49 +58,116 @@ exports.getUserByUserID = async function getUserByUserID(userID, body, projectio } -exports.getUsers = async function getUsers(req, res, next) { - - let connection - let sql = "SELECT * FROM poamtracking.user;" - connection = await dbUtils.pool.getConnection() - let [rows] = await connection.query(sql) - - await connection.release() - - var size = Object.keys(rows).length - - var users = { - users: [] +exports.getCurrentUser = async function getCurrentUser(req) { + if (!req.userObject || !req.userObject.email) { + return { error: "User is not authenticated", status: 400 }; } - for (let counter = 0; counter < size; counter++) { - // console.log("Before setting permissions size: ", size, ", counter: ",counter); - - users.users.push({ - "userId": rows[counter].userId, - "userName": rows[counter].userName, - "userEmail": rows[counter].userEmail, - "firstName": rows[counter].firstName, - "lastName": rows[counter].lastName, - "created": rows[counter].created, - "lastAccess": rows[counter].lastAccess, - "lastCollectionAccessedId": rows[counter].lastCollectionAccessedId, - "phoneNumber": rows[counter].phoneNumber, - "password": rows[counter].password, - "accountStatus": rows[counter].accountStatus, - "fullName": rows[counter].fullName, - "defaultTheme": rows[counter].defaultTheme, - "isAdmin": rows[counter].isAdmin, - }); - // console.log("After setting permissions size: ", size, ", counter: ",counter); - // if (counter + 1 >= size) break; + try { + const userEmail = req.userObject.email; + let connection = await dbUtils.pool.getConnection(); + const sqlUser = 'SELECT * FROM `user` WHERE `userEmail` = ?'; + const [rows] = await connection.query(sqlUser, [userEmail]); + + if (rows.length > 0) { + const user = rows[0]; + + // Now fetch permissions for this user + const sqlPermissions = "SELECT * FROM poamtracking.collectionpermissions WHERE userId=?"; + const [rowPermissions] = await connection.query(sqlPermissions, [user.userId]); + + const permissions = rowPermissions.map(permission => ({ + userId: permission.userId, + collectionId: permission.collectionId, + canOwn: permission.canOwn, + canMaintain: permission.canMaintain, + canApprove: permission.canApprove + })); + + const response = { + userId: user.userId, + userName: user.userName, + userEmail: user.userEmail, + firstName: user.firstName, + lastName: user.lastName, + created: user.created, + lastAccess: user.lastAccess, + lastCollectionAccessedId: user.lastCollectionAccessedId, + phoneNumber: user.phoneNumber, + password: user.password, + accountStatus: user.accountStatus, + fullName: user.fullName, + defaultTheme: user.defaultTheme, + isAdmin: user.isAdmin, + permissions: permissions // Adding permissions to the response + }; + + await connection.release(); + return { data: response, status: 200 }; + } else { + await connection.release(); + return { error: "User email not found", status: 404 }; + } + } catch (error) { + console.error('Error in getCurrentUser:', error); + if (connection) await connection.release(); + return { error: "Internal Server Error", status: 500 }; } +}; - // console.log("getUsers returning: ",users) - return { users }; +exports.getUsers = async function getUsers(req, res, next) { + let connection; + try { + connection = await dbUtils.pool.getConnection(); + let sql = "SELECT * FROM poamtracking.user;"; + let [rows] = await connection.query(sql); + + var size = Object.keys(rows).length; + var users = { + users: [] + }; + + for (let counter = 0; counter < size; counter++) { + const sqlPermissions = "SELECT * FROM poamtracking.collectionpermissions WHERE userId=?"; + const [rowPermissions] = await connection.query(sqlPermissions, [rows[counter].userId]); + + const permissions = rowPermissions.map(permission => ({ + userId: permission.userId, + collectionId: permission.collectionId, + canOwn: permission.canOwn, + canMaintain: permission.canMaintain, + canApprove: permission.canApprove + })); + + users.users.push({ + "userId": rows[counter].userId, + "userName": rows[counter].userName, + "userEmail": rows[counter].userEmail, + "firstName": rows[counter].firstName, + "lastName": rows[counter].lastName, + "created": rows[counter].created, + "lastAccess": rows[counter].lastAccess, + "lastCollectionAccessedId": rows[counter].lastCollectionAccessedId, + "phoneNumber": rows[counter].phoneNumber, + "password": rows[counter].password, + "accountStatus": rows[counter].accountStatus, + "fullName": rows[counter].fullName, + "defaultTheme": rows[counter].defaultTheme, + "isAdmin": rows[counter].isAdmin, + "permissions": permissions + }); + } + await connection.release(); + return { users }; + } catch (error) { + console.error('Error in getUsers:', error); + if (connection) await connection.release(); + return { error: "Internal Server Error", status: 500 }; + } } + exports.getUserByNamePassword = async function getUserByNamePassword(username, password, callback) { /** * This User instance will be passed through authentication to the JWT. @@ -164,7 +228,7 @@ exports.updateUser = async function updateUser(req, res, next) { // console.log("usersService updateUser req: ", req) // console.log("usersService updateUser req.userObject: ", req.userObject) //console.log("usersService updateUser req.preferred_username: ", req.preferred_username,", req.name: ", req.name) - let userID = req.body.userID; + let userId = req.body.userId; if (!req.body.userEmail) { console.info('Post usersService updateUser: email not provided.'); @@ -176,8 +240,8 @@ exports.updateUser = async function updateUser(req, res, next) { }); } - if (!req.body.userID) { - console.info('Post usersService updateUser: userID not provided.'); + if (!req.body.userId) { + console.info('Post usersService updateUser: userId not provided.'); return next({ status: 422, errors: { @@ -193,7 +257,7 @@ exports.updateUser = async function updateUser(req, res, next) { //console.log("usersService login sql: ", sql) connection = await dbUtils.pool.getConnection() - let sql = "SELECT * from user WHERE userId=" + userID + ";" + let sql = "SELECT * from user WHERE userId=" + userId + ";" let [currentUser] = await connection.query(sql) sql = "UPDATE user SET firstName = '" + req.body.firstName + @@ -205,12 +269,12 @@ exports.updateUser = async function updateUser(req, res, next) { "', fullName = '" + req.body.firstName + " " + req.body.lastName + "', defaultTheme = '" + req.body.defaultTheme + "', isAdmin = " + req.body.isAdmin + - " WHERE userId=" + userID + ";" + " WHERE userId=" + userId + ";" await connection.query(sql); //await connection.release() - sql = "SELECT * from user WHERE userId=" + userID + ";" + sql = "SELECT * from user WHERE userId=" + userId + ";" let [rowUser] = await connection.query(sql) await connection.release() @@ -271,21 +335,21 @@ exports.loginout = async function loginout(req, res, next) { return (message); } -module.exports.deleteUserByUserID = async function deleteUserByUserID(userID, req, res, next) { +module.exports.deleteUserByUserID = async function deleteUserByUserID(userId, req, res, next) { let connection - let sql_query = 'DELETE FROM `user` WHERE `id`=' + userID + let sql_query = 'DELETE FROM `user` WHERE `id`=' + userId connection = await dbUtils.pool.getConnection() let [row] = await connection.query(sql_query) await connection.release() // to meet requirement of STIG V222416 - writeLog.writeLog(3, "usersService", 'log', req.userObject.username, req.userObject.displayName, { event: 'removed account', userId: userID }) + writeLog.writeLog(3, "usersService", 'log', req.userObject.username, req.userObject.displayName, { event: 'removed account', userId: userId }) // to meet requirement of STIG V222420 - writeLog.writeLog(3, "usersService", 'notification', req.userObject.username, req.userObject.displayName, { event: 'removed account', userId: userID }) + writeLog.writeLog(3, "usersService", 'notification', req.userObject.username, req.userObject.displayName, { event: 'removed account', userId: userId }) let messageReturned = new Object() messageReturned.text = "User deleted" - // console.log("User with id: " + userID + " deleted") + // console.log("User with id: " + userId + " deleted") return (messageReturned) } diff --git a/Api/index.js b/Api/index.js index 81ed0c13..00dcbe3b 100644 --- a/Api/index.js +++ b/Api/index.js @@ -11,11 +11,10 @@ require('dotenv').config(); const express = require('express'); -const mysql = require('mysql2'); const app = express(); const PORT = 8086; const HOST = 'localhost'; -var passport = require('passport'); +const passport = require('passport'); const sequelize = require('./utils/sequelize'); const path = require('path'); const multer = require('multer'); @@ -23,9 +22,7 @@ const http = require('http'); const cors = require('cors'); const authAPI = require('./utils/authAPI'); const upload = multer({ storage: multer.memoryStorage() }); -const poamUploadRoutes = require('./Routes/poamUpload.routes'); -const STIGMANCollectionController = require('./Controllers/STIGMANCollection.controller'); -const STIGMANAssetController = require('./Controllers/STIGMANAsset.controller'); +const Import = require('./Controllers/Import'); const { middleware: openApiMiddleware } = require('express-openapi-validator'); const apiSpecPath = path.join(__dirname, './specification/poam-manager.yaml'); @@ -38,10 +35,13 @@ initAuth(); app.use(cors()); app.use(express.json({ - strict: false, // allow root to be any JSON value - limit: parseInt('1048576') // TODO: Set to a reasonable value. Measured in bytes (currently 1MB). + strict: false, + limit: parseInt('10485760') //JSON request body limited to 10MB })); -app.use('/api/poamimport', poamUploadRoutes); + +// Define the poamUploadRoutes within index.js +app.post('/api/poamimport', upload.single('file'), Import.uploadPoamFile); + app.use("/", openApiMiddleware({ apiSpec: apiSpecPath, validateRequests: { @@ -64,8 +64,8 @@ app.use("/", openApiMiddleware({ }, })); -app.post('/api/stigmancollectionimport', STIGMANCollectionController.importCollectionAndAssets); -app.post('/api/stigmanassetimport', STIGMANAssetController.importAssets); +app.post('/api/stigmancollectionimport', Import.importCollectionAndAssets); +app.post('/api/stigmanassetimport', Import.importAssets); require('./utils/passport'); diff --git a/Api/specification/poam-manager.yaml b/Api/specification/poam-manager.yaml index 1cfc7880..cdf01297 100644 --- a/Api/specification/poam-manager.yaml +++ b/Api/specification/poam-manager.yaml @@ -18,140 +18,9 @@ info: version: '1.0' paths: - /api/poamimport: - post: - summary: Upload a POAM file - operationId: uploadPoamFile - requestBody: - required: true - content: - multipart/form-data: - schema: - type: object - properties: - file: - type: string - format: binary - description: Excel file containing POAM data - responses: - '200': - description: File uploaded successfully - content: - application/json: - schema: - type: object - properties: - message: - type: string - '400': - description: Bad request - invalid file format or missing file - content: - application/json: - schema: - $ref: '#/components/schemas/error' - '500': - description: Server error - content: - application/json: - schema: - $ref: '#/components/schemas/error' - tags: - - poamUpload.controller - security: - - oauth: - - 'c-pat:read' - - /api/stigmancollectionimport: - post: - summary: Import collection and assets - operationId: importCollectionAndAssets - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - collection: - $ref: '#/components/schemas/Collection' - assets: - type: array - items: - $ref: '#/components/schemas/Asset' - responses: - '200': - description: Collection and assets imported successfully - content: - application/json: - schema: - type: object - properties: - message: - type: string - '400': - description: Bad request - invalid data format or missing data - content: - application/json: - schema: - $ref: '#/components/schemas/error' - '500': - description: Server error - content: - application/json: - schema: - $ref: '#/components/schemas/error' - tags: - - STIGMANCollection.controller - security: - - oauth: - - 'c-pat:read' - - /api/stigmanassetimport: - post: - summary: Import assets - operationId: importAssets - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - assets: - type: array - items: - $ref: '#/components/schemas/Asset' - responses: - '200': - description: Assets imported successfully - content: - application/json: - schema: - type: object - properties: - message: - type: string - '400': - description: Bad request - invalid data format or missing data - content: - application/json: - schema: - $ref: '#/components/schemas/error' - '500': - description: Server error - content: - application/json: - schema: - $ref: '#/components/schemas/error' - tags: - - STIGMANAsset.controller - security: - - oauth: - - 'c-pat:read' - /assets: get: - summary: Return all assets + summary: Return a list of all assets operationId: getAssets parameters: - in: query @@ -199,7 +68,7 @@ paths: schema: type: integer get: - summary: Return assets by collectionId + summary: Return all assets belonging to a specific collection operationId: getAssetsByCollection responses: '200': @@ -232,7 +101,7 @@ paths: schema: type: integer get: - summary: Return a assetby Id + summary: Return details on a specific asset operationId: getAsset responses: '200': @@ -257,7 +126,7 @@ paths: - oauth: - 'c-pat:read' delete: - summary: Delete a Asset by assetId + summary: Delete an Asset by assetId operationId: deleteAsset responses: '200': @@ -279,7 +148,7 @@ paths: - 'c-pat:read' /asset: post: - summary: Add a asset + summary: Add an asset operationId: postAsset requestBody: required: true @@ -568,7 +437,7 @@ paths: schema: $ref: '#/components/schemas/error' tags: - - auth + - Auth security: - oauth: - 'c-pat:read' @@ -600,7 +469,7 @@ paths: schema: $ref: '#/components/schemas/error' tags: - - auth + - Auth security: - oauth: - 'c-pat:read' @@ -632,7 +501,7 @@ paths: schema: $ref: '#/components/schemas/error' tags: - - auth + - Auth security: - oauth: - 'c-pat:read' @@ -664,7 +533,7 @@ paths: schema: $ref: '#/components/schemas/error' tags: - - auth + - Auth security: - oauth: - 'c-pat:read' @@ -816,6 +685,7 @@ paths: application/json: schema: $ref: '#/components/schemas/error' + '/collections/{collectionId}/POAMs': parameters: - $ref: '#/components/parameters/collectionIdPath' @@ -978,6 +848,137 @@ paths: - oauth: - 'c-pat:read' + /api/poamimport: + post: + summary: Parse and import .xls, .xlsx, or .xlsm eMASS POAM exports + operationId: uploadPoamFile + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + file: + type: string + format: binary + description: .xls, .xlsx, or .xlsm eMASS POAM export file + responses: + '200': + description: File uploaded successfully + content: + application/json: + schema: + type: object + properties: + message: + type: string + '400': + description: Bad request - invalid file format or missing file + content: + application/json: + schema: + $ref: '#/components/schemas/error' + '500': + description: Server error + content: + application/json: + schema: + $ref: '#/components/schemas/error' + tags: + - Import + security: + - oauth: + - 'c-pat:read' + + /api/stigmancollectionimport: + post: + summary: Endpoint to receive collection and assets data from STIG Manager + operationId: importCollectionAndAssets + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + collection: + $ref: '#/components/schemas/Collection' + assets: + type: array + items: + $ref: '#/components/schemas/Asset' + responses: + '200': + description: Collection and assets imported successfully + content: + application/json: + schema: + type: object + properties: + message: + type: string + '400': + description: Bad request - invalid data format or missing data + content: + application/json: + schema: + $ref: '#/components/schemas/error' + '500': + description: Server error + content: + application/json: + schema: + $ref: '#/components/schemas/error' + tags: + - Import + security: + - oauth: + - 'c-pat:read' + + /api/stigmanassetimport: + post: + summary: Endpoint to receive asset data from STIG Manager + operationId: importAssets + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + assets: + type: array + items: + $ref: '#/components/schemas/Asset' + responses: + '200': + description: Assets imported successfully + content: + application/json: + schema: + type: object + properties: + message: + type: string + '400': + description: Bad request - invalid data format or missing data + content: + application/json: + schema: + $ref: '#/components/schemas/error' + '500': + description: Server error + content: + application/json: + schema: + $ref: '#/components/schemas/error' + tags: + - Import + security: + - oauth: + - 'c-pat:read' + '/labels': get: summary: Return all labels @@ -1115,27 +1116,96 @@ paths: - oauth: - 'c-pat:read' - '/permissions/user/{userId}': - parameters: - - in: path - name: userId + # '/permissions/user/{userId}': + # parameters: + # - in: path + # name: userId + # required: true + # schema: + # type: integer + # get: + # summary: Return all collection Permissionss for a user + # operationId: getPermissions_User + # responses: + # '200': + # description: Collection Permissions array response + # content: + # application/json: + # schema: + # type: array + # items: + # $ref: '#/components/schemas/user_Permissions' + # '403': + # $ref: '#/components/responses/forbidden' + # default: + # description: unexpected error + # content: + # application/json: + # schema: + # $ref: '#/components/schemas/error' + # tags: + # - Permissions + # security: + # - oauth: + # - 'c-pat:op' + + # '/permissions/user/{userId}/collection/{collectionId}': + # parameters: + # - in: path + # name: userId + # required: true + # schema: + # type: integer + # - in: path + # name: collectionId + # required: true + # schema: + # type: integer + # get: + # summary: Return unique user collection permission user + # operationId: getPermissions_UserCollection + # responses: + # '200': + # description: Collection Permissions array response + # content: + # application/json: + # schema: + # type: array + # items: + # $ref: '#/components/schemas/user_Permissions' + # '403': + # $ref: '#/components/responses/forbidden' + # default: + # description: unexpected error + # content: + # application/json: + # schema: + # $ref: '#/components/schemas/error' + # tags: + # - Permissions + # security: + # - oauth: + # - 'c-pat:op' + + '/permission': + post: + summary: Add a user collection permission + operationId: postPermission + requestBody: required: true - schema: - type: integer - get: - summary: Return all collection Permissionss for a user - operationId: getPermissions_User + content: + application/json: + schema: + $ref: '#/components/schemas/user_Permissions' responses: '200': - description: Collection Permissions array response + description: return the added collection permission response content: application/json: schema: type: array items: $ref: '#/components/schemas/user_Permissions' - '403': - $ref: '#/components/responses/forbidden' default: description: unexpected error content: @@ -1146,56 +1216,48 @@ paths: - Permissions security: - oauth: - - 'c-pat:read' + - 'c-pat:op' - '/permissions/collection/{collectionId}': - parameters: - - in: path - name: collectionId + put: + summary: Updates user collection permissions + operationId: putPermission + requestBody: required: true - schema: - type: integer - get: - summary: Return all collection Permissions for a collection - operationId: getPermissions_Collection + content: + application/json: + schema: + $ref: '#/components/schemas/user_Permissions' responses: '200': - description: Collection Permissions array response + description: return the updated collection permission response content: application/json: schema: type: array items: $ref: '#/components/schemas/user_Permissions' - '403': - $ref: '#/components/responses/forbidden' default: description: unexpected error content: application/json: schema: $ref: '#/components/schemas/error' - tags: + tags: - Permissions security: - oauth: - - 'c-pat:read' - - '/permissions/user/{userId}/collection/{collectionId}': + - 'c-pat:op' + + '/permissions/collection/{collectionId}': parameters: - - in: path - name: userId - required: true - schema: - type: integer - in: path name: collectionId required: true schema: - type: integer + type: integer get: - summary: Return unique user collection permission user - operationId: getPermissions_UserCollection + summary: Return all collection Permissions for a collection + operationId: getPermissions_Collection responses: '200': description: Collection Permissions array response @@ -1217,69 +1279,8 @@ paths: - Permissions security: - oauth: - - 'c-pat:read' - - '/permission': - post: - summary: Add a user collection permission - operationId: postPermission - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/user_Permissions' - responses: - '200': - description: return the added collection permission response - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/user_Permissions' - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/error' - tags: - - Permissions - security: - - oauth: - - 'c-pat:read' - - put: - summary: Updates user collection permissions - operationId: putPermission - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/user_Permissions' - responses: - '200': - description: return the updated collection permission response - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/user_Permissions' - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/error' - tags: - - Permissions - security: - - oauth: - - 'c-pat:read' - + - 'c-pat:op' + '/permission/{userId}/{collectionId}': parameters: - in: path @@ -1312,7 +1313,7 @@ paths: - Permissions security: - oauth: - - 'c-pat:read' + - 'c-pat:op' '/poamApprovers/{poamId}': parameters: @@ -2090,6 +2091,27 @@ paths: - oauth: - 'c-pat:read' '/user': + get: + tags: + - User + summary: Return the current users information + operationId: getCurrentUser + responses: + '200': + description: UserProjected response + content: + application/json: + schema: + $ref: '#/components/schemas/current_user_Response' + default: + description: unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/error' + security: + - oauth: + - 'c-pat:read' put: tags: - User @@ -2124,7 +2146,7 @@ paths: - User security: - oauth: - - 'c-pat:read' + - 'c-pat:op' summary: Return all users for admin processing (assigning collections and permissions) operationId: getUsers responses: @@ -2135,7 +2157,7 @@ paths: schema: type: array items: - $ref: '#/components/schemas/user_Response' + $ref: '#/components/schemas/current_user_Response' default: description: unexpected error content: @@ -2143,10 +2165,10 @@ paths: schema: $ref: '#/components/schemas/error' - '/user/{userID}': + '/user/{userId}': parameters: - in: path - name: userID + name: userId required: true schema: type: integer @@ -2155,7 +2177,7 @@ paths: - User security: - oauth: - - 'c-pat:read' + - 'c-pat:op' summary: Return a User operationId: getUserByUserID responses: @@ -2176,7 +2198,7 @@ paths: - User security: - oauth: - - 'c-pat:read' + - 'c-pat:op' summary: Delete a User operationId: deleteUser responses: @@ -2683,7 +2705,7 @@ components: user: type: object required: - - userID + - userId - userName - email - displayName @@ -2694,7 +2716,7 @@ components: - isAdmin additionalProperties: true properties: - userID: + userId: type: string maxLength: 255 readOnly: true @@ -2724,10 +2746,10 @@ components: isAdmin: type: integer - user_Response: + current_user_Response: type: object required: - - userID + - userId - userName - userEmail - firstName @@ -2741,11 +2763,11 @@ components: - fullName - defaultTheme - isAdmin + - permissions additionalProperties: false properties: - userID: - type: string - maxLength: 50 + userId: + type: integer readOnly: true userName: type: string @@ -2753,6 +2775,7 @@ components: readOnly: true userEmail: type: string + maxLength: 100 readOnly: true firstName: type: string @@ -2770,8 +2793,93 @@ components: format: date # pattern: '^\d{4}-(0[1-9]|1[012])-(0[1-9][12][0-9]|3[0-1])$' lastCollectionAccessedId: + type: integer + phoneNumber: + type: string + maxLength: 15 + password: + type: string + maxLength: 255 + accountStatus: + type: string + maxLength: 45 + fullName: + type: string + maxLength: 225 + defaultTheme: + type: string + maxLength: 20 + isAdmin: + type: integer + permissions: + type: array + items: + type: object + required: + - userId + - collectionId + - canOwn + - canMaintain + - canApprove + properties: + userId: + type: integer + collectionId: + type: integer + canOwn: + type: integer + canMaintain: + type: integer + canApprove: + type: integer + + user_Response: + type: object + required: + - userId + - userName + - userEmail + - firstName + - lastName + - created + - lastAccess + - lastCollectionAccessedId + - phoneNumber + - password + - accountStatus + - fullName + - defaultTheme + - isAdmin + additionalProperties: false + properties: + userId: + type: integer + readOnly: true + userName: + type: string + maxLength: 20 + readOnly: true + userEmail: + type: string + maxLength: 100 + readOnly: true + firstName: + type: string + maxLength: 50 + readOnly: true + lastName: type: string maxLength: 50 + created: + type: string + format: date + # pattern: '^\d{4}-(0[1-9]|1[012])-(0[1-9][12][0-9]|3[0-1])$' + lastAccess: + type: string + format: date + # pattern: '^\d{4}-(0[1-9]|1[012])-(0[1-9][12][0-9]|3[0-1])$' + lastCollectionAccessedId: + type: integer phoneNumber: type: string maxLength: 15 @@ -2793,7 +2901,7 @@ components: user_Update: type: object required: - - userID + - userId - userEmail - firstName - lastName @@ -2804,7 +2912,7 @@ components: - isAdmin additionalProperties: true properties: - userID: + userId: type: integer userEmail: type: string @@ -2860,7 +2968,7 @@ components: user_Token: required: - - userID + - userId - userName - userEmail - firstName @@ -2872,7 +2980,7 @@ components: - defaultTheme additionalProperties: false properties: - userID: + userId: type: integer userName: type: string diff --git a/Api/utils/authAPI.js b/Api/utils/authAPI.js index f1048347..c64828d1 100644 --- a/Api/utils/authAPI.js +++ b/Api/utils/authAPI.js @@ -66,30 +66,7 @@ const verifyRequest = async function (req, requiredScopes, securityDefinition) { privileges.canAdmin = privilegeGetter(decoded).includes('admin') req.userObject.privileges = privileges - /* const response = await User.getUserByUsername(req.userObject.username, ['collectionGrants', 'statistics'], false, null) - req.userObject.userId = response?.userId || null - req.userObject.collectionGrants = response?.collectionGrants || [] - req.userObject.statistics = response?.statistics || {} - - const refreshFields = {} - let now = new Date().toUTCString() - now = new Date(now).getTime() - now = now / 1000 | 0 //https://stackoverflow.com/questions/7487977/using-bitwise-or-0-to-floor-a-number - - if (!response?.statistics?.lastAccess || now - response?.statistics?.lastAccess >= config.settings.lastAccessResolution) { - refreshFields.lastAccess = now - } - if (!response?.statistics?.lastClaims || decoded.jti !== response?.statistics?.lastClaims?.jti) { - refreshFields.lastClaims = decoded - } - if (req.userObject.username && (refreshFields.lastAccess || refreshFields.lastClaims)) { - const userId = await User.setUserData(req.userObject, refreshFields) - if (userId != req.userObject.userId) { - req.userObject.userId = userId.toString() - } - } - - */ + if ('elevate' in req.query && (req.query.elevate === 'true' && !req.userObject.privileges.canAdmin)) { throw ({ status: 403, message: 'User has insufficient privilege to complete this request.' }) } diff --git a/Front End/poam-app/src/app/access-control-list.ts b/Front End/poam-app/src/app/access-control-list.ts index ec3dc9de..b7a82607 100644 --- a/Front End/poam-app/src/app/access-control-list.ts +++ b/Front End/poam-app/src/app/access-control-list.ts @@ -10,16 +10,8 @@ import { NbAclOptions } from "@nebular/security"; -export const ACCESS_CONTROL_LIST: any = { //}: NbAclOptions = { +export const ACCESS_CONTROL_LIST: any = { accessControl: { - // user: { - // create: ['create-task','timekeeping', 'odcform', 'monthly-report'], - // view: ['create-task', 'timekeeping', 'odcform', 'help', 'hierarchy', 'send-reports', 'reporting'] - // }, - // viewer: { - // create: ['create-task'], - // view: ['dashboard','hierarchy','send-reports','help','reporting'] - // }, owner: { view: ['*'], create: ['poam','asset','label','collection'], diff --git a/Front End/poam-app/src/app/app-menu.ts b/Front End/poam-app/src/app/app-menu.ts index 318ca8b8..5fdfb2d9 100644 --- a/Front End/poam-app/src/app/app-menu.ts +++ b/Front End/poam-app/src/app/app-menu.ts @@ -22,27 +22,27 @@ export const appMenuItems: NbMenuItem[] = [ title: 'Asset Processing', icon: 'hard-drive-outline', link: '/asset-processing', - data: { permission: 'create', resource: 'asset' }, + data: { permission: 'view', resource: 'asset' }, hidden: true, }, { title: 'Collections', icon: { icon: 'archive-outline', pack: 'eva' }, link: '/collection-processing', - data: { permission: 'create', resource: 'collection' }, + data: { permission: 'view', resource: 'collection' }, hidden: true, }, { title: 'Label Processing', icon: 'pricetags-outline', link: '/label-processing', - data: { permission: 'create', resource: 'label' }, + data: { permission: 'view', resource: 'label' }, hidden: true, }, { title: 'POAMs', icon: 'list-outline', - data: { permission: 'create', resource: 'poam' }, + data: { permission: 'view', resource: 'poam' }, hidden: true, children: [ { diff --git a/Front End/poam-app/src/app/app.component.ts b/Front End/poam-app/src/app/app.component.ts index 7f0b4a58..94d4ff5b 100644 --- a/Front End/poam-app/src/app/app.component.ts +++ b/Front End/poam-app/src/app/app.component.ts @@ -14,8 +14,18 @@ import { ACCESS_CONTROL_LIST } from './access-control-list'; import { appMenuItems } from './app-menu'; import { environment } from '../environments/environment'; import { FileUploadService } from './file-upload.service'; +import { Location } from '@angular/common'; import { HttpEventType, HttpResponse } from '@angular/common/http'; - +import { ChangeDetectorRef } from '@angular/core'; +import { Users } from './pages/user-processing/users.model'; + +interface Permission { + userId: number; + collectionId: number; + canOwn: number; + canMaintain: number; + canApprove: number; +} @Component({ selector: "ngx-app", @@ -24,7 +34,6 @@ import { HttpEventType, HttpResponse } from '@angular/common/http'; export class AppComponent implements OnInit, OnDestroy { @Output() resetRole: EventEmitter = new EventEmitter(); - public isLoggedIn = false; public userProfile: KeycloakProfile | null = null; classificationCode: string = 'U'; @@ -57,9 +66,11 @@ export class AppComponent implements OnInit, OnDestroy { hasDivider: true }; + private subs = new SubSink() constructor( + private cdr: ChangeDetectorRef, private readonly sidebarService: NbSidebarService, private menuService: NbMenuService, private themeService: NbThemeService, @@ -79,7 +90,7 @@ export class AppComponent implements OnInit, OnDestroy { if (event.item.title === 'Import POAM') { this.triggerFileInput(); } - + // Add logout functionality if (event.item.title === 'Logout') { this.logOut(); @@ -93,8 +104,6 @@ export class AppComponent implements OnInit, OnDestroy { this.isLoggedIn = await this.keycloak.isLoggedIn(); if (this.isLoggedIn) { this.userProfile = await this.keycloak.loadUserProfile(); - //console.log("Poams component userProfile: ",this.userProfile.email) - //console.log("Poams component userProfile: ",this.userProfile.username) this.setPayload(); } @@ -110,69 +119,53 @@ export class AppComponent implements OnInit, OnDestroy { } setPayload() { - this.users = [] this.user = null; this.payload = null; - this.subs.sink = forkJoin( - this.userService.getUsers(), - ).subscribe(([users]: any) => { - console.log('users: ', users) - this.users = users.users.users - // console.log('this.users: ',this.users) - this.user = this.users.find((e: { userName: string; }) => e.userName === this.userProfile?.username) - console.log('this.user: ', this.user) - if (!this.user || this.user === undefined) { - let user = { - userName: this.userProfile?.username, - firstName: this.userProfile?.firstName, - lastName: this.userProfile?.lastName, - email: this.userProfile?.email, - phoneNumber: '', - password: 'same', - confirmPassword: 'same', - } - - this.user = user; - - this.userService.postUser(user).subscribe(result => { - console.log("User name: " + user.userName + " has been added, account status is PENDING") - }) - + this.subs.sink = this.userService.getCurrentUser().subscribe( + (response: any) => { + console.log('Current user: ', response); + this.user = response; - } else { if (this.user.accountStatus === 'ACTIVE') { - this.payload = Object.assign(this.user, { - collections: [] + this.payload = Object.assign({}, this.user, { + collections: this.user.permissions.map((permission: Permission) => ({ + collectionId: permission.collectionId, + canOwn: permission.canOwn, + canMaintain: permission.canMaintain, + canApprove: permission.canApprove + })) }); - this.subs.sink = forkJoin( - this.userService.getUserPermissions(this.user.userId) - ).subscribe(([permissions]: any) => { - // console.log("permissions: ", permissions) - - permissions.permissions.permissions.forEach((element: any) => { - // console.log("element: ",element) - let assigendCollections = { - collectionId: element.collectionId, - canOwn: element.canOwn, - canMaintain: element.canMaintain, - canApprove: element.canApprove, - } - // console.log("assignedCollections: ", assigendCollections) - this.payload.collections.push(assigendCollections); - }); - - console.log("payload: ", this.payload) - this.getCollections(); - }) + console.log("payload: ", this.payload); + this.getCollections(); // Proceed with the payload } else { - alert('Your account status is not Active, contact your system administrator') + alert('Your account status is not Active, contact your system administrator'); + } + }, + (error) => { + if (error.status === 404 || !this.user) { + let newUser = { + userName: this.userProfile?.username, + firstName: this.userProfile?.firstName, + lastName: this.userProfile?.lastName, + email: this.userProfile?.email, + phoneNumber: this.userProfile?.phoneNumber || "", + password: 'same', + confirmPassword: 'same', + }; + + this.userService.postUser(newUser).subscribe(result => { + console.log("User name: " + newUser.userName + " has been added, account status is PENDING"); + this.user = newUser; + // Further processing if needed after user creation + }); + } else { + // Handle other kinds of errors + console.error('An error occurred:', error.message); } - } - - }) + ); } getCollections() { @@ -284,7 +277,7 @@ export class AppComponent implements OnInit, OnDestroy { } resetWorkspace(selectedCollection: any) { - // console.log("resetWorkspace selection: ",selectedCollection) + //console.log("resetWorkspace selection: ",selectedCollection) this.selectedCollection = selectedCollection; this.selectCollectionMsg = false; @@ -297,7 +290,7 @@ export class AppComponent implements OnInit, OnDestroy { att.textContent = collection.collectionName + " - " + collection.description } } - // update token and user + let userUpdate = { userId: this.user.userId, @@ -345,7 +338,6 @@ export class AppComponent implements OnInit, OnDestroy { defaultTheme: (this.user.defaultTheme) ? this.user.defaultTheme : 'default', isAdmin: this.user.isAdmin } - this.authMenuItems(); }); diff --git a/Front End/poam-app/src/app/pages/asset-processing/asset-processing.component.ts b/Front End/poam-app/src/app/pages/asset-processing/asset-processing.component.ts index 83eb7d20..0d385fc2 100644 --- a/Front End/poam-app/src/app/pages/asset-processing/asset-processing.component.ts +++ b/Front End/poam-app/src/app/pages/asset-processing/asset-processing.component.ts @@ -26,6 +26,13 @@ import { environment } from '../../../environments/environment'; import { ChangeDetectorRef } from '@angular/core'; import { Assets } from './asset.model'; +interface Permission { + userId: number; + collectionId: number; + canOwn: number; + canMaintain: number; + canApprove: number; +} interface TreeNode { data: T; children?: TreeNode[]; @@ -182,40 +189,37 @@ export class AssetProcessingComponent implements OnInit { } setPayload() { - this.users = [] this.user = null; this.payload = null; - // console.log("setPayload()..."); - this.subs.sink = forkJoin( - this.userService.getUsers(), - ).subscribe(([users]: any) => { - // console.log('users: ', users) - this.users = users.users.users - // console.log('this.users: ', this.users) - this.user = this.users.find((e: { userName: string; }) => e.userName === this.userProfile?.username) - // console.log('this.user: ', this.user) - this.payload = Object.assign(this.user, { - collections: [] - }); - this.subs.sink = forkJoin( - this.userService.getUserPermissions(this.user.userId) - ).subscribe(([permissions]: any) => { - - permissions.permissions.permissions.forEach((element: any) => { - // console.log("element: ",element) - let assigendCollections = { - collectionId: element.collectionId, - canOwn: element.canOwn, - canMaintain: element.canMaintain, - canApprove: element.canApprove, + this.subs.sink = this.userService.getCurrentUser().subscribe( + (response: any) => { + if (response && response.userId) { + this.user = response; + console.log('Current user: ', this.user); + + if (this.user.accountStatus === 'ACTIVE') { + this.payload = { + ...this.user, + collections: this.user.permissions.map((permission: Permission) => ({ + collectionId: permission.collectionId, + canOwn: permission.canOwn, + canMaintain: permission.canMaintain, + canApprove: permission.canApprove + })) + }; + + console.log("payload: ", this.payload); + this.getAssetData(); } - // console.log("assignedCollections: ", assigendCollections) - this.payload.collections.push(assigendCollections); - }); - this.getAssetData(); - }) - }) + } else { + console.error('User data is not available or user is not active'); + } + }, + (error) => { + console.error('An error occurred:', error); + } + ); } getAssetData(loadMore = false) { diff --git a/Front End/poam-app/src/app/pages/collection-processing/collection-processing.component.ts b/Front End/poam-app/src/app/pages/collection-processing/collection-processing.component.ts index 93b972e1..206d8929 100644 --- a/Front End/poam-app/src/app/pages/collection-processing/collection-processing.component.ts +++ b/Front End/poam-app/src/app/pages/collection-processing/collection-processing.component.ts @@ -23,6 +23,13 @@ import { KeycloakProfile } from 'keycloak-js'; import { UsersService } from '../user-processing/users.service' import { environment } from '../../../environments/environment'; +interface Permission { + userId: number; + collectionId: number; + canOwn: number; + canMaintain: number; + canApprove: number; +} interface TreeNode { data: T; children?: TreeNode[]; @@ -160,45 +167,37 @@ export class CollectionProcessingComponent implements OnInit { } setPayload() { - this.users = [] this.user = null; this.payload = null; - this.subs.sink = forkJoin( - this.userService.getUsers(), - ).subscribe(([users]: any) => { - //console.log('users: ',users) - this.users = users.users.users - //console.log('this.users: ',this.users) - this.user = this.users.find((e: { userName: string; }) => e.userName === this.userProfile?.username) - //console.log('this.user: ',this.user) - this.payload = Object.assign(this.user, { - collections: [] - }); + this.subs.sink = this.userService.getCurrentUser().subscribe( + (response: any) => { + if (response && response.userId) { + this.user = response; + console.log('Current user: ', this.user); + + if (this.user.accountStatus === 'ACTIVE') { + this.payload = { + ...this.user, + collections: this.user.permissions.map((permission: Permission) => ({ + collectionId: permission.collectionId, + canOwn: permission.canOwn, + canMaintain: permission.canMaintain, + canApprove: permission.canApprove + })) + }; - this.subs.sink = forkJoin( - this.userService.getUserPermissions(this.user.userId) - ).subscribe(([permissions]: any) => { - //console.log("permissions: ", permissions) - - permissions.permissions.permissions.forEach((element: any) => { - // console.log("element: ",element) - let assigendCollections = { - collectionId: element.collectionId, - canOwn: element.canOwn, - canMaintain: element.canMaintain, - canApprove: element.canApprove, + console.log("payload: ", this.payload); + this.getCollectionData(); // Adjusted function name } - // console.log("assignedCollections: ", assigendCollections) - this.payload.collections.push(assigendCollections); - }); - - //console.log("payload: ",this.payload) - - this.getCollectionData(); - }) - - }) + } else { + console.error('User data is not available or user is not active'); + } + }, + (error) => { + console.error('An error occurred:', error); + } + ); } getCollectionData() { diff --git a/Front End/poam-app/src/app/pages/label-processing/label-processing.component.ts b/Front End/poam-app/src/app/pages/label-processing/label-processing.component.ts index 1aa6fd0c..9567a28e 100644 --- a/Front End/poam-app/src/app/pages/label-processing/label-processing.component.ts +++ b/Front End/poam-app/src/app/pages/label-processing/label-processing.component.ts @@ -21,6 +21,13 @@ import { UsersService } from '../user-processing/users.service'; import { KeycloakService } from 'keycloak-angular'; import { KeycloakProfile } from 'keycloak-js'; +interface Permission { + userId: number; + collectionId: number; + canOwn: number; + canMaintain: number; + canApprove: number; +} interface TreeNode { data: T; children?: TreeNode[]; @@ -87,19 +94,6 @@ export class LabelProcessingComponent implements OnInit { } async ngOnInit() { - // this.subs.sink = this.authService.onTokenChange() - // .subscribe((token: NbAuthJWTToken) => { - // //if (token.isValid() && this.router.url === '/pages/collection-processing') { - // if (token.isValid()) { - // this.isLoading = true; - // this.payload = token.getPayload(); - - // this.data = []; - // this.getLabelData(); - - // } - // }) - this.isLoggedIn = await this.keycloak.isLoggedIn(); if (this.isLoggedIn) { this.userProfile = await this.keycloak.loadUserProfile(); @@ -111,49 +105,39 @@ export class LabelProcessingComponent implements OnInit { } setPayload() { - this.users = [] this.user = null; this.payload = null; - this.subs.sink = forkJoin( - this.userService.getUsers(), - ).subscribe(([users]: any) => { - console.log('users: ',users) - this.users = users.users.users - console.log('this.users: ',this.users) - this.user = this.users.find((e: { userName: string; }) => e.userName === this.userProfile?.username) - console.log('this.user: ',this.user) - this.payload = Object.assign(this.user, { - collections: [] - }); - - this.subs.sink = forkJoin( - this.userService.getUserPermissions(this.user.userId) - ).subscribe(([permissions]: any) => { - console.log("permissions: ", permissions) - - permissions.permissions.permissions.forEach((element: any) => { - // console.log("element: ",element) - let assigendCollections = { - collectionId: element.collectionId, - canOwn: element.canOwn, - canMaintain: element.canMaintain, - canApprove: element.canApprove, + this.subs.sink = this.userService.getCurrentUser().subscribe( + (response: any) => { + if (response && response.userId) { + this.user = response; + console.log('Current user: ', this.user); + + if (this.user.accountStatus === 'ACTIVE') { + this.payload = { + ...this.user, + collections: this.user.permissions.map((permission: Permission) => ({ + collectionId: permission.collectionId, + canOwn: permission.canOwn, + canMaintain: permission.canMaintain, + canApprove: permission.canApprove + })) + }; + + console.log("payload: ", this.payload); + this.getLabelData(); } - // console.log("assignedCollections: ", assigendCollections) - this.payload.collections.push(assigendCollections); - }); - - console.log("payload: ",this.payload) - - this.getLabelData(); - }) - - - }) + } else { + console.error('User data is not available or user is not active'); + } + }, + (error) => { + console.error('An error occurred:', error); + } + ); } - getLabelData() { this.isLoading = true; this.labels = null; diff --git a/Front End/poam-app/src/app/pages/poam-processing/poam-approve/poam-approve.component.ts b/Front End/poam-app/src/app/pages/poam-processing/poam-approve/poam-approve.component.ts index f51bb585..ddce3de7 100644 --- a/Front End/poam-app/src/app/pages/poam-processing/poam-approve/poam-approve.component.ts +++ b/Front End/poam-app/src/app/pages/poam-processing/poam-approve/poam-approve.component.ts @@ -19,6 +19,14 @@ import { KeycloakProfile } from 'keycloak-js'; import { UsersService } from '../../user-processing/users.service'; import { DatePipe } from '@angular/common'; +interface Permission { + userId: number; + collectionId: number; + canOwn: number; + canMaintain: number; + canApprove: number; +} + @Component({ selector: 'ngx-poam-approve', templateUrl: './poam-approve.component.html', @@ -71,46 +79,41 @@ export class PoamApproveComponent implements OnInit { } setPayload() { - this.users = [] this.user = null; this.payload = null; - this.subs.sink = forkJoin( - this.userService.getUsers(), - ).subscribe(([users]: any) => { - console.log('users: ',users) - this.users = users.users.users - // console.log('this.users: ',this.users) - this.user = this.users.find((e: { userName: string; }) => e.userName === this.userProfile?.username) - //console.log('this.user: ',this.user) - this.payload = Object.assign(this.user, { - collections: [] - }); - - this.subs.sink = forkJoin( - this.userService.getUserPermissions(this.user.userId) - ).subscribe(([permissions]: any) => { - console.log("permissions: ", permissions) - - permissions.permissions.permissions.forEach((element: any) => { - // console.log("element: ",element) - let assigendCollections = { - collectionId: element.collectionId, - canOwn: element.canOwn, - canMaintain: element.canMaintain, - canApprove: element.canApprove, + this.subs.sink = this.userService.getCurrentUser().subscribe( + (response: any) => { + if (response && response.userId) { + this.user = response; + console.log('Current user: ', this.user); + + if (this.user.accountStatus === 'ACTIVE') { + const mappedPermissions = this.user.permissions.map((permission: Permission) => ({ + collectionId: permission.collectionId, + canOwn: permission.canOwn, + canMaintain: permission.canMaintain, + canApprove: permission.canApprove + })); + + this.payload = { + ...this.user, + collections: mappedPermissions + }; + + console.log("Payload with permissions: ", this.payload); + this.getData(); + } else { + console.error('User data is not available or user is not active'); } - // console.log("assignedCollections: ", assigendCollections) - this.payload.collections.push(assigendCollections); - }); - - console.log("payload: ",this.payload) - - this.getData(); - }) - - - }) + } else { + console.error('No current user data available'); + } + }, + (error) => { + console.error('An error occurred:', error); + } + ); } getData() { diff --git a/Front End/poam-app/src/app/pages/poam-processing/poam-details/poam-details.component.ts b/Front End/poam-app/src/app/pages/poam-processing/poam-details/poam-details.component.ts index d15a150f..9936eb4c 100644 --- a/Front End/poam-app/src/app/pages/poam-processing/poam-details/poam-details.component.ts +++ b/Front End/poam-app/src/app/pages/poam-processing/poam-details/poam-details.component.ts @@ -21,6 +21,13 @@ import { NbDialogService, NbWindowRef } from '@nebular/theme'; import { KeycloakService } from 'keycloak-angular'; import { KeycloakProfile } from 'keycloak-js'; import { UsersService } from '../../user-processing/users.service' +interface Permission { + userId: number; + collectionId: number; + canOwn: number; + canMaintain: number; + canApprove: number; +} @Component({ selector: 'ngx-poamdetails', @@ -167,7 +174,7 @@ export class PoamDetailsComponent implements OnInit { list: [ { value: 'Not Reviewed', title: 'Not Reviewed' }, { value: 'Approved', title: 'Approved' }, - { value: 'Rejected', title: 'Rejected'} + { value: 'Rejected', title: 'Rejected' } ], }, }, @@ -179,7 +186,7 @@ export class PoamDetailsComponent implements OnInit { editable: false, addable: false, valuePrepareFunction: (_cell: any, row: any) => { - return (row.approvedDate) ? row.approvedDate.substr(0,10) : ''; + return (row.approvedDate) ? row.approvedDate.substr(0, 10) : ''; }, editor: { type: 'list', @@ -288,69 +295,57 @@ export class PoamDetailsComponent implements OnInit { } setPayload() { - this.users = [] this.user = null; this.payload = null; - this.subs.sink = forkJoin( - this.userService.getUsers(), - ).subscribe(([users]: any) => { - // console.log('users: ', users) - this.users = users.users.users - // console.log('this.users: ', this.users) - this.user = this.users.find((e: { userName: string; }) => e.userName === this.userProfile?.username) - // console.log('this.user: ', this.user) - this.payload = Object.assign(this.user, { - collections: [] - }); - - this.subs.sink = forkJoin( - this.userService.getUserPermissions(this.user.userId) - ).subscribe(([permissions]: any) => { - // console.log("permissions: ", permissions) - - permissions.permissions.permissions.forEach((element: any) => { - // console.log("element: ",element) - let assigendCollections = { - collectionId: element.collectionId, - canOwn: element.canOwn, - canMaintain: element.canMaintain, - canApprove: element.canApprove, + this.subs.sink = this.userService.getCurrentUser().subscribe( + (response: any) => { + if (response && response.userId) { + this.user = response; + console.log('Current user: ', this.user); + if (this.user.accountStatus === 'ACTIVE') { + + const mappedPermissions = this.user.permissions.map((permission: Permission) => ({ + collectionId: permission.collectionId, + canOwn: permission.canOwn, + canMaintain: permission.canMaintain, + canApprove: permission.canApprove + })); + + this.payload = { + ...this.user, + collections: mappedPermissions + }; + + let selectedPermissions = this.payload.collections.find((x: { collectionId: any; }) => x.collectionId == this.payload.lastCollectionAccessedId); + let myRole = ''; + + if (!selectedPermissions && !this.user.isAdmin) { + myRole = 'none'; + } else { + myRole = (this.user.isAdmin) ? 'admin' : + (selectedPermissions?.canOwn) ? 'owner' : + (selectedPermissions?.canMaintain) ? 'maintainer' : + (selectedPermissions?.canApprove) ? 'approver' : 'none'; + } + this.payload.role = myRole; + this.showApprove = ['admin', 'owner', 'approver'].includes(this.payload.role); + this.showClose = ['admin', 'owner'].includes(this.payload.role); + this.showSubmit = ['admin', 'owner', 'maintainer'].includes(this.payload.role); + + this.getData(); } - // console.log("assignedCollections: ", assigendCollections) - this.payload.collections.push(assigendCollections); - }); - - // console.log("resetWorkspace payload.collections: ",this.payload.collections) - let selectedPermissions = this.payload.collections.find((x: { collectionId: any; }) => x.collectionId == this.payload.lastCollectionAccessedId) - // console.log("resetWorkspace selectedPermission: ",selectedPermissions) - let myRole = '' - - if (!selectedPermissions && !this.user.isAdmin) { - myRole = 'none' } else { - myRole = (this.user.isAdmin) ? 'admin' : (selectedPermissions.canOwn) ? 'owner' : (selectedPermissions.canMaintain) ? 'maintainer' : (selectedPermissions.canApprove) ? 'approver' : 'none' - } - this.payload.role = myRole; - // console.log("POAM-DETAILS payload.role: ", this.payload.role) - if (this.payload.role == 'admin' || this.payload.role == 'owner' || this.payload.role == 'approver') { - this.showApprove = true; - //alert("Setting showApproveClose") - } - if (this.payload.role == 'admin' || this.payload.role == 'owner') { - this.showClose = true; - //alert("Setting showApproveClose") + console.error('User data is not available or user is not active'); } - if (this.payload.role == 'admin' || this.payload.role == 'owner' || this.payload.role == 'maintainer') { - this.showSubmit = true; - //alert("Setting showSubmit") - } - - this.getData(); - }) - }) + }, + (error) => { + console.error('An error occurred:', error); + } + ); } + getData() { if (this.poamId == undefined || !this.poamId) return; @@ -450,6 +445,7 @@ export class PoamDetailsComponent implements OnInit { this.poamApprovers = poamApprovers.poamApprovers; console.log("poamApprovers: ", this.poamApprovers) this.collectionApprovers = collectionApprovers.collectionApprovers; + //console.log("Collection Approvers: " + this.collectionApprovers); // console.log("collectionApprovers: ", this.collectionApprovers) if (this.collectionApprovers.length > 0 && (this.poamApprovers == undefined || this.poamApprovers.length ==0)) { // Set default approvers... diff --git a/Front End/poam-app/src/app/pages/poam-processing/poams.component.html b/Front End/poam-app/src/app/pages/poam-processing/poams.component.html index 98c59f9a..bc41de24 100644 --- a/Front End/poam-app/src/app/pages/poam-processing/poams.component.html +++ b/Front End/poam-app/src/app/pages/poam-processing/poams.component.html @@ -17,10 +17,12 @@
Selected Collection:
- +

- +
+ +

@@ -34,7 +36,7 @@

-
Expired
- --> +
diff --git a/Front End/poam-app/src/app/pages/poam-processing/poams.component.scss b/Front End/poam-app/src/app/pages/poam-processing/poams.component.scss index 3ce40b87..090d5080 100644 --- a/Front End/poam-app/src/app/pages/poam-processing/poams.component.scss +++ b/Front End/poam-app/src/app/pages/poam-processing/poams.component.scss @@ -19,3 +19,7 @@ hr { margin: 1em 0; padding: 0; } +.canvas { + height: 50vh; + width: 100vw; +} diff --git a/Front End/poam-app/src/app/pages/poam-processing/poams.component.ts b/Front End/poam-app/src/app/pages/poam-processing/poams.component.ts index 96314cdd..479ae67a 100644 --- a/Front End/poam-app/src/app/pages/poam-processing/poams.component.ts +++ b/Front End/poam-app/src/app/pages/poam-processing/poams.component.ts @@ -8,7 +8,7 @@ !######################################################################## */ -import { Component, OnInit } from '@angular/core'; +import { ChangeDetectorRef, Component, OnInit } from '@angular/core'; import { SubSink } from 'subsink'; import { NbThemeService, NbButtonModule } from "@nebular/theme"; import { PoamService } from './poams.service'; @@ -20,6 +20,13 @@ import { Router } from '@angular/router'; import { KeycloakService } from 'keycloak-angular'; import { KeycloakProfile } from 'keycloak-js'; import { UsersService } from '../user-processing/users.service' +interface Permission { + userId: number; + collectionId: number; + canOwn: number; + canMaintain: number; + canApprove: number; +} @Component({ selector: 'ngx-poams', @@ -68,8 +75,8 @@ export class PoamsComponent implements OnInit { maintainAspectRatio: false, tooltips: { callbacks: { - label: function (tooltipItem: any) { - return tooltipItem.yLabel; + label: function (tooltipItem: any, data: any) { + return `POAM Status: ${data.datasets[tooltipItem.datasetIndex].label}`; } } }, @@ -116,13 +123,15 @@ export class PoamsComponent implements OnInit { private subs = new SubSink() - constructor(private poamService: PoamService, + constructor( + private poamService: PoamService, private theme: NbThemeService, private authService: AuthService, private router: Router, private readonly keycloak: KeycloakService, private userService: UsersService, - private treeviewI18nDefault: TreeviewI18n + private treeviewI18nDefault: TreeviewI18n, + private cdr: ChangeDetectorRef ) { } @@ -138,6 +147,10 @@ export class PoamsComponent implements OnInit { return itemsArray; } + updateChart() { + this.cdr.detectChanges(); + } + onSelectedChange(data: any) { // console.log("onSelectedChange data: ", data) if (data.length === 0 || !data) return; @@ -189,56 +202,40 @@ export class PoamsComponent implements OnInit { } setPayload() { - this.users = [] this.user = null; this.payload = null; - this.subs.sink = forkJoin( - this.userService.getUsers(), - ).subscribe(([users]: any) => { - console.log('users: ', users) - this.users = users.users.users - //console.log('this.users: ',this.users) - this.user = this.users.find((e: { userName: string; }) => e.userName === this.userProfile?.username) - console.log('this.user: ', this.user) - - if (this.user.accountStatus === 'ACTIVE') { - this.payload = Object.assign(this.user, { - collections: [] - }); - - // this.userService.getUser(this.payload.userId).subscribe((result: any) => { - // console.log("getUser(id) returned: ", result) - // }); - - this.subs.sink = forkJoin( - this.userService.getUserPermissions(this.user.userId) - ).subscribe(([permissions]: any) => { - // console.log("permissions: ", permissions) - - permissions.permissions.permissions.forEach((element: any) => { - // console.log("element: ",element) - let assigendCollections = { - collectionId: element.collectionId, - canOwn: element.canOwn, - canMaintain: element.canMaintain, - canApprove: element.canApprove, - } - // console.log("assignedCollections: ", assigendCollections) - this.payload.collections.push(assigendCollections); - }); - - console.log("payload: ", this.payload) - this.getPoamData(); - }) - - } else { - alert('Your account status is not Active, contact your system administrator') + this.subs.sink = this.userService.getCurrentUser().subscribe( + (response: any) => { + if (response && response.userId) { + this.user = response; + console.log('Current user: ', this.user); + + if (this.user.accountStatus === 'ACTIVE') { + this.payload = { + ...this.user, + collections: this.user.permissions.map((permission: Permission) => ({ + collectionId: permission.collectionId, + canOwn: permission.canOwn, + canMaintain: permission.canMaintain, + canApprove: permission.canApprove + })) + }; + + console.log("payload: ", this.payload); + this.getPoamData(); + } + } else { + console.error('User data is not available or user is not active'); + } + }, + (error) => { + console.error('An error occurred:', error); } - - }) + ); } + getPoamData() { this.subs.sink = forkJoin( this.poamService.getCollection(this.payload.lastCollectionAccessedId, this.payload.userName), @@ -288,7 +285,8 @@ export class PoamsComponent implements OnInit { color: chartjs.axisLineColor }, ticks: { - fontColor: chartjs.textColor + fontColor: chartjs.textColor, + beginAtZero: true } } ] @@ -376,7 +374,7 @@ export class PoamsComponent implements OnInit { this.filteredPoams.push(this.poams[i]); } } - // console.log("this.filteredPoams: ", this.filteredPoams) + //console.log("this.filteredPoams: ", this.filteredPoams) } this.sortData(); } diff --git a/Front End/poam-app/src/app/pages/user-processing/user-processing.component.html b/Front End/poam-app/src/app/pages/user-processing/user-processing.component.html index 043d3f4d..6c713ebd 100644 --- a/Front End/poam-app/src/app/pages/user-processing/user-processing.component.html +++ b/Front End/poam-app/src/app/pages/user-processing/user-processing.component.html @@ -53,16 +53,15 @@

Users

-
+
+ (selectedChange)="setUser($event)" placeholder="User" required> {{ user.firstName }} - {{ user.lastName }} - {{ user.accountStatus }}
-
diff --git a/Front End/poam-app/src/app/pages/user-processing/user-processing.component.ts b/Front End/poam-app/src/app/pages/user-processing/user-processing.component.ts index 57afea44..adfd1827 100644 --- a/Front End/poam-app/src/app/pages/user-processing/user-processing.component.ts +++ b/Front End/poam-app/src/app/pages/user-processing/user-processing.component.ts @@ -19,7 +19,13 @@ import { ConfirmationDialogComponent, ConfirmationDialogOptions } from '../../Sh import { KeycloakService } from 'keycloak-angular'; import { KeycloakProfile } from 'keycloak-js'; - +interface Permission { + userId: number; + collectionId: number; + canOwn: number; + canMaintain: number; + canApprove: number; +} interface TreeNode { data: T; children?: TreeNode[]; @@ -44,7 +50,7 @@ export class UserProcessingComponent implements OnInit { customColumn = 'user'; - defaultColumns = ['Status', 'First Name', 'Last Name', 'Email', 'Phone', 'Collection', 'Can Own', 'Can Maintain', 'Can Approve']; + defaultColumns = ['Status', 'First Name', 'Last Name', 'Email', 'Collection', 'Can Own', 'Can Maintain', 'Can Approve']; allColumns = [this.customColumn, ...this.defaultColumns]; dataSource!: NbTreeGridDataSource; @@ -87,149 +93,104 @@ export class UserProcessingComponent implements OnInit { } async ngOnInit() { - // this.subs.sink = this.authService.onTokenChange() - // .subscribe((token: NbAuthJWTToken) => { - // //if (token.isValid() && this.router.url === '/pages/collection-processing') { - // if (token.isValid()) { - // this.isLoading = true; - // this.payload = token.getPayload(); - - // this.selectedRole = 'admin'; - // this.data = []; - // this.getUserData(); - - // } - // }) - - this.isLoggedIn = await this.keycloak.isLoggedIn(); + this.isLoggedIn = await this.keycloak.isLoggedIn(); if (this.isLoggedIn) { this.userProfile = await this.keycloak.loadUserProfile(); - console.log("userProfile.email: ",this.userProfile.email,", userProfile.username: ",this.userProfile.username) + console.log("userProfile.email: ", this.userProfile.email, ", userProfile.username: ", this.userProfile.username) this.setPayload(); } } setPayload() { - this.users = [] - this.user.userId = 1; + this.user = null; this.payload = null; - this.subs.sink = forkJoin( - this.userService.getUsers(), - ).subscribe(([users]: any) => { - // console.log('users: ',users) - this.users = users.users.users - console.log('ALl users: ',this.users) - this.user = null; - this.user = this.users.find((e: { userName: string; }) => e.userName === this.userProfile?.username) - console.log('this.user: ',this.user) - this.payload = Object.assign(this.user, { - collections: [] - }); - - this.subs.sink = forkJoin( - this.userService.getUserPermissions(this.user.userId) - ).subscribe(([permissions]: any) => { - console.log("permissions: ", permissions) - - permissions.permissions.permissions.forEach((element: any) => { - // console.log("element: ",element) - let assigendCollections = { - collectionId: element.collectionId, - canOwn: element.canOwn, - canMaintain: element.canMaintain, - canApprove: element.canApprove, + this.subs.sink = this.userService.getCurrentUser().subscribe( + (response: any) => { + if (response && response.userId) { + this.user = response; + console.log('Current user: ', this.user); + + if (this.user.accountStatus === 'ACTIVE') { + this.payload = { + ...this.user, + collections: this.user.permissions.map((permission: Permission) => ({ + collectionId: permission.collectionId, + canOwn: permission.canOwn, + canMaintain: permission.canMaintain, + canApprove: permission.canApprove + })) + }; + + console.log("payload: ", this.payload); + + // Check if the user is an admin before calling getUserData + if (this.user.isAdmin === 1) { + this.getUserData(); + } else { + console.log('Access Denied: User is not an admin.'); + } } - // console.log("assignedCollections: ", assigendCollections) - this.payload.collections.push(assigendCollections); - }); - - console.log("payload: ",this.payload) - - this.getUserData(); - }) - - - }) + } else { + console.error('User data is not available or user is not active'); + } + }, + (error) => { + console.error('An error occurred:', error); + } + ); } + getUserData() { this.isLoading = true; this.users = []; this.userService.getUsers().subscribe((rData: any) => { this.data = rData.users.users; this.users = this.data; - //console.log("this.data: ",this.data) this.getUsersGrid(""); this.isLoading = false; }); } - async getUsersGrid(filter: string) { + getUsersGrid(filter: string) { let userData = this.data; - console.log("userData: ", userData) + console.log("userData: ", userData); let mydata: any = []; + for (let i = 0; i < userData.length; i++) { - await this.userService.getUserPermissions(userData[i].userId).subscribe((permissions: any) => { - let tchild: any = []; - console.log("permissions.permissions: ", permissions.permissions.permissions.length) - let userPermissions = permissions.permissions.permissions; - console.log("userPermissions: ", userPermissions) - if (userPermissions.length > 0) { - userPermissions.forEach((permission: any) => { - console.log("permissions: ", permission) - tchild.push({ - data: { - user: '', 'Status': '', 'First Name': '', 'Last Name': '', 'Email': '', - 'Phone': '', 'Collection': 'waiting on api', - 'Can Own': (permission.canOwn == 1) ? 'true' : 'false' , - 'Can Maintain': (permission.canMaintain == 1) ? 'true' : 'false', - 'Can Approve': (permission.canApprove == 1) ? 'true' : 'false' - } - }) + let tchild: any = []; + let userPermissions = userData[i].permissions; + + if (userPermissions && userPermissions.length > 0) { + userPermissions.forEach((permission: any) => { + tchild.push({ + data: { + user: '', 'Status': '', 'First Name': '', 'Last Name': '', 'Email': '', + 'Phone': '', + 'Collection': permission.collectionId, + 'Can Own': permission.canOwn == 1 ? 'True' : 'False', + 'Can Maintain': permission.canMaintain == 1 ? 'True' : 'False', + 'Can Approve': permission.canApprove == 1 ? 'True' : 'False' + } }); - } - - console.log("tChild: ", tchild) - mydata.push({ - data: { - user: userData[i].userId, 'Status': userData[i].accountStatus, 'First Name': userData[i].firstName, 'Last Name': userData[i].lastName, - 'Email': userData[i].userEmail, 'Phone': userData[i].phoneNumber - }, children: tchild }); + } - - // var treeViewData: TreeNode[] = userData.map((user: { - // userId: number | any[]; accountStatus: any; firstName: any; - // lastName: any; userEmail: any; phoneNumber: any; - // }) => { - // let children: any = []; - // //children = tchild; - - - - // // children.push({data: { user: '', 'Status': '', 'First Name': '', 'Last Name': '', 'Email': '', - // // 'Phone': '', 'Collection': 'TEST TEST', 'Can Own': 'true', 'Can Maintain': 'false', 'Can Approve': 'true'} }) - - // // return { - - // // data: { user: user.userId, 'Status': user.accountStatus, 'First Name': user.firstName, 'Last Name': user.lastName, - // // 'Email': user.userEmail, 'Phone': user.phoneNumber}, - // // children: children - // // }; - // }) - console.log("treeViewData: ", mydata) - this.dataSource = this.dataSourceBuilder.create(mydata); - + mydata.push({ + data: { + user: userData[i].userId, 'Status': userData[i].accountStatus, 'First Name': userData[i].firstName, 'Last Name': userData[i].lastName, + 'Email': userData[i].userEmail, 'Phone': userData[i].phoneNumber + }, children: tchild }); - } - //if (filter) { collectionData = this.data.filter((collection: { collectionId: string; }) => collection.collectionId === filter); } - + this.dataSource = this.dataSourceBuilder.create(mydata); } + + setUser(userId: any) { this.user = null; diff --git a/Front End/poam-app/src/app/pages/user-processing/user-processing.module.ts b/Front End/poam-app/src/app/pages/user-processing/user-processing.module.ts index 621791f6..6d12c745 100644 --- a/Front End/poam-app/src/app/pages/user-processing/user-processing.module.ts +++ b/Front End/poam-app/src/app/pages/user-processing/user-processing.module.ts @@ -16,7 +16,7 @@ import { UserProcessingRoutingModule } from './user-processing.routing'; import { SharedModule } from '../../Shared/shared.module'; import { UserComponent } from './user/user.component'; import { ConfirmationDialogComponent } from 'src/app/Shared/components/confirmation-dialog/confirmation-dialog.component'; -import { NbButtonModule, NbCardModule,NbLayoutModule, NbTreeGridModule, NbSpinnerModule, NbSelectModule, NbIconModule, NbCheckboxModule } from '@nebular/theme'; +import { NbButtonModule, NbInputModule, NbToggleModule, NbCardModule,NbLayoutModule, NbTreeGridModule, NbSpinnerModule, NbSelectModule, NbIconModule, NbCheckboxModule } from '@nebular/theme'; import { Ng2SmartTableModule } from 'ng2-smart-table'; @NgModule({ @@ -32,9 +32,11 @@ import { Ng2SmartTableModule } from 'ng2-smart-table'; NbCardModule, NbCheckboxModule, NbIconModule, + NbInputModule, NbLayoutModule, NbSelectModule, NbSpinnerModule, + NbToggleModule, NbTreeGridModule, Ng2SmartTableModule, SharedModule, diff --git a/Front End/poam-app/src/app/pages/user-processing/user/user.component.html b/Front End/poam-app/src/app/pages/user-processing/user/user.component.html index 0a536a27..e3d508b0 100644 --- a/Front End/poam-app/src/app/pages/user-processing/user/user.component.html +++ b/Front End/poam-app/src/app/pages/user-processing/user/user.component.html @@ -13,12 +13,12 @@
- -      - + + + -      - + +

@@ -26,33 +26,35 @@
-                - + + -                  - + + (ngModelChange)='onSelectedThemeChange($event)'> Pending Active Expired -             - Is Admin + + Grant Admin Privileges
-
+
>
-
@@ -64,8 +66,8 @@
- - + +
diff --git a/Front End/poam-app/src/app/pages/user-processing/user/user.component.ts b/Front End/poam-app/src/app/pages/user-processing/user/user.component.ts index ec5a7c50..b7fe8104 100644 --- a/Front End/poam-app/src/app/pages/user-processing/user/user.component.ts +++ b/Front End/poam-app/src/app/pages/user-processing/user/user.component.ts @@ -15,6 +15,20 @@ import { SubSink } from 'subsink'; import { forkJoin, Observable } from 'rxjs'; import { UsersService } from '../users.service' +interface Permission { + userId: number; + collectionId: number; + canOwn: number; + canMaintain: number; + canApprove: number; +} +export interface CollectionsResponse { + collections: Array<{ + collectionId: number; + collectionName: string; + }>; +} + @Component({ selector: 'ngx-user', templateUrl: './user.component.html', @@ -27,12 +41,11 @@ export class UserComponent implements OnInit { @Input() payload: any; @Output() userchange = new EventEmitter(); checked: boolean = false; - isLoading: boolean = true; collectionList: any; collectionPermissions: any[] = []; data: any = []; - + editedRows: any[] = []; modalWindow: NbWindowRef | undefined dialog!: TemplateRef; @@ -61,16 +74,11 @@ export class UserComponent implements OnInit { }, columns: { collectionId: { - title: '*Collection', + title: 'Collections', type: 'html', valuePrepareFunction: (_cell: any, row: any) => { - //console.log("row: ", row); - var collection = (row.collectionId != undefined && row.collectionId != null) ? this.collectionList.find((tl: any) => tl.collectionId === row.collectionId) : null; - return (collection) - ? collection.collectionName - : row.collectionId; - } - , + return row.collectionId + }, editor: { type: 'list', config: { @@ -145,69 +153,119 @@ export class UserComponent implements OnInit { constructor(private dialogService: NbDialogService, private userService: UsersService, - // private iconLibraries: NbIconLibraries ) { } ngOnInit(): void { - console.log("init user: ", this.user) - if (this.user.isAdmin == 1) this.checked = true; - this.data = this.user; - this.getData(); + this.isLoading = true; + + if (!this.user || !this.user.userId) { + this.userService.getCurrentUser().subscribe( + currentUser => { + this.user = currentUser; + + if (this.user.isAdmin == 1) { + this.checked = true; + } + this.loadCollections(); + this.getData(); + this.isLoading = false; + }, + error => { + console.error('Error fetching current user', error); + this.isLoading = false; + } + ); + } else { + this.loadUserData(this.user.userId); + } + } + + private loadUserData(userId: number): void { + this.userService.getUser(userId).subscribe( + userData => { + this.user = userData; + this.loadCollections(); + this.getData(); + this.isLoading = false; + }, + error => { + console.error('Error fetching user data', error); + this.isLoading = false; + } + ); + } + + private loadCollections(): void { + this.userService.getCurrentUser().subscribe( + currentUser => { + this.userService.getCollections(currentUser.userName).subscribe( + (response: CollectionsResponse) => { + this.collectionList = []; + response.collections.forEach(collection => { + this.collectionList.push({ + title: collection.collectionName, + value: collection.collectionId.toString() + }); + }); + this.updateCollectionSettings(); + }, + error => { + console.error('Error fetching collections', error); + } + ); + }, + error => { + console.error('Error fetching current user for collections', error); + } + ); + } + + private updateCollectionSettings(): void { + let settings = this.collectionPermissionsSettings; + settings.columns.collectionId.editor.config.list = this.collectionList.map((collection: any) => ({ + title: collection.title, + value: collection.value + })); + this.collectionPermissionsSettings = { ...settings }; } - onSubmit() { + onSubmit() { this.isLoading = true; this.userService.updateUser(this.user).subscribe(user => { - //this.data = permissionData; - //console.log("after updatePermission, permissionData: ",permissionData) - // event.confirm.resolve(); - // this.getData(); this.userchange.emit(); }); - - } ngOnChanges() { this.getData(); } getData() { + if (this.user && Array.isArray(this.user.permissions)) { + this.collectionPermissions = this.user.permissions.map((permission: Permission) => ({ + collectionId: permission.collectionId, + canOwn: permission.canOwn, + canMaintain: permission.canMaintain, + canApprove: permission.canApprove + })); + } else { + console.error('User or permissions data is not available'); + } - console.log("user.getData() user: ", this.user) - - this.subs.sink = forkJoin( - this.userService.getCollections(this.user.userName), - this.userService.getCollections(this.payload.userName), - this.userService.getUserPermissions(this.user.userId) - ) - .subscribe(([collections, availableCollections, permissions]: any) => { - - this.collectionList = collections.collections; - if (this.collectionList.length == 0) this.collectionList = availableCollections.collections; - this.collectionPermissions = permissions.permissions.permissions; - //console.log("collectionList: ", this.collectionList) - //console.log("collectionPermissions: ", this.collectionPermissions) - - let settings = this.collectionPermissionsSettings; - settings.columns.collectionId.editor.config.list = this.collectionList.map((collection: any) => { - //console.log("collection: ",collection) - return { - title: collection.collectionName, - value: collection.collectionId - } - }); - - this.collectionPermissionsSettings = Object.assign({}, settings); - this.isLoading = false; - }); + if (Array.isArray(this.collectionList)) { + let settings = this.collectionPermissionsSettings; + settings.columns.collectionId.editor.config.list = this.collectionList.map((collection: any) => ({ + collectionId: collection.collectionId + })) as any; + this.collectionPermissionsSettings = { ...settings }; + } else { + console.error('Available collection data is not available'); + } } - + confirmCreate(event: any) { - - // console.log("Attempting to confirmCreate()..."); if (this.user.userId && event.newData.collectionId && event.newData.canOwn && @@ -217,7 +275,6 @@ export class UserComponent implements OnInit { var collection_index = this.collectionList.findIndex((e: any) => e.collectionId == event.newData.collectionId); - // can't continue without collection data. NOTE** collection_index my be 0, if the 1st row is selected! if (!collection_index && collection_index != 0) { this.invalidData("Unable to resolve collection"); event.confirm.reject(); @@ -235,7 +292,6 @@ export class UserComponent implements OnInit { this.isLoading = true; this.userService.postPermission(collectionPermission).subscribe(permissionData => { this.isLoading = false; - //console.log("after postPermission, permissionData: ",permissionData) event.confirm.resolve(); this.getData(); }) @@ -256,8 +312,6 @@ export class UserComponent implements OnInit { var collection_index = this.collectionList.findIndex((e: any) => e.collectionId == event.newData.collectionId); - - // can't continue without collection data. NOTE** collection_index my be 0, if the 1st row is selected! if (!collection_index && collection_index != 0) { this.invalidData("Unable to resolve collection") event.confirm.reject(); @@ -286,6 +340,7 @@ export class UserComponent implements OnInit { } } + confirmDelete(event: any) { //console.log("Attempting to confirmDelete()...event.data: ",event.data); diff --git a/Front End/poam-app/src/app/pages/user-processing/users.model.ts b/Front End/poam-app/src/app/pages/user-processing/users.model.ts index 905f4fd6..60926b92 100644 --- a/Front End/poam-app/src/app/pages/user-processing/users.model.ts +++ b/Front End/poam-app/src/app/pages/user-processing/users.model.ts @@ -9,17 +9,18 @@ */ export interface Users { - userId: number; - userName: string; - userEmail: string; - firstName?: string; - lastName?: string; - created?: Date; - lastAccess?: Date; - lastCollectionAccessedId?: number; - phoneNumber?: string; - password?: string; - accountStatus: string; - fullName?: string; - defaultTheme?: string; - } + userId: number; + userName: string; + userEmail: string; + firstName: string; + lastName: string; + created: string; + lastAccess: string; + lastCollectionAccessedId: number; + phoneNumber: string; + password: string; + accountStatus: string; + fullName: string; + defaultTheme: string; + isAdmin: number; +} diff --git a/Front End/poam-app/src/app/pages/user-processing/users.service.ts b/Front End/poam-app/src/app/pages/user-processing/users.service.ts index 4a875d73..68719bfa 100644 --- a/Front End/poam-app/src/app/pages/user-processing/users.service.ts +++ b/Front End/poam-app/src/app/pages/user-processing/users.service.ts @@ -10,10 +10,12 @@ import { EventEmitter, Injectable, Output } from '@angular/core'; import { HttpClient, HttpParams, HttpHeaders, HttpErrorResponse } from '@angular/common/http'; -import { Observable, throwError } from 'rxjs'; -import { catchError } from 'rxjs/operators'; +import { KeycloakService } from 'keycloak-angular'; +import { from, Observable, throwError } from 'rxjs'; +import { switchMap, catchError } from 'rxjs/operators'; import { environment } from '../../../environments/environment'; import { Users } from './users.model'; +import { CollectionsResponse } from '../user-processing/user/user.component'; @Injectable({ providedIn: 'root' @@ -29,7 +31,9 @@ export class UsersService { }) }; - constructor(private http: HttpClient) { } + constructor(private http: HttpClient, + private keycloakService: KeycloakService) { + } private handleError(error: HttpErrorResponse) { if (error.error instanceof ErrorEvent) { @@ -57,7 +61,20 @@ export class UsersService { return this.http .get(`${this.uri}/user/${id}`) .pipe(catchError(this.handleError)); - } + } + + getCurrentUser(): Observable { + return from(this.keycloakService.getToken()).pipe( + switchMap(token => { + const headers = new HttpHeaders({ + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${token}` + }); + return this.http.get(`${this.uri}/user`, { headers: headers }); + }), + catchError(this.handleError) + ); + } getUsers() { //console.log("Users Service Call attempted: getUsers()..."); @@ -66,25 +83,20 @@ export class UsersService { .pipe(catchError(this.handleError)); } - getCollections(userName: string) { - // console.log("UserService Call attempted: getCollections()..."); - let params = new HttpParams() - //let myName = { userName: userName} - params = params.append("userName", userName) - return this.http - .get(`${this.uri}/collections/`, { params } ) - .pipe(catchError(this.handleError)); - } + getCollections(userName: string): Observable { + let params = new HttpParams().set('userName', userName); + return this.http.get(`${this.uri}/collections/`, { params }) + .pipe(catchError(this.handleError)); + } getUserPermissions(id: any) { - //console.log("UsersService Call attempted: getUserPermissions(id)...id: ", id); return this.http .get(`${this.uri}/permissions/user/${id}`) .pipe(catchError(this.handleError)); } updateUser(userData: any) { - let user = { userID: userData.userId, + let user = { userId: userData.userId, firstName: userData.firstName, lastName: userData.lastName, userEmail: userData.userEmail, @@ -109,12 +121,12 @@ export class UsersService { .pipe(catchError(this.handleError)); } - getAUserPermission(userId: any, collectionId: any) { - //console.log("UsersService Call attempted: getAUserPermission(userPermission)...userId: ", userId,", collectionId: ", collectionId); - return this.http - .get(`${this.uri}/permissions/user/${userId}/collection/${collectionId}`, this.httpOptions) - .pipe(catchError(this.handleError)); - } + //getAUserPermission(userId: any, collectionId: any) { + // //console.log("UsersService Call attempted: getAUserPermission(userPermission)...userId: ", userId,", collectionId: ", collectionId); + // return this.http + // .get(`${this.uri}/permissions/user/${userId}/collection/${collectionId}`, this.httpOptions) + // .pipe(catchError(this.handleError)); + //} postPermission(userPermission: any) { //console.log("UsersService Call attempted: postPermission(userPermission)...userPermission: ", userPermission);