Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
947c325
Added an API that fetches all the admins
ntrehan Oct 8, 2024
76f2927
Added API that fetches all projectManagers
ntrehan Oct 21, 2024
5e8ea4a
Merge branch 'development' of https://github.com/hackforla/vrms into …
ntrehan Oct 21, 2024
460068f
Fixes to issue #1752
jng34 Oct 29, 2024
ee1f3f4
fixes #1752
jng34 Oct 29, 2024
7c842cc
Add redesigned Users page
vorleakyek Oct 17, 2024
7d5bfe9
Create redesigned Users page with two buttons link to users-search an…
vorleakyek Oct 19, 2024
29f1c9b
undo deletion of package.json and yarn.lock
vorleakyek Oct 28, 2024
abdc330
Update div to box
vorleakyek Oct 31, 2024
1819aad
PR #1808 update & fixes
jng34 Nov 5, 2024
95e3814
Add redesigned Users page
vorleakyek Oct 17, 2024
663e4c5
Create redesigned Users page with two buttons link to users-search an…
vorleakyek Oct 19, 2024
6d7b3fd
undo deletion of package.json and yarn.lock
vorleakyek Oct 28, 2024
b02b441
Update div to box
vorleakyek Oct 31, 2024
3123e02
Add search functionality and link to the user profile
vorleakyek Nov 11, 2024
bbf2963
add comments for clarification
vorleakyek Nov 11, 2024
c91b2e6
Merge branch 'development' into filteredPermissionsDataComp
jng34 Nov 28, 2024
ed2661f
Merge pull request #1831 from ntrehan/1769
trillium Jan 21, 2025
88f9b77
Merge pull request #1832 from vorleakyek/redesign-users-screen-1751
trillium Jan 21, 2025
9898ba9
Merge branch 'user_permissions_search' into filtered-permission-1754
trillium Jan 21, 2025
2953cae
Merge pull request #1833 from vorleakyek/filtered-permission-1754
trillium Jan 21, 2025
8b4b5d6
Merge branch 'user_permissions_search' into filteredPermissionsDataComp
trillium Jan 21, 2025
2138f31
Merge pull request #1834 from jng34/filteredPermissionsDataComp
trillium Jan 21, 2025
a536ef3
Merge pull request #1835 from ntrehan/1771
trillium Jan 21, 2025
ca8449d
remove dummy data and hook up API for admins
vorleakyek Jan 28, 2025
306ef90
hook up project manager API to display the data on the console
vorleakyek Jan 30, 2025
20727b1
Updated the project managers API and display the data for the project…
vorleakyek Jan 31, 2025
9b45efa
Update the filtered data to show users with 'superadmin'
vorleakyek Feb 4, 2025
f15a433
Refactor the code in the backend to make it cleaner
vorleakyek Feb 5, 2025
36da6f7
Merge branch 'development' into user_permissions_search
trillium Feb 10, 2025
b82ad0e
resolve the empty nav element and remove the dummy data comment
vorleakyek Feb 11, 2025
cfd85f4
Merge branch 'development' into user_permissions_search
trillium Feb 11, 2025
2e49857
Update the API to fetch the project leads and the frontend to work pr…
vorleakyek Feb 18, 2025
4306fea
remove console log
vorleakyek Feb 19, 2025
7d81629
Merge branch 'development' into user_permissions_search
JackHaeg Feb 25, 2025
f71c70f
Merge branch 'development' into user_permissions_search
jng34 Feb 25, 2025
c13569b
Merge branch 'development' into user_permissions_search
trillium Mar 4, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 8 additions & 9 deletions backend/controllers/project.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ ProjectController.project_list = async function (req, res) {
}
};

ProjectController.pm_filtered_projects = async function(req, res) {
ProjectController.pm_filtered_projects = async function (req, res) {
try {
const projectList = await Project.find({})
const projects = projectList.filter(proj => req.body.includes(proj._id.toString()))
return res.status(200).send(projects)
} catch(e) {
return res.sendStatus(400)
const projectList = await Project.find({});
const projects = projectList.filter((proj) => req.body.includes(proj._id.toString()));
return res.status(200).send(projects);
} catch (e) {
return res.sendStatus(400);
}
}
};

