From 4b3d808192bc894d6f77a81d62fdee5f8ccec853 Mon Sep 17 00:00:00 2001 From: A Repko Date: Sat, 28 Sep 2024 17:00:43 +0200 Subject: [PATCH 01/24] Added invite list to admin dashboard --- .../dashboard/components/InviteList.tsx | 56 +++++++++++++++ .../dashboard/components/adminPage.tsx | 68 +++++++++---------- CoVAR-app/src/functions/requests.tsx | 11 +++ langchain/requirements.txt | 3 +- server/routes/invites.js | 29 ++++++-- 5 files changed, 125 insertions(+), 42 deletions(-) create mode 100644 CoVAR-app/src/app/(pages)/dashboard/components/InviteList.tsx diff --git a/CoVAR-app/src/app/(pages)/dashboard/components/InviteList.tsx b/CoVAR-app/src/app/(pages)/dashboard/components/InviteList.tsx new file mode 100644 index 0000000..a5b5b0f --- /dev/null +++ b/CoVAR-app/src/app/(pages)/dashboard/components/InviteList.tsx @@ -0,0 +1,56 @@ +'use client'; +import React, { useEffect, useState } from 'react'; +import { Paper, Typography, Box, CircularProgress, List, ListItem, ListItemText } from '@mui/material'; +import { fetchAllInvites } from '@/functions/requests'; + +type Invite = { + invite_id: string; + username: string; + organization_name: string; + invite_status: string; +}; + +const InviteList: React.FC = () => { + const [invites, setInvites] = useState([]); + const [loading, setLoading] = useState(true); + + useEffect(() => { + const loadInvites = async () => { + try { + const token = localStorage.getItem('accessToken'); + const invites = await fetchAllInvites(token as string); + setInvites(invites); + setLoading(false); + } catch (error) { + console.error('Error fetching invites:', error); + setLoading(false); + } + }; + + loadInvites(); + }, []); + + return ( + + Pending Invites + {loading ? ( + + ) : invites.length === 0 ? ( + No pending invites at the moment. + ) : ( + + {invites.map((invite) => ( + + + + ))} + + )} + + ); +}; + +export default InviteList; diff --git a/CoVAR-app/src/app/(pages)/dashboard/components/adminPage.tsx b/CoVAR-app/src/app/(pages)/dashboard/components/adminPage.tsx index 558ebf2..de242b9 100644 --- a/CoVAR-app/src/app/(pages)/dashboard/components/adminPage.tsx +++ b/CoVAR-app/src/app/(pages)/dashboard/components/adminPage.tsx @@ -10,6 +10,8 @@ import { Height } from '@mui/icons-material'; import { mainContentStyles } from '@/styles/sidebarStyle'; import SeverityDistribution from './severityDistribution'; import { chartContainerStyles } from '@/styles/dashboardStyle'; +import InviteList from './InviteList'; // Import the new component + type User = { user_id: string; @@ -160,49 +162,47 @@ const AdminPage: React.FC = () => { { name: 'Clients', value: userMetrics.clients }, ]; - return ( - - - - - User Metrics - - - - - - Total Users: {userMetrics.total} - Admins: {userMetrics.admins} - VAs: {userMetrics.vas} - Clients: {userMetrics.clients} - + return ( + + + + User Metrics + + + + + Total Users: {userMetrics.total} + Admins: {userMetrics.admins} + VAs: {userMetrics.vas} + Clients: {userMetrics.clients} + + + Role Distribution - - - - - - - Unauthorised Users (Last Week) - - + + + + + + + + Unauthorised Users (Last Week) + + {loading ? ( ) : ( - - row.user_id} - sx = {{...dataGridStyles, - height : '50vh' - }} - /> + row.user_id} + sx={{ ...dataGridStyles, height: '50vh' }} + /> )} { }; return await handleRequest(request); }; + + +// Function to fetch all invites +export const fetchAllInvites = async (accessToken: string) => { + const request = { + method: 'get', + url: `/api/invites`, + headers: { Authorization: `Bearer ${accessToken}` }, + }; + return await handleRequest(request); +}; diff --git a/langchain/requirements.txt b/langchain/requirements.txt index 486b3b5..a92d38e 100644 --- a/langchain/requirements.txt +++ b/langchain/requirements.txt @@ -9,4 +9,5 @@ requests python-dotenv openai PyJWT -cryptography \ No newline at end of file +cryptography +gunicorn \ No newline at end of file diff --git a/server/routes/invites.js b/server/routes/invites.js index 1a65236..39cd5a3 100644 --- a/server/routes/invites.js +++ b/server/routes/invites.js @@ -1,12 +1,9 @@ const express = require('express'); - -const { authenticateToken} = require('../lib/securityFunctions'); - +const { authenticateToken } = require('../lib/securityFunctions'); const pgClient = require('../lib/postgres'); - const router = express.Router(); -// Fetch invites for a user +// Fetch invites for a specific user router.get('/invites/:username', authenticateToken, async (req, res) => { const { username } = req.params; @@ -19,7 +16,7 @@ router.get('/invites/:username', authenticateToken, async (req, res) => { const userId = userResult.rows[0].user_id; - // Fetch invites for the user + // Fetch pending invites for the user const invitesQuery = ` SELECT i.invite_id, o.name as organization_name, i.invite_status FROM organization_invites i @@ -82,5 +79,23 @@ router.patch('/invites/:inviteId/reject', authenticateToken, async (req, res) => } }); +// Fetch all invites +router.get('/invites', authenticateToken, async (req, res) => { + try { + const invitesQuery = ` + SELECT i.invite_id, u.username, o.name as organization_name, i.invite_status + FROM organization_invites i + JOIN organizations o ON i.organization_id = o.organization_id + JOIN users u ON i.user_id = u.user_id + `; + const invitesResult = await pgClient.query(invitesQuery); + + res.json(invitesResult.rows); + } catch (err) { + console.error(err.message); + res.status(500).send('Server Error'); + } +}); + -module.exports = router; \ No newline at end of file +module.exports = router; From 8f6be7c11aa0f005fdc341985635cea3a4f815bb Mon Sep 17 00:00:00 2001 From: Alec Watson Date: Sat, 28 Sep 2024 18:25:13 +0200 Subject: [PATCH 02/24] Fix for lounge middleware and production changes --- .github/workflows/deploy.yml | 4 - CoVAR-app/src/app/(pages)/lounge/page.tsx | 100 +++++++++++----------- docker-compose.prod.yml | 22 +---- langchain/__pycache__/app.cpython-39.pyc | Bin 1407 -> 7217 bytes langchain/requirements.txt | 3 +- 5 files changed, 54 insertions(+), 75 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 1e921cc..1aad67e 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -77,8 +77,6 @@ jobs: - name: Create Pem Files run: | - echo ${{ secrets.PUBLIC }} > langchain/public.pem - echo ${{ secrets.PRIVATE }} > langchain/private.pem echo ${{ secrets.PUBLIC }} > server/public.pem echo ${{ secrets.PRIVATE }} > server/private.pem echo ${{ secrets.REFRESH_PUBLIC }} > server/refreshPublic.pem @@ -90,11 +88,9 @@ jobs: docker build -t 211125691345.dkr.ecr.eu-west-2.amazonaws.com/covar_api:latest ./server docker build -t 211125691345.dkr.ecr.eu-west-2.amazonaws.com/covar_client:latest ./CoVAR-app docker build -t 211125691345.dkr.ecr.eu-west-2.amazonaws.com/covar_nginx:latest ./nginx - docker build -t 211125691345.dkr.ecr.eu-west-2.amazonaws.com/covar_langchain:latest ./langchain docker push 211125691345.dkr.ecr.eu-west-2.amazonaws.com/covar_api:latest docker push 211125691345.dkr.ecr.eu-west-2.amazonaws.com/covar_client:latest docker push 211125691345.dkr.ecr.eu-west-2.amazonaws.com/covar_nginx:latest - docker push 211125691345.dkr.ecr.eu-west-2.amazonaws.com/covar_langchain:latest deploy-containers: runs-on: ubuntu-latest diff --git a/CoVAR-app/src/app/(pages)/lounge/page.tsx b/CoVAR-app/src/app/(pages)/lounge/page.tsx index b8a5b03..ed66803 100644 --- a/CoVAR-app/src/app/(pages)/lounge/page.tsx +++ b/CoVAR-app/src/app/(pages)/lounge/page.tsx @@ -8,12 +8,17 @@ import { useRouter } from 'next/navigation'; import { doSignOut } from '../../../functions/firebase/auth'; import axios from 'axios'; - - const Lounge: React.FC = () => { const router = useRouter(); const pollingRef = useRef(null); + // Clear the cookie on component mount + useEffect(() => { + console.log("chicken"); + // Clear the accessToken cookie + document.cookie = 'accessToken=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'; + }, []); + const handleSignOut = async () => { try { await doSignOut(); @@ -23,59 +28,56 @@ const Lounge: React.FC = () => { } }; -// Function to get the current user and check their role -const checkUserStatus = useCallback(async () => { - try { - const response = await axios.post( - '/api/getUser', - { accessToken: localStorage.getItem('accessToken') }, - { headers: { Authorization: `Bearer ${localStorage.getItem('accessToken')}` } } - ); - - const {role} = response.data; - console.log("Role:", role); - - if (role !== 'unauthorised') { - router.replace('/dashboard'); - } - - } catch (error) { - console.error('Error fetching user status:', error); - } -}, [router]); - -// Start polling every 5 seconds -const startPolling = useCallback(() => { - if (!pollingRef.current) { - pollingRef.current = setInterval(() => { - checkUserStatus(); - }, 5000); - } -}, [checkUserStatus]); + // Function to get the current user and check their role + const checkUserStatus = useCallback(async () => { + try { + const response = await axios.post( + '/api/getUser', + { accessToken: localStorage.getItem('accessToken') }, + { headers: { Authorization: `Bearer ${localStorage.getItem('accessToken')}` } } + ); + const { role } = response.data; + console.log("Role:", role); + if (role !== 'unauthorised') { + router.replace('/dashboard'); + } -const stopPolling = useCallback(() => { - if (pollingRef.current) { - clearInterval(pollingRef.current); - pollingRef.current = null; - } -}, []); + } catch (error) { + console.error('Error fetching user status:', error); + } + }, [router]); + + // Start polling every 5 seconds + const startPolling = useCallback(() => { + if (!pollingRef.current) { + pollingRef.current = setInterval(() => { + checkUserStatus(); + }, 5000); + } + }, [checkUserStatus]); + const stopPolling = useCallback(() => { + if (pollingRef.current) { + clearInterval(pollingRef.current); + pollingRef.current = null; + } + }, []); -useEffect(() => { - startPolling(); + useEffect(() => { + startPolling(); - return () => { - stopPolling(); - }; -}, [startPolling, stopPolling]); + return () => { + stopPolling(); + }; + }, [startPolling, stopPolling]); return ( -

+
CoVAR @@ -86,14 +88,14 @@ useEffect(() => { Please wait here until an administrator verifies your account. -

-

+
+
-

-

-

+
+
+