ProjectController.create = async function (req, res) {
const { body } = req;
Expand All @@ -48,7 +48,7 @@ ProjectController.project_by_id = async function (req, res) {
ProjectController.update = async function (req, res) {
const { ProjectId } = req.params;
try {
const project = await Project.findOneAndUpdate({_id: ProjectId}, req.body, {new: true});
const project = await Project.findOneAndUpdate({ _id: ProjectId }, req.body, { new: true });
return res.status(200).send(project);
} catch (err) {
return res.sendStatus(400);
Expand All @@ -66,5 +66,4 @@ ProjectController.destroy = async function (req, res) {
}
};


module.exports = ProjectController;
77 changes: 65 additions & 12 deletions backend/controllers/user.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const jwt = require('jsonwebtoken');
const EmailController = require('./email.controller');
const { CONFIG_AUTH } = require('../config');

const { User } = require('../models');
const { User, Project } = require('../models');

const expectedHeader = process.env.CUSTOM_REQUEST_HEADER;

Expand All @@ -26,6 +26,63 @@ UserController.user_list = async function (req, res) {
}
};

// Get list of Users with accessLevel 'admin' or 'superadmin' with GET
UserController.admin_list = async function (req, res) {
const { headers } = req;

if (headers['x-customrequired-header'] !== expectedHeader) {
return res.sendStatus(403);
}

try {
const admins = await User.find({ accessLevel: { $in: ['admin', 'superadmin'] } });
return res.status(200).send(admins);
} catch (err) {
return res.sendStatus(400);
}
};

// Get list of Users with accessLevel 'admin' or 'superadmin' and also managed projects with GET
UserController.projectLead_list = async function (req, res) {
const { headers } = req;

if (headers['x-customrequired-header'] !== expectedHeader) {
return res.sendStatus(403);
}

try {
const projectManagers = await User.find({
$and: [
{ accessLevel: { $in: ['admin', 'superadmin'] } },
{ managedProjects: { $exists: true, $type: 'array', $ne: [] } },
],
});

const updatedProjectManagers = [];

for (const projectManager of projectManagers) {
const projectManagerObj = projectManager.toObject();
projectManagerObj.isProjectLead = true;
const projectNames = [];

for (const projectId of projectManagerObj.managedProjects) {
const projectDetail = await Project.findById(projectId);
if (projectDetail && projectDetail.name) {
projectNames.push(projectDetail.name);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should you return (push) the projectId in addition to the name?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jng34, The projectId is already included as part of the admins data. So, I think we don't need to push it.

The API for the admins is returning this data object
image

The API for the project leads is returning this data object
image

So, I want to check if we should include the isProjectLead and managedProjectNames properties in the API that fetches all the admin as well?
Thanks for taking a look at the code.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vorleakyek

Got it, thanks for the screenshots.

Regarding the isProjectLead and managedProjectNames properties, I think including those in the API fetch for admins would be a good idea if the user wants to know that info about a specific admin when clicking on his/her profile.

I guess that depends on what accessLevel ('user', 'admin', 'superadmin') does the user have and what info do we want each to be able to see.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your input @jng34!
@ntrehan, could you tell us what you think since you worked on the fetch admin API ticket?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per discussion with @trillium, it should be okay to not include isProjectLead and managedProjectNames as part of the admins API.

} else {
console.warn('Project detail is null, cannot access name');
}
}
projectManagerObj.managedProjectNames = projectNames;

updatedProjectManagers.push(projectManagerObj);
}
return res.status(200).send(updatedProjectManagers);
} catch (err) {
return res.sendStatus(400);
}
};

// Get User by id with GET
UserController.user_by_id = async function (req, res) {
const { headers } = req;
Expand All @@ -51,12 +108,11 @@ UserController.create = async function (req, res) {
return res.sendStatus(403);
}


try {
const newUser = {
...req.body,
email: req.body.email.toLowerCase()
}
const newUser = {
...req.body,
email: req.body.email.toLowerCase(),
};
const user = await User.create(newUser);
return res.status(201).send(user);
} catch (error) {
Expand All @@ -80,7 +136,7 @@ UserController.update = async function (req, res) {
}

try {
const user = await User.findOneAndUpdate({_id: UserId}, req.body, { new: true });
const user = await User.findOneAndUpdate({ _id: UserId }, req.body, { new: true });
return res.status(200).send(user);
} catch (err) {
return res.sendStatus(400);
Expand Down Expand Up @@ -192,10 +248,7 @@ UserController.verifyMe = async function (req, res) {
};

UserController.logout = async function (req, res) {
return res
.clearCookie('token')
.status(200)
.send('Successfully logged out.');
}
return res.clearCookie('token').status(200).send('Successfully logged out.');
};

module.exports = UserController;
5 changes: 2 additions & 3 deletions backend/routers/projects.router.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
const express = require("express");
const express = require('express');
const router = express.Router();

const { ProjectController } = require('../controllers');
const { AuthUtil } = require("../middleware");
const { AuthUtil } = require('../middleware');

// The base is /api/projects
router.get('/', ProjectController.project_list);
Expand All @@ -18,5 +18,4 @@ router.put('/:ProjectId', AuthUtil.verifyCookie, ProjectController.update);

router.patch('/:ProjectId', AuthUtil.verifyCookie, ProjectController.update);


module.exports = router;
4 changes: 4 additions & 0 deletions backend/routers/users.router.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ const { UserController } = require('../controllers');
// The base is /api/users
router.get('/', UserController.user_list);

router.get('/admins', UserController.admin_list);

router.get('/projectManagers', UserController.projectLead_list);

router.post('/', UserController.create);

router.get('/:UserId', UserController.user_by_id);
Expand Down
15 changes: 13 additions & 2 deletions client/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,17 @@ import HandleAuth from './components/auth/HandleAuth';
import EmailSent from './pages/EmailSent';
import Events from './pages/Events';
import ProjectLeaderDashboard from './pages/ProjectLeaderDashboard';
import Users from './pages/Users';
import UserAdmin from './pages/UserAdmin';
import ProjectList from './pages/ProjectList';
import ManageProjects from './pages/ManageProjects';
import addProject from './components/manageProjects/addProject';
import HealthCheck from './pages/HealthCheck';
import SecretPassword from './pages/SecretPassword';
import UserWelcome from './pages/UserWelcome';
// Added User Permission Search component
import UserPermissionSearch from './pages/UserPermissionSearch';
import UserPermission from './pages/UserPermission';

import { ThemeProvider } from '@mui/material';
import theme from './theme';
Expand All @@ -46,9 +50,16 @@ const routes = [
{ path: '/handleauth', name: 'handleauth', Component: HandleAuth },
{ path: '/emailsent', name: 'emailsent', Component: EmailSent },
{ path: '/events', name: 'events', Component: Events },
{ path: '/useradmin', name: 'useradmin', Component: UserAdmin },
{ path: '/users', name: 'users', Component: Users },

{ path: '/users/user-search', name: 'useradmin', Component: UserAdmin },
{
path: '/users/permission-search',
name: 'useradmin',
Component: UserPermission,
},
{ path: '/projects', name: 'projects', Component: ProjectList },
{ path: '/projects/create', name: 'projectform', Component: addProject},
{ path: '/projects/create', name: 'projectform', Component: addProject },
{
path: '/projects/:projectId',
name: 'project',
Expand Down
18 changes: 9 additions & 9 deletions client/src/api/ProjectApiService.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@ class ProjectApiService {
console.log('THIS BASEPROJECT URL', this.baseProjectUrl);

try {
const proj = await fetch(this.baseProjectUrl, requestOptions);
const projectDetails = await proj.json()
return projectDetails._id
const proj = await fetch(this.baseProjectUrl, requestOptions);
const projectDetails = await proj.json();
return projectDetails._id;
} catch (error) {
console.error(`Add project error: `, error);
alert('Server not responding. Please try again.');
Expand Down Expand Up @@ -87,13 +87,13 @@ class ProjectApiService {
async fetchPMProjects(projects) {
const requestOptions = {
headers: this.headers,
method: "PUT",
body: JSON.stringify(projects)
}
method: 'PUT',
body: JSON.stringify(projects),
};
try {
const res = await fetch(this.baseProjectUrl, requestOptions);
return await res.json();
} catch(e) {
const res = await fetch(this.baseProjectUrl, requestOptions);
return await res.json();
} catch (e) {
console.error(e);
return undefined;
}
Expand Down
28 changes: 28 additions & 0 deletions client/src/api/UserApiService.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,34 @@ class UserApiService {
return [];
}

async fetchAdmins() {
try {
const route = this.baseUserUrl + '/admins';
const res = await fetch(route, {
headers: this.headers,
});
return await res.json();
} catch (error) {
console.error(`fetchAdmins error: ${error}`);
alert('Server not responding. Please refresh the page.');
}
return [];
}

async fetchProjectsManagers() {
try {
const route = this.baseUserUrl + '/projectManagers';
const res = await fetch(route, {
headers: this.headers,
});
return await res.json();
} catch (error) {
console.error(`fetchProjectsManagers error: ${error}`);
alert('Server not responding. Please refresh the page.');
}
return [];
}

// Updates user projects in db
async updateUserDbProjects(userToEdit, managedProjects) {
// eslint-disable-next-line no-underscore-dangle
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/Navbar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ const Navbar = (props) => {
{/* Admin auth -> Displays 2 links -> 'Users' and 'Projects'. */}
{auth?.user?.accessLevel === 'admin' && (
<>
<StyledButton component={NavLink} to="/useradmin">
<StyledButton component={NavLink} to="/users">
USERS
</StyledButton>
<StyledButton component={NavLink} to="/projects">
Expand Down
Loading
Loading