├── Client
└── dashboard
│ ├── .gitignore
│ ├── package-lock.json
│ ├── package.json
│ ├── public
│ ├── favicon.ico
│ ├── index.html
│ ├── logo192.png
│ ├── logo512.png
│ ├── manifest.json
│ └── robots.txt
│ └── src
│ ├── App.css
│ ├── App.js
│ ├── charts
│ ├── BarChart.jsx
│ ├── DoughnutChart.jsx
│ ├── LineChart.jsx
│ ├── PieChart.jsx
│ ├── PolarChart.jsx
│ └── RadarChart.jsx
│ ├── components
│ ├── AccordionForCharts.jsx
│ ├── CardsForData.jsx
│ ├── Filters.jsx
│ ├── Header.jsx
│ └── Tabsrow.jsx
│ └── index.js
└── Server
├── .gitignore
├── app.js
├── controllers
└── index.js
├── database
└── index.js
├── models
└── index.js
├── package-lock.json
├── package.json
└── routes
└── index.js
/Client/dashboard/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/Client/dashboard/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "dashboard",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^5.16.5",
7 | "@testing-library/react": "^13.4.0",
8 | "@testing-library/user-event": "^13.5.0",
9 | "axios": "^1.4.0",
10 | "bootstrap": "^5.2.3",
11 | "chart.js": "^4.3.0",
12 | "react": "^18.2.0",
13 | "react-bootstrap": "^2.7.4",
14 | "react-chartjs-2": "^5.2.0",
15 | "react-dom": "^18.2.0",
16 | "react-scripts": "5.0.1",
17 | "web-vitals": "^2.1.4"
18 | },
19 | "scripts": {
20 | "start": "react-scripts start",
21 | "build": "react-scripts build",
22 | "test": "react-scripts test",
23 | "eject": "react-scripts eject"
24 | },
25 | "eslintConfig": {
26 | "extends": [
27 | "react-app",
28 | "react-app/jest"
29 | ]
30 | },
31 | "browserslist": {
32 | "production": [
33 | ">0.2%",
34 | "not dead",
35 | "not op_mini all"
36 | ],
37 | "development": [
38 | "last 1 chrome version",
39 | "last 1 firefox version",
40 | "last 1 safari version"
41 | ]
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Client/dashboard/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ayusharma-ctrl/Data_Visualization_Dashboard-MERN-Stack/d07ccbf1c8401b26da285ee5d03dcf66a5750427/Client/dashboard/public/favicon.ico
--------------------------------------------------------------------------------
/Client/dashboard/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | React App
28 |
29 |
30 | You need to enable JavaScript to run this app.
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/Client/dashboard/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ayusharma-ctrl/Data_Visualization_Dashboard-MERN-Stack/d07ccbf1c8401b26da285ee5d03dcf66a5750427/Client/dashboard/public/logo192.png
--------------------------------------------------------------------------------
/Client/dashboard/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ayusharma-ctrl/Data_Visualization_Dashboard-MERN-Stack/d07ccbf1c8401b26da285ee5d03dcf66a5750427/Client/dashboard/public/logo512.png
--------------------------------------------------------------------------------
/Client/dashboard/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/Client/dashboard/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/Client/dashboard/src/App.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700&display=swap');
2 |
3 | *{
4 | margin: 0;
5 | padding: 0;
6 | box-sizing: border-box;
7 | font-family: 'Inter', sans-serif;
8 | font-weight: 400;
9 | }
10 |
11 | .tabsClass {
12 | margin: 1vw 2vw;
13 | }
14 |
15 | .cardText {
16 | font-size: 0.8rem;
17 | white-space: nowrap;
18 | overflow: hidden;
19 | text-overflow: ellipsis;
20 | }
21 |
22 | .cardDiv {
23 | transition: transform 0.2s ease-in-out;
24 | }
25 |
26 | .cardDiv:hover{
27 | transform: scale(0.9);
28 | background-color: thistle;
29 | }
--------------------------------------------------------------------------------
/Client/dashboard/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react';
2 | import axios from 'axios';
3 | import './App.css';
4 |
5 | //import from files
6 | import Header from './components/Header';
7 | import Tabsrow from './components/Tabsrow';
8 |
9 |
10 | function App() {
11 | //state to save data received from the server
12 | const [mainData, setMainData] = useState([]);
13 | //asynchronous function to fetch data from server and updating the state
14 | const getDataFromDB = async() => {
15 | try{
16 | const response = await axios.get("https://dashboard-6bfs.onrender.com/api/data/all");
17 | setMainData(response.data.data)
18 | }
19 | catch(e){
20 | console.log(e)
21 | }
22 | }
23 | //calling the above function on first render
24 | useEffect(()=>{
25 | getDataFromDB();
26 | },[])
27 | //where a state is updated, we will print the length of data received just for the test purposes
28 | useEffect(()=>{
29 | console.log(mainData.length)
30 | },[mainData])
31 |
32 | return (
33 |
34 |
35 |
36 |
37 | );
38 | }
39 |
40 | export default App;
41 |
--------------------------------------------------------------------------------
/Client/dashboard/src/charts/BarChart.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Bar } from 'react-chartjs-2';
3 | import Chart from 'chart.js/auto';
4 |
5 |
6 | const BarChart = ({serverData}) => {
7 |
8 | let uniqueSectors = [];
9 |
10 | //using forEach because it doesn't return any array and we are adding unique sector names to an array
11 | serverData.forEach((i) => {
12 | if (!uniqueSectors.includes(i.sector) && i.sector !== "") {
13 | uniqueSectors.push(i.sector);
14 | }
15 | })
16 |
17 | // counting the total number of projects in each sector uniquely
18 | const sectorCount = uniqueSectors.map((item) => {
19 | return {
20 | sector: item,
21 | count: serverData.filter((i) => i.sector === item).length
22 | }
23 | })
24 |
25 |
26 | return (
27 |
28 | e),
31 | datasets: [
32 | {
33 | label: 'Total Projects',
34 | data: sectorCount.map(e=>e.count),
35 | borderWidth: 1,
36 | },
37 | // {
38 | // label: 'Quantity',
39 | // data: [7, 26, 111, 22, 11, 56]
40 | // }
41 | ]
42 | }}
43 | options={{
44 | maintainAspectRatio: false,
45 | scales: {
46 | y: {
47 | type: 'linear',
48 | beginAtZero: true,
49 | },
50 | }
51 | }}
52 | height={300}
53 |
54 | />
55 |
56 | )
57 | }
58 |
59 | export default BarChart
--------------------------------------------------------------------------------
/Client/dashboard/src/charts/DoughnutChart.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Doughnut } from 'react-chartjs-2';
3 | import Chart from 'chart.js/auto';
4 |
5 | const DoughnutChart = ({serverData}) => {
6 |
7 | let uniqueSectors = [];
8 | //using forEach because it doesn't return any array
9 | serverData.forEach((i) => {
10 | if (!uniqueSectors.includes(i.sector) && i.sector !== "") {
11 | uniqueSectors.push(i.sector);
12 | }
13 | })
14 |
15 | let uniqueTopics = [];
16 | serverData.forEach((i) => {
17 | if (!uniqueTopics.includes(i.topic) && i.topic !== "") {
18 | uniqueTopics.push(i.topic);
19 | }
20 | })
21 |
22 | let uniqueRegion = [];
23 | serverData.forEach((i) => {
24 | if (!uniqueRegion.includes(i.region) && i.region !== "") {
25 | uniqueRegion.push(i.region);
26 | }
27 | })
28 |
29 | let uniqueCountry = [];
30 | serverData.forEach((i) => {
31 | if (!uniqueCountry.includes(i.country) && i.country !== "") {
32 | uniqueCountry.push(i.country);
33 | }
34 | })
35 |
36 | let uniqueSource = [];
37 | serverData.forEach((i) => {
38 | if (!uniqueSource.includes(i.source) && i.source !== "") {
39 | uniqueSource.push(i.source);
40 | }
41 | })
42 |
43 | let uniquePestle = [];
44 | serverData.forEach((i) => {
45 | if (!uniquePestle.includes(i.pestle) && i.pestle !== "") {
46 | uniquePestle.push(i.pestle);
47 | }
48 | })
49 |
50 | const label = ["Country", "Region", "Source", "Topic", "Sector", "Pestle"];
51 | return (
52 |
53 |
77 |
78 | )
79 | }
80 |
81 | export default DoughnutChart
--------------------------------------------------------------------------------
/Client/dashboard/src/charts/LineChart.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Line } from 'react-chartjs-2';
3 | import Chart from 'chart.js/auto';
4 |
5 | const LineChart = ({serverData}) => {
6 |
7 | let uniquePestle = [];
8 | serverData.forEach((i) => {
9 | if (!uniquePestle.includes(i.pestle) && i.pestle !== "") {
10 | uniquePestle.push(i.pestle);
11 | }
12 | })
13 |
14 | const pestleCount = uniquePestle.map((item) => {
15 | return {
16 | pestle: item,
17 | count: serverData.filter((i) => i.pestle === item).length
18 | }
19 | })
20 |
21 | return (
22 |
23 | i.count),
30 | borderWidth: 1,
31 | },
32 | ]
33 | }}
34 | options={{
35 | maintainAspectRatio: false,
36 | scales: {
37 | y: {
38 | type: 'linear',
39 | beginAtZero: true
40 | },
41 | }
42 | }}
43 | height={300}
44 | />
45 |
46 | )
47 | }
48 |
49 | export default LineChart
--------------------------------------------------------------------------------
/Client/dashboard/src/charts/PieChart.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Pie } from 'react-chartjs-2';
3 | import Chart from 'chart.js/auto';
4 |
5 | const PieChart = ({serverData}) => {
6 | let uniquePestle = [];
7 |
8 | serverData.forEach((i) => {
9 | if (!uniquePestle.includes(i.pestle) && i.pestle !== "") {
10 | uniquePestle.push(i.pestle);
11 | }
12 | })
13 |
14 | const pestleCount = uniquePestle.map((item) => {
15 | return {
16 | pestle: item,
17 | count: serverData.filter((i) => i.pestle === item).length
18 | }
19 | })
20 |
21 | return (
22 |
23 |
i.count),
30 | borderWidth: 1,
31 | hoverOffset: 5,
32 | },
33 | ]
34 | }}
35 | options={{
36 | maintainAspectRatio: false,
37 | scales: {
38 | y: {
39 | type: 'linear',
40 | beginAtZero: true
41 | },
42 | }
43 | }}
44 | height={300}
45 | />
46 |
47 | )
48 | }
49 |
50 | export default PieChart
--------------------------------------------------------------------------------
/Client/dashboard/src/charts/PolarChart.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react'
2 | import { PolarArea } from 'react-chartjs-2';
3 | import Chart from 'chart.js/auto';
4 |
5 |
6 | const PolarChart = ({ serverData }) => {
7 |
8 | let uniqueSectors = [];
9 | //using forEach because it doesn't return any array
10 | serverData.forEach((i) => {
11 | if (!uniqueSectors.includes(i.sector) && i.sector !== "") {
12 | uniqueSectors.push(i.sector);
13 | }
14 | })
15 |
16 | let uniqueTopics = [];
17 | serverData.forEach((i) => {
18 | if (!uniqueTopics.includes(i.topic) && i.topic !== "") {
19 | uniqueTopics.push(i.topic);
20 | }
21 | })
22 |
23 | let uniqueRegion = [];
24 | serverData.forEach((i) => {
25 | if (!uniqueRegion.includes(i.region) && i.region !== "") {
26 | uniqueRegion.push(i.region);
27 | }
28 | })
29 |
30 | let uniqueCountry = [];
31 | serverData.forEach((i) => {
32 | if (!uniqueCountry.includes(i.country) && i.country !== "") {
33 | uniqueCountry.push(i.country);
34 | }
35 | })
36 |
37 | let uniqueSource = [];
38 | serverData.forEach((i) => {
39 | if (!uniqueSource.includes(i.source) && i.source !== "") {
40 | uniqueSource.push(i.source);
41 | }
42 | })
43 |
44 | let uniquePestle = [];
45 | serverData.forEach((i) => {
46 | if (!uniquePestle.includes(i.pestle) && i.pestle !== "") {
47 | uniquePestle.push(i.pestle);
48 | }
49 | })
50 |
51 | const label = ["Country", "Region", "Source", "Topic", "Sector", "Pestle"];
52 |
53 | return (
54 |
78 | )
79 | }
80 |
81 | export default PolarChart
--------------------------------------------------------------------------------
/Client/dashboard/src/charts/RadarChart.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Radar } from 'react-chartjs-2';
3 | import Chart from 'chart.js/auto';
4 |
5 | const RadarChart = ({serverData}) => {
6 |
7 | let uniquePestle = [];
8 |
9 | serverData.forEach((i) => {
10 | if (!uniquePestle.includes(i.pestle) && i.pestle !== "") {
11 | uniquePestle.push(i.pestle);
12 | }
13 | })
14 |
15 | const pestleCount = uniquePestle.map((item) => {
16 | return {
17 | pestle: item,
18 | count: serverData.filter((i) => i.pestle === item).length
19 | }
20 | })
21 |
22 | return (
23 |
24 | i.count),
31 | borderWidth: 1,
32 | },
33 | ]
34 | }}
35 | options={{
36 | maintainAspectRatio: false,
37 | scales: {
38 | y: {
39 | type: 'linear',
40 | beginAtZero: true
41 | },
42 | }
43 | }}
44 | height={300}
45 | />
46 |
47 | )
48 | }
49 |
50 | export default RadarChart
--------------------------------------------------------------------------------
/Client/dashboard/src/components/AccordionForCharts.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Accordion from 'react-bootstrap/Accordion';
3 |
4 | //import from files
5 | import BarChart from '../charts/BarChart';
6 | import PolarChart from '../charts/PolarChart';
7 | import LineChart from '../charts/LineChart';
8 | import RadarChart from '../charts/RadarChart';
9 | import DoughnutChart from '../charts/DoughnutChart';
10 | import PieChart from '../charts/PieChart';
11 |
12 | const AccordionForCharts = ({ data }) => {
13 | // defaultActiveKey="0"
14 | return (
15 |
16 |
17 |
18 | Polar Area and Doughnut Charts - represents number of countries, sectors, topics, pestles, sources, etc are involved
19 |
20 |
24 |
25 |
26 |
27 | Bar Chart- represents number of projects in each sector
28 |
29 |
30 |
31 |
32 |
33 | Line Chart- represents number of projects as per pestle
34 |
35 |
36 |
37 |
38 |
39 | Radar and Pie Charts- represents number of projects as per pestle
40 |
41 |
45 |
46 |
47 |
48 |
49 |
50 | )
51 | }
52 |
53 | export default AccordionForCharts
--------------------------------------------------------------------------------
/Client/dashboard/src/components/CardsForData.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Card from 'react-bootstrap/Card';
3 |
4 | // we are returning a dynamic bootstrap card
5 | const CardsForData = ({ item }) => {
6 | return (
7 |
8 |
9 |
10 | Project Details
11 | {item.sector ? item.sector : "Sector"}
12 |
13 |
14 | {item.topic ? item.topic : "No Info"}
15 | {item.title ? item.title : "No Info"}
16 | {item.insight ? item.insight : "No Info"}
17 | {item.url ? item.url : "No Info"}
18 | {item.region ? item.region : "No Info"}
19 | {item.country ? item.country : "No Info"}
20 | {item.source ? item.source : "No Info"}
21 | {item.pestle ? item.pestle : "No Info"}
22 | {item.start_year ? item.start_year : "No Info"}
23 | {item.end_year ? item.end_year : "No Info"}
24 | {item.added ? item.added : "No Info"}
25 | {item.published ? item.published : "No Info"}
26 | {item.intensity ? item.intensity : "No Info"}
27 | {item.likelihood ? item.likelihood : "No Info"}
28 |
29 |
30 |
31 |
32 |
33 | )
34 | }
35 |
36 | export default CardsForData
--------------------------------------------------------------------------------
/Client/dashboard/src/components/Filters.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Button from 'react-bootstrap/Button';
3 | import { Dropdown } from 'react-bootstrap';
4 | import axios from 'axios';
5 |
6 | // here we are returning a bootstrap dropdown and just a button
7 | const Filters = ({ setMainData }) => {
8 | //function to call the getDataFromDB function and passing the 'year' to it entered by the user
9 | const handleSelect = (eventKey, event) => {
10 | getDataFromDB(event.target.innerText)
11 | };
12 | // func to fetch the filtered data by year and update the state
13 | const getDataFromDB = async(year) => {
14 | try{
15 | const response = await axios.get(`https://dashboard-6bfs.onrender.com/api/data/year/${year}`);
16 | setMainData(response.data.data)
17 | }
18 | catch(e){
19 | console.log(e)
20 | }
21 | }
22 | // func to handle the "reset filters button" by making another api call and update state
23 | const handleReset = async() => {
24 | try{
25 | const response = await axios.get("https://dashboard-6bfs.onrender.com/api/data/all");
26 | setMainData(response.data.data)
27 | }
28 | catch(e){
29 | console.log(e)
30 | }
31 |
32 | }
33 |
34 | return (
35 |
36 |
37 |
38 |
39 |
40 | Filter By Year
41 |
42 |
43 |
44 | 2014
45 | 2015
46 | 2016
47 | 2017
48 | 2018
49 | 2019
50 | 2020
51 |
52 |
53 |
54 | Reset Filters
55 |
56 | )
57 | }
58 |
59 | export default Filters
--------------------------------------------------------------------------------
/Client/dashboard/src/components/Header.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Container from 'react-bootstrap/Container';
3 | import Navbar from 'react-bootstrap/Navbar';
4 |
5 | // we are using bootstrap navbar
6 | const Header = () => {
7 | return (
8 | <>
9 |
10 |
11 | Data Virtualization Dashboard
12 |
13 |
14 | >
15 | )
16 | }
17 |
18 | export default Header
--------------------------------------------------------------------------------
/Client/dashboard/src/components/Tabsrow.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import Tab from 'react-bootstrap/Tab';
3 | import Tabs from 'react-bootstrap/Tabs';
4 | import CardGroup from 'react-bootstrap/CardGroup';
5 | import Button from 'react-bootstrap/Button';
6 |
7 | //import from files
8 | import CardsForData from './CardsForData';
9 | import AccordionForCharts from './AccordionForCharts';
10 | import Filters from './Filters';
11 | import axios from 'axios';
12 |
13 | const Tabsrow = ({ data, setMainData }) => {
14 | // state to store the number of data cards we want to display at a time, we'll update it on click of a button
15 | const [limit, setLimit] = useState(5);
16 | const limitedData = data.slice(0, limit);
17 | // state to store the search bar text
18 | const [search, setSearch] = useState("");
19 | // function to make an api call to get the filtered data
20 | const handleSearchResult = async (e) => {
21 | e.preventDefault();
22 | try {
23 | const response = await axios.get(`https://dashboard-6bfs.onrender.com/api/data/any/${search}`);
24 | setMainData(response.data.data);
25 | setSearch("");
26 | }
27 | catch (e) {
28 | console.log(e)
29 | }
30 | }
31 |
32 | return (
33 |
34 |
39 |
40 |
44 |
45 |
46 | {limitedData && limitedData.length === 0 ? (
47 | No data found, or please wait for a while.
48 | ) : limitedData && limitedData.length > 0 ? (
49 |
50 | {limitedData.map((e, i) => {
51 | return
52 | })}
53 |
54 | ) : (
55 | Loading...
56 | )}
57 | setLimit(prev => prev + 5)}>Show More
58 |
59 |
60 |
64 |
65 |
66 |
67 |
68 |
69 | );
70 | }
71 |
72 | export default Tabsrow
--------------------------------------------------------------------------------
/Client/dashboard/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom/client';
3 | import App from './App';
4 | import 'bootstrap/dist/css/bootstrap.min.css';
5 |
6 | const root = ReactDOM.createRoot(document.getElementById('root'));
7 | root.render(
8 |
9 |
10 |
11 | );
12 |
--------------------------------------------------------------------------------
/Server/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | config.env
--------------------------------------------------------------------------------
/Server/app.js:
--------------------------------------------------------------------------------
1 | import express from 'express';
2 | import { config } from 'dotenv';
3 | import cors from 'cors';
4 |
5 | // import from files
6 | import reportRouter from './routes/index.js'
7 | import { mongoDB } from './database/index.js'
8 |
9 |
10 | //creates a new instance of an Express application
11 | const app = express();
12 |
13 | //setting up config.env file so that we can use content of it
14 | config({
15 | path: "./config.env"
16 | })
17 |
18 | //connecting server and database, just call this func^
19 | mongoDB();
20 |
21 |
22 | // <------------ middlewares ------------>
23 |
24 | //we'll be sending data in json format, that's why it is required to use this middleware
25 | app.use(express.json());
26 |
27 | //we'll be using dynamic routes, in order to read the data from url we have to use this
28 | app.use(express.urlencoded({ extended: true }));
29 |
30 | //set 'credentials: true' to pass --> headers, cookies, etc to browser/frontend
31 | app.use(cors({
32 | origin: [process.env.FRONTEND_URL],
33 | methods: ["GET", "POST", "PUT", "DELETE"],
34 | credentials: true,
35 | }))
36 |
37 | // route splitting
38 | app.use("/api/data", reportRouter)
39 |
40 | // <----------------------------------------------------------------------->
41 |
42 |
43 | // variables
44 | const PORT = process.env.PORT || 8000
45 |
46 |
47 | //it is a test route just to see our server is working
48 | app.get("/", (req, res) => {
49 | return res.send(`Welcome to Data Virtualization Server
50 |
Below are the some examples of supported routes...
51 |
52 | GET all data from the database - /api/data
53 | GET data filtered by year - /api/data/year/:year
54 | GET data filtered by region - /api/data/region/:region
55 | Much more...
56 |
57 |
`)
58 | })
59 |
60 |
61 | //function is used to bind and listen to the connections on the specified host and port
62 | app.listen(PORT, (req, res) => {
63 | console.log(`Server is active on Port ${PORT}`)
64 | })
--------------------------------------------------------------------------------
/Server/controllers/index.js:
--------------------------------------------------------------------------------
1 | import { reportModel } from "../models/index.js";
2 |
3 | // function to get all the data
4 | export const getAllData = async (req, res) => {
5 | try {
6 | const allData = await reportModel.find();
7 | if (!allData || allData.length === 0) {
8 | return res.status(400).json({
9 | success: false,
10 | message: "No data found"
11 | })
12 | }
13 | return res.status(200).json({
14 | success: true,
15 | message: "All data",
16 | data: allData
17 | })
18 | } catch (e) {
19 | return res.status(500).json({
20 | success: false,
21 | message: "Internal Server Error",
22 | })
23 | }
24 | }
25 |
26 | // function to get data filtered by year
27 | export const filteredByYear = async (req, res) => {
28 | try {
29 | const { year } = req.params;
30 | if (year.length !== 4) {
31 | return res.status(400).json({
32 | success: false,
33 | message: "Invalid year",
34 | })
35 | }
36 | // ----------- important -----------
37 | // using '$or' operator to which includes multiple conditions
38 | // using '$regex' to match the particular field with given input
39 | // using $options: 'i' to make the search case-insensitive
40 | const allData = await reportModel.find({
41 | $or: [{ start_year: year }, { end_year: year }, { published: { $regex: year, $options: 'i' } },
42 | { added: { $regex: year, $options: 'i' } }]
43 | });
44 | if (!allData || allData.length === 0) {
45 | return res.status(400).json({
46 | success: false,
47 | message: "No Data Found",
48 | })
49 | }
50 | return res.status(200).json({
51 | success: true,
52 | message: `Filtered by year ${year}`,
53 | data: allData
54 | })
55 | } catch (e) {
56 | return res.status(500).json({
57 | success: false,
58 | message: "Internal Server Error",
59 | })
60 | }
61 | }
62 |
63 | // function to get data filtered by topics
64 | export const filteredByTopic = async (req, res) => {
65 | try {
66 | const { topic } = req.params;
67 | if (topic.length < 3) {
68 | return res.status(400).json({
69 | success: false,
70 | message: "Invalid topic",
71 | })
72 | }
73 | // ----------- important -----------
74 | // using '$regex' to match the particular field with given input
75 | // using $options: 'i' to make the search case-insensitive
76 | const allData = await reportModel.find({ topic: { $regex: topic, $options: 'i' } });
77 | if (!allData || allData.length === 0) {
78 | return res.status(400).json({
79 | success: false,
80 | message: "No Data Found",
81 | })
82 | }
83 | return res.status(200).json({
84 | success: true,
85 | message: `Filtered by topic: ${topic}`,
86 | data: allData
87 | })
88 | } catch (e) {
89 | return res.status(500).json({
90 | success: false,
91 | message: "Internal Server Error",
92 | })
93 | }
94 | }
95 |
96 | // function to get data filtered by title
97 | export const filteredByTitle = async (req, res) => {
98 | try {
99 | const { title } = req.params;
100 | if (title.length < 3) {
101 | return res.status(400).json({
102 | success: false,
103 | message: "Invalid title",
104 | })
105 | }
106 | // ----------- important -----------
107 | // using '$regex' to match the particular field with given input
108 | // using $options: 'i' to make the search case-insensitive
109 | const allData = await reportModel.find({ title: { $regex: title, $options: 'i' } });
110 | if (!allData || allData.length === 0) {
111 | return res.status(400).json({
112 | success: false,
113 | message: "No Data Found",
114 | })
115 | }
116 | return res.status(200).json({
117 | success: true,
118 | message: `Filtered by title: ${title}`,
119 | data: allData
120 | })
121 | } catch (e) {
122 | return res.status(500).json({
123 | success: false,
124 | message: "Internal Server Error",
125 | })
126 | }
127 | }
128 |
129 | // function to get data filtered by sector
130 | export const filteredBySector = async (req, res) => {
131 | try {
132 | const { sector } = req.params;
133 | if (sector.length < 3) {
134 | return res.status(400).json({
135 | success: false,
136 | message: "Invalid sector",
137 | })
138 | }
139 | // ----------- important -----------
140 | // using '$regex' to match the particular field with given input
141 | // using $options: 'i' to make the search case-insensitive
142 | const allData = await reportModel.find({ sector: { $regex: sector, $options: 'i' } });
143 | if (!allData || allData.length === 0) {
144 | return res.status(400).json({
145 | success: false,
146 | message: "No Data Found",
147 | })
148 | }
149 | return res.status(200).json({
150 | success: true,
151 | message: `Filtered by sector: ${sector}`,
152 | data: allData
153 | })
154 | } catch (e) {
155 | return res.status(500).json({
156 | success: false,
157 | message: "Internal Server Error",
158 | })
159 | }
160 | }
161 |
162 | // function to get data filtered by region
163 | export const filteredByRegion = async (req, res) => {
164 | try {
165 | const { region } = req.params;
166 | if (region.length < 3) {
167 | return res.status(400).json({
168 | success: false,
169 | message: "Invalid region",
170 | })
171 | }
172 | // ----------- important -----------
173 | // using '$regex' to match the particular field with given input
174 | // using $options: 'i' to make the search case-insensitive
175 | const allData = await reportModel.find({ region: { $regex: region, $options: 'i' } });
176 | if (!allData || allData.length === 0) {
177 | return res.status(400).json({
178 | success: false,
179 | message: "No Data Found",
180 | })
181 | }
182 | return res.status(200).json({
183 | success: true,
184 | message: `Filtered by region: ${region}`,
185 | data: allData
186 | })
187 | } catch (e) {
188 | return res.status(500).json({
189 | success: false,
190 | message: "Internal Server Error",
191 | })
192 | }
193 | }
194 |
195 | // function to get data filtered by country
196 | export const filteredByCountry = async (req, res) => {
197 | try {
198 | const { country } = req.params;
199 | if (country.length < 3) {
200 | return res.status(400).json({
201 | success: false,
202 | message: "Invalid country",
203 | })
204 | }
205 | // ----------- important -----------
206 | // using '$regex' to match the particular field with given input
207 | // using $options: 'i' to make the search case-insensitive
208 | const allData = await reportModel.find({ country: { $regex: country, $options: 'i' } });
209 | if (!allData || allData.length === 0) {
210 | return res.status(400).json({
211 | success: false,
212 | message: "No Data Found",
213 | })
214 | }
215 | return res.status(200).json({
216 | success: true,
217 | message: `Filtered by country: ${country}`,
218 | data: allData
219 | })
220 | } catch (e) {
221 | return res.status(500).json({
222 | success: false,
223 | message: "Internal Server Error",
224 | })
225 | }
226 | }
227 |
228 | // function to get data filtered by pestle
229 | export const filteredByPestle = async (req, res) => {
230 | try {
231 | const { pestle } = req.params;
232 | if (pestle.length < 3) {
233 | return res.status(400).json({
234 | success: false,
235 | message: "Invalid pestle",
236 | })
237 | }
238 | // ----------- important -----------
239 | // using '$regex' to match the particular field with given input
240 | // using $options: 'i' to make the search case-insensitive
241 | const allData = await reportModel.find({ pestle: { $regex: pestle, $options: 'i' } });
242 | if (!allData || allData.length === 0) {
243 | return res.status(400).json({
244 | success: false,
245 | message: "No Data Found",
246 | })
247 | }
248 | return res.status(200).json({
249 | success: true,
250 | message: `Filtered by pestle: ${pestle}`,
251 | data: allData
252 | })
253 | } catch (e) {
254 | return res.status(500).json({
255 | success: false,
256 | message: "Internal Server Error",
257 | })
258 | }
259 | }
260 |
261 | // function to get data filtered by source
262 | export const filteredBySource = async (req, res) => {
263 | try {
264 | const { source } = req.params;
265 | if (source.length < 3) {
266 | return res.status(400).json({
267 | success: false,
268 | message: "Invalid source",
269 | })
270 | }
271 | // ----------- important -----------
272 | // using '$regex' to match the particular field with given input
273 | // using $options: 'i' to make the search case-insensitive
274 | const allData = await reportModel.find({ source: { $regex: source, $options: 'i' } });
275 | if (!allData || allData.length === 0) {
276 | return res.status(400).json({
277 | success: false,
278 | message: "No Data Found",
279 | })
280 | }
281 | return res.status(200).json({
282 | success: true,
283 | message: `Filtered by source: ${source}`,
284 | data: allData
285 | })
286 | } catch (e) {
287 | return res.status(500).json({
288 | success: false,
289 | message: "Internal Server Error",
290 | })
291 | }
292 | }
293 |
294 | // function to get data filtered by intensity
295 | export const filteredByIntensity = async (req, res) => {
296 | try {
297 | const { intensity } = req.params;
298 | const allData = await reportModel.find({ intensity: parseInt(intensity) });
299 | if (!allData || allData.length === 0) {
300 | return res.status(400).json({
301 | success: false,
302 | message: "No Data Found",
303 | })
304 | }
305 | return res.status(200).json({
306 | success: true,
307 | message: `Filtered by intensity: ${intensity}`,
308 | data: allData
309 | })
310 | } catch (e) {
311 | return res.status(500).json({
312 | success: false,
313 | message: "Internal Server Error",
314 | })
315 | }
316 | }
317 |
318 | // function to get data filtered by likelihood
319 | export const filteredByLikelihood = async (req, res) => {
320 | try {
321 | const { likelihood } = req.params;
322 | const allData = await reportModel.find({ likelihood: parseInt(likelihood) });
323 | if (!allData || allData.length === 0) {
324 | return res.status(400).json({
325 | success: false,
326 | message: "No Data Found",
327 | })
328 | }
329 | return res.status(200).json({
330 | success: true,
331 | message: `Filtered by likelihood: ${likelihood}`,
332 | data: allData
333 | })
334 | } catch (e) {
335 | return res.status(500).json({
336 | success: false,
337 | message: "Internal Server Error",
338 | })
339 | }
340 | }
341 |
342 | // function to get data filtered by any
343 | export const filteredByAny = async (req, res) => {
344 | try {
345 | const { search } = req.params;
346 | if (search.length < 3) {
347 | return res.status(400).json({
348 | success: false,
349 | message: "Invalid search",
350 | })
351 | }
352 | // ----------- important -----------
353 | // using '$or' operator to which includes multiple conditions
354 | // using '$regex' to match the particular field with given input
355 | // using $options: 'i' to make the search case-insensitive
356 | const allData = await reportModel.find({
357 | $or: [{ sector: { $regex: search, $options: 'i' } }, { topic: { $regex: search, $options: 'i' } },
358 | { insight: { $regex: search, $options: 'i' } }, { title: { $regex: search, $options: 'i' } },
359 | { pestle: { $regex: search, $options: 'i' } }, { source: { $regex: search, $options: 'i' } },
360 | { url: { $regex: search, $options: 'i' } }]
361 | });
362 | if (!allData || allData.length === 0) {
363 | return res.status(400).json({
364 | success: false,
365 | message: "No Data Found",
366 | })
367 | }
368 | return res.status(200).json({
369 | success: true,
370 | message: `Filtered by search ${search}`,
371 | data: allData
372 | })
373 | } catch (e) {
374 | return res.status(500).json({
375 | success: false,
376 | message: "Internal Server Error",
377 | })
378 | }
379 | }
--------------------------------------------------------------------------------
/Server/database/index.js:
--------------------------------------------------------------------------------
1 | import mongoose from "mongoose";
2 |
3 | // database connection
4 | export const mongoDB = () => {
5 | mongoose.connect(process.env.MONGO_URI)
6 | .then(() => {
7 | console.log("MongoDb database is connected!");
8 | })
9 | .catch((error) => {
10 | console.log(error);
11 | });
12 | }
--------------------------------------------------------------------------------
/Server/models/index.js:
--------------------------------------------------------------------------------
1 | import mongoose from "mongoose";
2 |
3 | const schema = new mongoose.Schema({
4 | end_year: {
5 | type: Number,
6 | },
7 | intensity: {
8 | type: Number,
9 | },
10 | sector: {
11 | type: String
12 | },
13 | topic: {
14 | type: String
15 | },
16 | insight: {
17 | type: String
18 | },
19 | url: {
20 | type: String
21 | },
22 | region: {
23 | type: String
24 | },
25 | start_year: {
26 | type: Number
27 | },
28 | impact: {
29 | type: String
30 | },
31 | added: {
32 | type: String
33 | },
34 | published: {
35 | type: String
36 | },
37 | country: {
38 | type: String
39 | },
40 | relevance: {
41 | type: Number
42 | },
43 | pestle: {
44 | type: String
45 | },
46 | source: {
47 | type: String
48 | },
49 | title: {
50 | type: String
51 | },
52 | likelihood: {
53 | type: Number
54 | },
55 | })
56 |
57 | export const reportModel = mongoose.model("report", schema);
--------------------------------------------------------------------------------
/Server/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "data-virtualization-app",
3 | "version": "1.0.0",
4 | "lockfileVersion": 2,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "data-virtualization-app",
9 | "version": "1.0.0",
10 | "license": "ISC",
11 | "dependencies": {
12 | "cors": "^2.8.5",
13 | "dotenv": "^16.0.3",
14 | "express": "^4.18.2",
15 | "mongoose": "^7.1.0"
16 | }
17 | },
18 | "node_modules/@types/node": {
19 | "version": "18.16.3",
20 | "resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.3.tgz",
21 | "integrity": "sha512-OPs5WnnT1xkCBiuQrZA4+YAV4HEJejmHneyraIaxsbev5yCEr6KMwINNFP9wQeFIw8FWcoTqF3vQsa5CDaI+8Q=="
22 | },
23 | "node_modules/@types/webidl-conversions": {
24 | "version": "7.0.0",
25 | "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
26 | "integrity": "sha512-xTE1E+YF4aWPJJeUzaZI5DRntlkY3+BCVJi0axFptnjGmAoWxkyREIh/XMrfxVLejwQxMCfDXdICo0VLxThrog=="
27 | },
28 | "node_modules/@types/whatwg-url": {
29 | "version": "8.2.2",
30 | "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.2.tgz",
31 | "integrity": "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==",
32 | "dependencies": {
33 | "@types/node": "*",
34 | "@types/webidl-conversions": "*"
35 | }
36 | },
37 | "node_modules/accepts": {
38 | "version": "1.3.8",
39 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
40 | "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
41 | "dependencies": {
42 | "mime-types": "~2.1.34",
43 | "negotiator": "0.6.3"
44 | },
45 | "engines": {
46 | "node": ">= 0.6"
47 | }
48 | },
49 | "node_modules/array-flatten": {
50 | "version": "1.1.1",
51 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
52 | "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
53 | },
54 | "node_modules/body-parser": {
55 | "version": "1.20.1",
56 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
57 | "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
58 | "dependencies": {
59 | "bytes": "3.1.2",
60 | "content-type": "~1.0.4",
61 | "debug": "2.6.9",
62 | "depd": "2.0.0",
63 | "destroy": "1.2.0",
64 | "http-errors": "2.0.0",
65 | "iconv-lite": "0.4.24",
66 | "on-finished": "2.4.1",
67 | "qs": "6.11.0",
68 | "raw-body": "2.5.1",
69 | "type-is": "~1.6.18",
70 | "unpipe": "1.0.0"
71 | },
72 | "engines": {
73 | "node": ">= 0.8",
74 | "npm": "1.2.8000 || >= 1.4.16"
75 | }
76 | },
77 | "node_modules/bson": {
78 | "version": "5.2.0",
79 | "resolved": "https://registry.npmjs.org/bson/-/bson-5.2.0.tgz",
80 | "integrity": "sha512-HevkSpDbpUfsrHWmWiAsNavANKYIErV2ePXllp1bwq5CDreAaFVj6RVlZpJnxK4WWDCJ/5jMUpaY6G526q3Hjg==",
81 | "engines": {
82 | "node": ">=14.20.1"
83 | }
84 | },
85 | "node_modules/bytes": {
86 | "version": "3.1.2",
87 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
88 | "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
89 | "engines": {
90 | "node": ">= 0.8"
91 | }
92 | },
93 | "node_modules/call-bind": {
94 | "version": "1.0.2",
95 | "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
96 | "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
97 | "dependencies": {
98 | "function-bind": "^1.1.1",
99 | "get-intrinsic": "^1.0.2"
100 | },
101 | "funding": {
102 | "url": "https://github.com/sponsors/ljharb"
103 | }
104 | },
105 | "node_modules/content-disposition": {
106 | "version": "0.5.4",
107 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
108 | "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
109 | "dependencies": {
110 | "safe-buffer": "5.2.1"
111 | },
112 | "engines": {
113 | "node": ">= 0.6"
114 | }
115 | },
116 | "node_modules/content-type": {
117 | "version": "1.0.5",
118 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
119 | "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
120 | "engines": {
121 | "node": ">= 0.6"
122 | }
123 | },
124 | "node_modules/cookie": {
125 | "version": "0.5.0",
126 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
127 | "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
128 | "engines": {
129 | "node": ">= 0.6"
130 | }
131 | },
132 | "node_modules/cookie-signature": {
133 | "version": "1.0.6",
134 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
135 | "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
136 | },
137 | "node_modules/cors": {
138 | "version": "2.8.5",
139 | "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
140 | "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
141 | "dependencies": {
142 | "object-assign": "^4",
143 | "vary": "^1"
144 | },
145 | "engines": {
146 | "node": ">= 0.10"
147 | }
148 | },
149 | "node_modules/debug": {
150 | "version": "2.6.9",
151 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
152 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
153 | "dependencies": {
154 | "ms": "2.0.0"
155 | }
156 | },
157 | "node_modules/depd": {
158 | "version": "2.0.0",
159 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
160 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
161 | "engines": {
162 | "node": ">= 0.8"
163 | }
164 | },
165 | "node_modules/destroy": {
166 | "version": "1.2.0",
167 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
168 | "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
169 | "engines": {
170 | "node": ">= 0.8",
171 | "npm": "1.2.8000 || >= 1.4.16"
172 | }
173 | },
174 | "node_modules/dotenv": {
175 | "version": "16.0.3",
176 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz",
177 | "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==",
178 | "engines": {
179 | "node": ">=12"
180 | }
181 | },
182 | "node_modules/ee-first": {
183 | "version": "1.1.1",
184 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
185 | "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
186 | },
187 | "node_modules/encodeurl": {
188 | "version": "1.0.2",
189 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
190 | "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
191 | "engines": {
192 | "node": ">= 0.8"
193 | }
194 | },
195 | "node_modules/escape-html": {
196 | "version": "1.0.3",
197 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
198 | "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
199 | },
200 | "node_modules/etag": {
201 | "version": "1.8.1",
202 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
203 | "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
204 | "engines": {
205 | "node": ">= 0.6"
206 | }
207 | },
208 | "node_modules/express": {
209 | "version": "4.18.2",
210 | "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
211 | "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
212 | "dependencies": {
213 | "accepts": "~1.3.8",
214 | "array-flatten": "1.1.1",
215 | "body-parser": "1.20.1",
216 | "content-disposition": "0.5.4",
217 | "content-type": "~1.0.4",
218 | "cookie": "0.5.0",
219 | "cookie-signature": "1.0.6",
220 | "debug": "2.6.9",
221 | "depd": "2.0.0",
222 | "encodeurl": "~1.0.2",
223 | "escape-html": "~1.0.3",
224 | "etag": "~1.8.1",
225 | "finalhandler": "1.2.0",
226 | "fresh": "0.5.2",
227 | "http-errors": "2.0.0",
228 | "merge-descriptors": "1.0.1",
229 | "methods": "~1.1.2",
230 | "on-finished": "2.4.1",
231 | "parseurl": "~1.3.3",
232 | "path-to-regexp": "0.1.7",
233 | "proxy-addr": "~2.0.7",
234 | "qs": "6.11.0",
235 | "range-parser": "~1.2.1",
236 | "safe-buffer": "5.2.1",
237 | "send": "0.18.0",
238 | "serve-static": "1.15.0",
239 | "setprototypeof": "1.2.0",
240 | "statuses": "2.0.1",
241 | "type-is": "~1.6.18",
242 | "utils-merge": "1.0.1",
243 | "vary": "~1.1.2"
244 | },
245 | "engines": {
246 | "node": ">= 0.10.0"
247 | }
248 | },
249 | "node_modules/finalhandler": {
250 | "version": "1.2.0",
251 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
252 | "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
253 | "dependencies": {
254 | "debug": "2.6.9",
255 | "encodeurl": "~1.0.2",
256 | "escape-html": "~1.0.3",
257 | "on-finished": "2.4.1",
258 | "parseurl": "~1.3.3",
259 | "statuses": "2.0.1",
260 | "unpipe": "~1.0.0"
261 | },
262 | "engines": {
263 | "node": ">= 0.8"
264 | }
265 | },
266 | "node_modules/forwarded": {
267 | "version": "0.2.0",
268 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
269 | "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
270 | "engines": {
271 | "node": ">= 0.6"
272 | }
273 | },
274 | "node_modules/fresh": {
275 | "version": "0.5.2",
276 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
277 | "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
278 | "engines": {
279 | "node": ">= 0.6"
280 | }
281 | },
282 | "node_modules/function-bind": {
283 | "version": "1.1.1",
284 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
285 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
286 | },
287 | "node_modules/get-intrinsic": {
288 | "version": "1.2.0",
289 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz",
290 | "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==",
291 | "dependencies": {
292 | "function-bind": "^1.1.1",
293 | "has": "^1.0.3",
294 | "has-symbols": "^1.0.3"
295 | },
296 | "funding": {
297 | "url": "https://github.com/sponsors/ljharb"
298 | }
299 | },
300 | "node_modules/has": {
301 | "version": "1.0.3",
302 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
303 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
304 | "dependencies": {
305 | "function-bind": "^1.1.1"
306 | },
307 | "engines": {
308 | "node": ">= 0.4.0"
309 | }
310 | },
311 | "node_modules/has-symbols": {
312 | "version": "1.0.3",
313 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
314 | "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
315 | "engines": {
316 | "node": ">= 0.4"
317 | },
318 | "funding": {
319 | "url": "https://github.com/sponsors/ljharb"
320 | }
321 | },
322 | "node_modules/http-errors": {
323 | "version": "2.0.0",
324 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
325 | "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
326 | "dependencies": {
327 | "depd": "2.0.0",
328 | "inherits": "2.0.4",
329 | "setprototypeof": "1.2.0",
330 | "statuses": "2.0.1",
331 | "toidentifier": "1.0.1"
332 | },
333 | "engines": {
334 | "node": ">= 0.8"
335 | }
336 | },
337 | "node_modules/iconv-lite": {
338 | "version": "0.4.24",
339 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
340 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
341 | "dependencies": {
342 | "safer-buffer": ">= 2.1.2 < 3"
343 | },
344 | "engines": {
345 | "node": ">=0.10.0"
346 | }
347 | },
348 | "node_modules/inherits": {
349 | "version": "2.0.4",
350 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
351 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
352 | },
353 | "node_modules/ip": {
354 | "version": "2.0.0",
355 | "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz",
356 | "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ=="
357 | },
358 | "node_modules/ipaddr.js": {
359 | "version": "1.9.1",
360 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
361 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
362 | "engines": {
363 | "node": ">= 0.10"
364 | }
365 | },
366 | "node_modules/kareem": {
367 | "version": "2.5.1",
368 | "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.5.1.tgz",
369 | "integrity": "sha512-7jFxRVm+jD+rkq3kY0iZDJfsO2/t4BBPeEb2qKn2lR/9KhuksYk5hxzfRYWMPV8P/x2d0kHD306YyWLzjjH+uA==",
370 | "engines": {
371 | "node": ">=12.0.0"
372 | }
373 | },
374 | "node_modules/media-typer": {
375 | "version": "0.3.0",
376 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
377 | "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
378 | "engines": {
379 | "node": ">= 0.6"
380 | }
381 | },
382 | "node_modules/memory-pager": {
383 | "version": "1.5.0",
384 | "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz",
385 | "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==",
386 | "optional": true
387 | },
388 | "node_modules/merge-descriptors": {
389 | "version": "1.0.1",
390 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
391 | "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
392 | },
393 | "node_modules/methods": {
394 | "version": "1.1.2",
395 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
396 | "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
397 | "engines": {
398 | "node": ">= 0.6"
399 | }
400 | },
401 | "node_modules/mime": {
402 | "version": "1.6.0",
403 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
404 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
405 | "bin": {
406 | "mime": "cli.js"
407 | },
408 | "engines": {
409 | "node": ">=4"
410 | }
411 | },
412 | "node_modules/mime-db": {
413 | "version": "1.52.0",
414 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
415 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
416 | "engines": {
417 | "node": ">= 0.6"
418 | }
419 | },
420 | "node_modules/mime-types": {
421 | "version": "2.1.35",
422 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
423 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
424 | "dependencies": {
425 | "mime-db": "1.52.0"
426 | },
427 | "engines": {
428 | "node": ">= 0.6"
429 | }
430 | },
431 | "node_modules/mongodb": {
432 | "version": "5.3.0",
433 | "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-5.3.0.tgz",
434 | "integrity": "sha512-Wy/sbahguL8c3TXQWXmuBabiLD+iVmz+tOgQf+FwkCjhUIorqbAxRbbz00g4ZoN4sXIPwpAlTANMaGRjGGTikQ==",
435 | "dependencies": {
436 | "bson": "^5.2.0",
437 | "mongodb-connection-string-url": "^2.6.0",
438 | "socks": "^2.7.1"
439 | },
440 | "engines": {
441 | "node": ">=14.20.1"
442 | },
443 | "optionalDependencies": {
444 | "saslprep": "^1.0.3"
445 | },
446 | "peerDependencies": {
447 | "@aws-sdk/credential-providers": "^3.201.0",
448 | "mongodb-client-encryption": ">=2.3.0 <3",
449 | "snappy": "^7.2.2"
450 | },
451 | "peerDependenciesMeta": {
452 | "@aws-sdk/credential-providers": {
453 | "optional": true
454 | },
455 | "mongodb-client-encryption": {
456 | "optional": true
457 | },
458 | "snappy": {
459 | "optional": true
460 | }
461 | }
462 | },
463 | "node_modules/mongodb-connection-string-url": {
464 | "version": "2.6.0",
465 | "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz",
466 | "integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==",
467 | "dependencies": {
468 | "@types/whatwg-url": "^8.2.1",
469 | "whatwg-url": "^11.0.0"
470 | }
471 | },
472 | "node_modules/mongoose": {
473 | "version": "7.1.0",
474 | "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-7.1.0.tgz",
475 | "integrity": "sha512-shoo9z/7o96Ojx69wpJn65+EC+Mt3q1SWTducW+F2Y4ieCXo0lZwpCZedgC841MIvJ7V8o6gmzoN1NfcnOTOuw==",
476 | "dependencies": {
477 | "bson": "^5.2.0",
478 | "kareem": "2.5.1",
479 | "mongodb": "5.3.0",
480 | "mpath": "0.9.0",
481 | "mquery": "5.0.0",
482 | "ms": "2.1.3",
483 | "sift": "16.0.1"
484 | },
485 | "engines": {
486 | "node": ">=14.0.0"
487 | },
488 | "funding": {
489 | "type": "opencollective",
490 | "url": "https://opencollective.com/mongoose"
491 | }
492 | },
493 | "node_modules/mongoose/node_modules/ms": {
494 | "version": "2.1.3",
495 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
496 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
497 | },
498 | "node_modules/mpath": {
499 | "version": "0.9.0",
500 | "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz",
501 | "integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==",
502 | "engines": {
503 | "node": ">=4.0.0"
504 | }
505 | },
506 | "node_modules/mquery": {
507 | "version": "5.0.0",
508 | "resolved": "https://registry.npmjs.org/mquery/-/mquery-5.0.0.tgz",
509 | "integrity": "sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==",
510 | "dependencies": {
511 | "debug": "4.x"
512 | },
513 | "engines": {
514 | "node": ">=14.0.0"
515 | }
516 | },
517 | "node_modules/mquery/node_modules/debug": {
518 | "version": "4.3.4",
519 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
520 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
521 | "dependencies": {
522 | "ms": "2.1.2"
523 | },
524 | "engines": {
525 | "node": ">=6.0"
526 | },
527 | "peerDependenciesMeta": {
528 | "supports-color": {
529 | "optional": true
530 | }
531 | }
532 | },
533 | "node_modules/mquery/node_modules/ms": {
534 | "version": "2.1.2",
535 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
536 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
537 | },
538 | "node_modules/ms": {
539 | "version": "2.0.0",
540 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
541 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
542 | },
543 | "node_modules/negotiator": {
544 | "version": "0.6.3",
545 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
546 | "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
547 | "engines": {
548 | "node": ">= 0.6"
549 | }
550 | },
551 | "node_modules/object-assign": {
552 | "version": "4.1.1",
553 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
554 | "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
555 | "engines": {
556 | "node": ">=0.10.0"
557 | }
558 | },
559 | "node_modules/object-inspect": {
560 | "version": "1.12.3",
561 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
562 | "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==",
563 | "funding": {
564 | "url": "https://github.com/sponsors/ljharb"
565 | }
566 | },
567 | "node_modules/on-finished": {
568 | "version": "2.4.1",
569 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
570 | "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
571 | "dependencies": {
572 | "ee-first": "1.1.1"
573 | },
574 | "engines": {
575 | "node": ">= 0.8"
576 | }
577 | },
578 | "node_modules/parseurl": {
579 | "version": "1.3.3",
580 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
581 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
582 | "engines": {
583 | "node": ">= 0.8"
584 | }
585 | },
586 | "node_modules/path-to-regexp": {
587 | "version": "0.1.7",
588 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
589 | "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
590 | },
591 | "node_modules/proxy-addr": {
592 | "version": "2.0.7",
593 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
594 | "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
595 | "dependencies": {
596 | "forwarded": "0.2.0",
597 | "ipaddr.js": "1.9.1"
598 | },
599 | "engines": {
600 | "node": ">= 0.10"
601 | }
602 | },
603 | "node_modules/punycode": {
604 | "version": "2.3.0",
605 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
606 | "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==",
607 | "engines": {
608 | "node": ">=6"
609 | }
610 | },
611 | "node_modules/qs": {
612 | "version": "6.11.0",
613 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
614 | "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
615 | "dependencies": {
616 | "side-channel": "^1.0.4"
617 | },
618 | "engines": {
619 | "node": ">=0.6"
620 | },
621 | "funding": {
622 | "url": "https://github.com/sponsors/ljharb"
623 | }
624 | },
625 | "node_modules/range-parser": {
626 | "version": "1.2.1",
627 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
628 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
629 | "engines": {
630 | "node": ">= 0.6"
631 | }
632 | },
633 | "node_modules/raw-body": {
634 | "version": "2.5.1",
635 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
636 | "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
637 | "dependencies": {
638 | "bytes": "3.1.2",
639 | "http-errors": "2.0.0",
640 | "iconv-lite": "0.4.24",
641 | "unpipe": "1.0.0"
642 | },
643 | "engines": {
644 | "node": ">= 0.8"
645 | }
646 | },
647 | "node_modules/safe-buffer": {
648 | "version": "5.2.1",
649 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
650 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
651 | "funding": [
652 | {
653 | "type": "github",
654 | "url": "https://github.com/sponsors/feross"
655 | },
656 | {
657 | "type": "patreon",
658 | "url": "https://www.patreon.com/feross"
659 | },
660 | {
661 | "type": "consulting",
662 | "url": "https://feross.org/support"
663 | }
664 | ]
665 | },
666 | "node_modules/safer-buffer": {
667 | "version": "2.1.2",
668 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
669 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
670 | },
671 | "node_modules/saslprep": {
672 | "version": "1.0.3",
673 | "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz",
674 | "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==",
675 | "optional": true,
676 | "dependencies": {
677 | "sparse-bitfield": "^3.0.3"
678 | },
679 | "engines": {
680 | "node": ">=6"
681 | }
682 | },
683 | "node_modules/send": {
684 | "version": "0.18.0",
685 | "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
686 | "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
687 | "dependencies": {
688 | "debug": "2.6.9",
689 | "depd": "2.0.0",
690 | "destroy": "1.2.0",
691 | "encodeurl": "~1.0.2",
692 | "escape-html": "~1.0.3",
693 | "etag": "~1.8.1",
694 | "fresh": "0.5.2",
695 | "http-errors": "2.0.0",
696 | "mime": "1.6.0",
697 | "ms": "2.1.3",
698 | "on-finished": "2.4.1",
699 | "range-parser": "~1.2.1",
700 | "statuses": "2.0.1"
701 | },
702 | "engines": {
703 | "node": ">= 0.8.0"
704 | }
705 | },
706 | "node_modules/send/node_modules/ms": {
707 | "version": "2.1.3",
708 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
709 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
710 | },
711 | "node_modules/serve-static": {
712 | "version": "1.15.0",
713 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
714 | "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
715 | "dependencies": {
716 | "encodeurl": "~1.0.2",
717 | "escape-html": "~1.0.3",
718 | "parseurl": "~1.3.3",
719 | "send": "0.18.0"
720 | },
721 | "engines": {
722 | "node": ">= 0.8.0"
723 | }
724 | },
725 | "node_modules/setprototypeof": {
726 | "version": "1.2.0",
727 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
728 | "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
729 | },
730 | "node_modules/side-channel": {
731 | "version": "1.0.4",
732 | "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
733 | "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
734 | "dependencies": {
735 | "call-bind": "^1.0.0",
736 | "get-intrinsic": "^1.0.2",
737 | "object-inspect": "^1.9.0"
738 | },
739 | "funding": {
740 | "url": "https://github.com/sponsors/ljharb"
741 | }
742 | },
743 | "node_modules/sift": {
744 | "version": "16.0.1",
745 | "resolved": "https://registry.npmjs.org/sift/-/sift-16.0.1.tgz",
746 | "integrity": "sha512-Wv6BjQ5zbhW7VFefWusVP33T/EM0vYikCaQ2qR8yULbsilAT8/wQaXvuQ3ptGLpoKx+lihJE3y2UTgKDyyNHZQ=="
747 | },
748 | "node_modules/smart-buffer": {
749 | "version": "4.2.0",
750 | "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
751 | "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
752 | "engines": {
753 | "node": ">= 6.0.0",
754 | "npm": ">= 3.0.0"
755 | }
756 | },
757 | "node_modules/socks": {
758 | "version": "2.7.1",
759 | "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz",
760 | "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==",
761 | "dependencies": {
762 | "ip": "^2.0.0",
763 | "smart-buffer": "^4.2.0"
764 | },
765 | "engines": {
766 | "node": ">= 10.13.0",
767 | "npm": ">= 3.0.0"
768 | }
769 | },
770 | "node_modules/sparse-bitfield": {
771 | "version": "3.0.3",
772 | "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
773 | "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==",
774 | "optional": true,
775 | "dependencies": {
776 | "memory-pager": "^1.0.2"
777 | }
778 | },
779 | "node_modules/statuses": {
780 | "version": "2.0.1",
781 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
782 | "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
783 | "engines": {
784 | "node": ">= 0.8"
785 | }
786 | },
787 | "node_modules/toidentifier": {
788 | "version": "1.0.1",
789 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
790 | "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
791 | "engines": {
792 | "node": ">=0.6"
793 | }
794 | },
795 | "node_modules/tr46": {
796 | "version": "3.0.0",
797 | "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz",
798 | "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==",
799 | "dependencies": {
800 | "punycode": "^2.1.1"
801 | },
802 | "engines": {
803 | "node": ">=12"
804 | }
805 | },
806 | "node_modules/type-is": {
807 | "version": "1.6.18",
808 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
809 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
810 | "dependencies": {
811 | "media-typer": "0.3.0",
812 | "mime-types": "~2.1.24"
813 | },
814 | "engines": {
815 | "node": ">= 0.6"
816 | }
817 | },
818 | "node_modules/unpipe": {
819 | "version": "1.0.0",
820 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
821 | "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
822 | "engines": {
823 | "node": ">= 0.8"
824 | }
825 | },
826 | "node_modules/utils-merge": {
827 | "version": "1.0.1",
828 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
829 | "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
830 | "engines": {
831 | "node": ">= 0.4.0"
832 | }
833 | },
834 | "node_modules/vary": {
835 | "version": "1.1.2",
836 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
837 | "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
838 | "engines": {
839 | "node": ">= 0.8"
840 | }
841 | },
842 | "node_modules/webidl-conversions": {
843 | "version": "7.0.0",
844 | "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
845 | "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==",
846 | "engines": {
847 | "node": ">=12"
848 | }
849 | },
850 | "node_modules/whatwg-url": {
851 | "version": "11.0.0",
852 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz",
853 | "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==",
854 | "dependencies": {
855 | "tr46": "^3.0.0",
856 | "webidl-conversions": "^7.0.0"
857 | },
858 | "engines": {
859 | "node": ">=12"
860 | }
861 | }
862 | },
863 | "dependencies": {
864 | "@types/node": {
865 | "version": "18.16.3",
866 | "resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.3.tgz",
867 | "integrity": "sha512-OPs5WnnT1xkCBiuQrZA4+YAV4HEJejmHneyraIaxsbev5yCEr6KMwINNFP9wQeFIw8FWcoTqF3vQsa5CDaI+8Q=="
868 | },
869 | "@types/webidl-conversions": {
870 | "version": "7.0.0",
871 | "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
872 | "integrity": "sha512-xTE1E+YF4aWPJJeUzaZI5DRntlkY3+BCVJi0axFptnjGmAoWxkyREIh/XMrfxVLejwQxMCfDXdICo0VLxThrog=="
873 | },
874 | "@types/whatwg-url": {
875 | "version": "8.2.2",
876 | "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.2.tgz",
877 | "integrity": "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==",
878 | "requires": {
879 | "@types/node": "*",
880 | "@types/webidl-conversions": "*"
881 | }
882 | },
883 | "accepts": {
884 | "version": "1.3.8",
885 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
886 | "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
887 | "requires": {
888 | "mime-types": "~2.1.34",
889 | "negotiator": "0.6.3"
890 | }
891 | },
892 | "array-flatten": {
893 | "version": "1.1.1",
894 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
895 | "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
896 | },
897 | "body-parser": {
898 | "version": "1.20.1",
899 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
900 | "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
901 | "requires": {
902 | "bytes": "3.1.2",
903 | "content-type": "~1.0.4",
904 | "debug": "2.6.9",
905 | "depd": "2.0.0",
906 | "destroy": "1.2.0",
907 | "http-errors": "2.0.0",
908 | "iconv-lite": "0.4.24",
909 | "on-finished": "2.4.1",
910 | "qs": "6.11.0",
911 | "raw-body": "2.5.1",
912 | "type-is": "~1.6.18",
913 | "unpipe": "1.0.0"
914 | }
915 | },
916 | "bson": {
917 | "version": "5.2.0",
918 | "resolved": "https://registry.npmjs.org/bson/-/bson-5.2.0.tgz",
919 | "integrity": "sha512-HevkSpDbpUfsrHWmWiAsNavANKYIErV2ePXllp1bwq5CDreAaFVj6RVlZpJnxK4WWDCJ/5jMUpaY6G526q3Hjg=="
920 | },
921 | "bytes": {
922 | "version": "3.1.2",
923 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
924 | "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="
925 | },
926 | "call-bind": {
927 | "version": "1.0.2",
928 | "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
929 | "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
930 | "requires": {
931 | "function-bind": "^1.1.1",
932 | "get-intrinsic": "^1.0.2"
933 | }
934 | },
935 | "content-disposition": {
936 | "version": "0.5.4",
937 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
938 | "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
939 | "requires": {
940 | "safe-buffer": "5.2.1"
941 | }
942 | },
943 | "content-type": {
944 | "version": "1.0.5",
945 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
946 | "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="
947 | },
948 | "cookie": {
949 | "version": "0.5.0",
950 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
951 | "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw=="
952 | },
953 | "cookie-signature": {
954 | "version": "1.0.6",
955 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
956 | "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
957 | },
958 | "cors": {
959 | "version": "2.8.5",
960 | "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
961 | "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
962 | "requires": {
963 | "object-assign": "^4",
964 | "vary": "^1"
965 | }
966 | },
967 | "debug": {
968 | "version": "2.6.9",
969 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
970 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
971 | "requires": {
972 | "ms": "2.0.0"
973 | }
974 | },
975 | "depd": {
976 | "version": "2.0.0",
977 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
978 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="
979 | },
980 | "destroy": {
981 | "version": "1.2.0",
982 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
983 | "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg=="
984 | },
985 | "dotenv": {
986 | "version": "16.0.3",
987 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz",
988 | "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ=="
989 | },
990 | "ee-first": {
991 | "version": "1.1.1",
992 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
993 | "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
994 | },
995 | "encodeurl": {
996 | "version": "1.0.2",
997 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
998 | "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="
999 | },
1000 | "escape-html": {
1001 | "version": "1.0.3",
1002 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
1003 | "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
1004 | },
1005 | "etag": {
1006 | "version": "1.8.1",
1007 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
1008 | "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="
1009 | },
1010 | "express": {
1011 | "version": "4.18.2",
1012 | "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
1013 | "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
1014 | "requires": {
1015 | "accepts": "~1.3.8",
1016 | "array-flatten": "1.1.1",
1017 | "body-parser": "1.20.1",
1018 | "content-disposition": "0.5.4",
1019 | "content-type": "~1.0.4",
1020 | "cookie": "0.5.0",
1021 | "cookie-signature": "1.0.6",
1022 | "debug": "2.6.9",
1023 | "depd": "2.0.0",
1024 | "encodeurl": "~1.0.2",
1025 | "escape-html": "~1.0.3",
1026 | "etag": "~1.8.1",
1027 | "finalhandler": "1.2.0",
1028 | "fresh": "0.5.2",
1029 | "http-errors": "2.0.0",
1030 | "merge-descriptors": "1.0.1",
1031 | "methods": "~1.1.2",
1032 | "on-finished": "2.4.1",
1033 | "parseurl": "~1.3.3",
1034 | "path-to-regexp": "0.1.7",
1035 | "proxy-addr": "~2.0.7",
1036 | "qs": "6.11.0",
1037 | "range-parser": "~1.2.1",
1038 | "safe-buffer": "5.2.1",
1039 | "send": "0.18.0",
1040 | "serve-static": "1.15.0",
1041 | "setprototypeof": "1.2.0",
1042 | "statuses": "2.0.1",
1043 | "type-is": "~1.6.18",
1044 | "utils-merge": "1.0.1",
1045 | "vary": "~1.1.2"
1046 | }
1047 | },
1048 | "finalhandler": {
1049 | "version": "1.2.0",
1050 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
1051 | "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
1052 | "requires": {
1053 | "debug": "2.6.9",
1054 | "encodeurl": "~1.0.2",
1055 | "escape-html": "~1.0.3",
1056 | "on-finished": "2.4.1",
1057 | "parseurl": "~1.3.3",
1058 | "statuses": "2.0.1",
1059 | "unpipe": "~1.0.0"
1060 | }
1061 | },
1062 | "forwarded": {
1063 | "version": "0.2.0",
1064 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
1065 | "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="
1066 | },
1067 | "fresh": {
1068 | "version": "0.5.2",
1069 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
1070 | "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="
1071 | },
1072 | "function-bind": {
1073 | "version": "1.1.1",
1074 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
1075 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
1076 | },
1077 | "get-intrinsic": {
1078 | "version": "1.2.0",
1079 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz",
1080 | "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==",
1081 | "requires": {
1082 | "function-bind": "^1.1.1",
1083 | "has": "^1.0.3",
1084 | "has-symbols": "^1.0.3"
1085 | }
1086 | },
1087 | "has": {
1088 | "version": "1.0.3",
1089 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
1090 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
1091 | "requires": {
1092 | "function-bind": "^1.1.1"
1093 | }
1094 | },
1095 | "has-symbols": {
1096 | "version": "1.0.3",
1097 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
1098 | "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="
1099 | },
1100 | "http-errors": {
1101 | "version": "2.0.0",
1102 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
1103 | "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
1104 | "requires": {
1105 | "depd": "2.0.0",
1106 | "inherits": "2.0.4",
1107 | "setprototypeof": "1.2.0",
1108 | "statuses": "2.0.1",
1109 | "toidentifier": "1.0.1"
1110 | }
1111 | },
1112 | "iconv-lite": {
1113 | "version": "0.4.24",
1114 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
1115 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
1116 | "requires": {
1117 | "safer-buffer": ">= 2.1.2 < 3"
1118 | }
1119 | },
1120 | "inherits": {
1121 | "version": "2.0.4",
1122 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
1123 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
1124 | },
1125 | "ip": {
1126 | "version": "2.0.0",
1127 | "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz",
1128 | "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ=="
1129 | },
1130 | "ipaddr.js": {
1131 | "version": "1.9.1",
1132 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
1133 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
1134 | },
1135 | "kareem": {
1136 | "version": "2.5.1",
1137 | "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.5.1.tgz",
1138 | "integrity": "sha512-7jFxRVm+jD+rkq3kY0iZDJfsO2/t4BBPeEb2qKn2lR/9KhuksYk5hxzfRYWMPV8P/x2d0kHD306YyWLzjjH+uA=="
1139 | },
1140 | "media-typer": {
1141 | "version": "0.3.0",
1142 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
1143 | "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ=="
1144 | },
1145 | "memory-pager": {
1146 | "version": "1.5.0",
1147 | "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz",
1148 | "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==",
1149 | "optional": true
1150 | },
1151 | "merge-descriptors": {
1152 | "version": "1.0.1",
1153 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
1154 | "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
1155 | },
1156 | "methods": {
1157 | "version": "1.1.2",
1158 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
1159 | "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w=="
1160 | },
1161 | "mime": {
1162 | "version": "1.6.0",
1163 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
1164 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
1165 | },
1166 | "mime-db": {
1167 | "version": "1.52.0",
1168 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
1169 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
1170 | },
1171 | "mime-types": {
1172 | "version": "2.1.35",
1173 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
1174 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
1175 | "requires": {
1176 | "mime-db": "1.52.0"
1177 | }
1178 | },
1179 | "mongodb": {
1180 | "version": "5.3.0",
1181 | "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-5.3.0.tgz",
1182 | "integrity": "sha512-Wy/sbahguL8c3TXQWXmuBabiLD+iVmz+tOgQf+FwkCjhUIorqbAxRbbz00g4ZoN4sXIPwpAlTANMaGRjGGTikQ==",
1183 | "requires": {
1184 | "bson": "^5.2.0",
1185 | "mongodb-connection-string-url": "^2.6.0",
1186 | "saslprep": "^1.0.3",
1187 | "socks": "^2.7.1"
1188 | }
1189 | },
1190 | "mongodb-connection-string-url": {
1191 | "version": "2.6.0",
1192 | "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz",
1193 | "integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==",
1194 | "requires": {
1195 | "@types/whatwg-url": "^8.2.1",
1196 | "whatwg-url": "^11.0.0"
1197 | }
1198 | },
1199 | "mongoose": {
1200 | "version": "7.1.0",
1201 | "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-7.1.0.tgz",
1202 | "integrity": "sha512-shoo9z/7o96Ojx69wpJn65+EC+Mt3q1SWTducW+F2Y4ieCXo0lZwpCZedgC841MIvJ7V8o6gmzoN1NfcnOTOuw==",
1203 | "requires": {
1204 | "bson": "^5.2.0",
1205 | "kareem": "2.5.1",
1206 | "mongodb": "5.3.0",
1207 | "mpath": "0.9.0",
1208 | "mquery": "5.0.0",
1209 | "ms": "2.1.3",
1210 | "sift": "16.0.1"
1211 | },
1212 | "dependencies": {
1213 | "ms": {
1214 | "version": "2.1.3",
1215 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
1216 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
1217 | }
1218 | }
1219 | },
1220 | "mpath": {
1221 | "version": "0.9.0",
1222 | "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz",
1223 | "integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew=="
1224 | },
1225 | "mquery": {
1226 | "version": "5.0.0",
1227 | "resolved": "https://registry.npmjs.org/mquery/-/mquery-5.0.0.tgz",
1228 | "integrity": "sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==",
1229 | "requires": {
1230 | "debug": "4.x"
1231 | },
1232 | "dependencies": {
1233 | "debug": {
1234 | "version": "4.3.4",
1235 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
1236 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
1237 | "requires": {
1238 | "ms": "2.1.2"
1239 | }
1240 | },
1241 | "ms": {
1242 | "version": "2.1.2",
1243 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
1244 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
1245 | }
1246 | }
1247 | },
1248 | "ms": {
1249 | "version": "2.0.0",
1250 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
1251 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
1252 | },
1253 | "negotiator": {
1254 | "version": "0.6.3",
1255 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
1256 | "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="
1257 | },
1258 | "object-assign": {
1259 | "version": "4.1.1",
1260 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
1261 | "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="
1262 | },
1263 | "object-inspect": {
1264 | "version": "1.12.3",
1265 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
1266 | "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g=="
1267 | },
1268 | "on-finished": {
1269 | "version": "2.4.1",
1270 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
1271 | "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
1272 | "requires": {
1273 | "ee-first": "1.1.1"
1274 | }
1275 | },
1276 | "parseurl": {
1277 | "version": "1.3.3",
1278 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
1279 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
1280 | },
1281 | "path-to-regexp": {
1282 | "version": "0.1.7",
1283 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
1284 | "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
1285 | },
1286 | "proxy-addr": {
1287 | "version": "2.0.7",
1288 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
1289 | "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
1290 | "requires": {
1291 | "forwarded": "0.2.0",
1292 | "ipaddr.js": "1.9.1"
1293 | }
1294 | },
1295 | "punycode": {
1296 | "version": "2.3.0",
1297 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
1298 | "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA=="
1299 | },
1300 | "qs": {
1301 | "version": "6.11.0",
1302 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
1303 | "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
1304 | "requires": {
1305 | "side-channel": "^1.0.4"
1306 | }
1307 | },
1308 | "range-parser": {
1309 | "version": "1.2.1",
1310 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
1311 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
1312 | },
1313 | "raw-body": {
1314 | "version": "2.5.1",
1315 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
1316 | "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
1317 | "requires": {
1318 | "bytes": "3.1.2",
1319 | "http-errors": "2.0.0",
1320 | "iconv-lite": "0.4.24",
1321 | "unpipe": "1.0.0"
1322 | }
1323 | },
1324 | "safe-buffer": {
1325 | "version": "5.2.1",
1326 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
1327 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
1328 | },
1329 | "safer-buffer": {
1330 | "version": "2.1.2",
1331 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
1332 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
1333 | },
1334 | "saslprep": {
1335 | "version": "1.0.3",
1336 | "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz",
1337 | "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==",
1338 | "optional": true,
1339 | "requires": {
1340 | "sparse-bitfield": "^3.0.3"
1341 | }
1342 | },
1343 | "send": {
1344 | "version": "0.18.0",
1345 | "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
1346 | "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
1347 | "requires": {
1348 | "debug": "2.6.9",
1349 | "depd": "2.0.0",
1350 | "destroy": "1.2.0",
1351 | "encodeurl": "~1.0.2",
1352 | "escape-html": "~1.0.3",
1353 | "etag": "~1.8.1",
1354 | "fresh": "0.5.2",
1355 | "http-errors": "2.0.0",
1356 | "mime": "1.6.0",
1357 | "ms": "2.1.3",
1358 | "on-finished": "2.4.1",
1359 | "range-parser": "~1.2.1",
1360 | "statuses": "2.0.1"
1361 | },
1362 | "dependencies": {
1363 | "ms": {
1364 | "version": "2.1.3",
1365 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
1366 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
1367 | }
1368 | }
1369 | },
1370 | "serve-static": {
1371 | "version": "1.15.0",
1372 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
1373 | "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
1374 | "requires": {
1375 | "encodeurl": "~1.0.2",
1376 | "escape-html": "~1.0.3",
1377 | "parseurl": "~1.3.3",
1378 | "send": "0.18.0"
1379 | }
1380 | },
1381 | "setprototypeof": {
1382 | "version": "1.2.0",
1383 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
1384 | "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
1385 | },
1386 | "side-channel": {
1387 | "version": "1.0.4",
1388 | "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
1389 | "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
1390 | "requires": {
1391 | "call-bind": "^1.0.0",
1392 | "get-intrinsic": "^1.0.2",
1393 | "object-inspect": "^1.9.0"
1394 | }
1395 | },
1396 | "sift": {
1397 | "version": "16.0.1",
1398 | "resolved": "https://registry.npmjs.org/sift/-/sift-16.0.1.tgz",
1399 | "integrity": "sha512-Wv6BjQ5zbhW7VFefWusVP33T/EM0vYikCaQ2qR8yULbsilAT8/wQaXvuQ3ptGLpoKx+lihJE3y2UTgKDyyNHZQ=="
1400 | },
1401 | "smart-buffer": {
1402 | "version": "4.2.0",
1403 | "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
1404 | "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="
1405 | },
1406 | "socks": {
1407 | "version": "2.7.1",
1408 | "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz",
1409 | "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==",
1410 | "requires": {
1411 | "ip": "^2.0.0",
1412 | "smart-buffer": "^4.2.0"
1413 | }
1414 | },
1415 | "sparse-bitfield": {
1416 | "version": "3.0.3",
1417 | "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
1418 | "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==",
1419 | "optional": true,
1420 | "requires": {
1421 | "memory-pager": "^1.0.2"
1422 | }
1423 | },
1424 | "statuses": {
1425 | "version": "2.0.1",
1426 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
1427 | "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="
1428 | },
1429 | "toidentifier": {
1430 | "version": "1.0.1",
1431 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
1432 | "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="
1433 | },
1434 | "tr46": {
1435 | "version": "3.0.0",
1436 | "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz",
1437 | "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==",
1438 | "requires": {
1439 | "punycode": "^2.1.1"
1440 | }
1441 | },
1442 | "type-is": {
1443 | "version": "1.6.18",
1444 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
1445 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
1446 | "requires": {
1447 | "media-typer": "0.3.0",
1448 | "mime-types": "~2.1.24"
1449 | }
1450 | },
1451 | "unpipe": {
1452 | "version": "1.0.0",
1453 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
1454 | "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="
1455 | },
1456 | "utils-merge": {
1457 | "version": "1.0.1",
1458 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
1459 | "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="
1460 | },
1461 | "vary": {
1462 | "version": "1.1.2",
1463 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
1464 | "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="
1465 | },
1466 | "webidl-conversions": {
1467 | "version": "7.0.0",
1468 | "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
1469 | "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g=="
1470 | },
1471 | "whatwg-url": {
1472 | "version": "11.0.0",
1473 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz",
1474 | "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==",
1475 | "requires": {
1476 | "tr46": "^3.0.0",
1477 | "webidl-conversions": "^7.0.0"
1478 | }
1479 | }
1480 | }
1481 | }
1482 |
--------------------------------------------------------------------------------
/Server/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "data-virtualization-dashboard",
3 | "version": "1.0.0",
4 | "description": "This project is a Data Visualization Dashboard that uses the MERN Stack to create visualizations. The project uses given JSON data to create a MongoDB database and create an API in node.js to retrieve the data. The visualizations are created using chart.js library. The dashboard has various filters like end year, topics, region, and other controls that can be added from the data. The project aims to generate insights from creative visualizations.",
5 | "main": "app.js",
6 | "type": "module",
7 | "engines": {
8 | "node": ">=14.20.1"
9 | },
10 | "scripts": {
11 | "test": "echo \"Error: no test specified\" && exit 1",
12 | "dev": "nodemon app.js",
13 | "start": "node app.js"
14 | },
15 | "author": "ayusharma-ctrl",
16 | "license": "ISC",
17 | "dependencies": {
18 | "cors": "^2.8.5",
19 | "dotenv": "^16.0.3",
20 | "express": "^4.18.2",
21 | "mongoose": "^7.1.0"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Server/routes/index.js:
--------------------------------------------------------------------------------
1 | import express from 'express';
2 | import { filteredByAny, filteredByCountry, filteredByIntensity, filteredByLikelihood, filteredByPestle, filteredByRegion, filteredBySector, filteredBySource, filteredByTitle, filteredByTopic, filteredByYear, getAllData } from '../controllers/index.js';
3 |
4 | //creating a router
5 | const router = express.Router();
6 |
7 | //api to get all the data
8 | router.get('/all', getAllData);
9 |
10 | // api to get data filtered by year
11 | router.get("/year/:year", filteredByYear)
12 |
13 | // api to get data filtered by topic
14 | router.get("/topic/:topic", filteredByTopic)
15 |
16 | // api to get data filtered by title
17 | router.get("/title/:title", filteredByTitle)
18 |
19 | // api to get data filtered by sector
20 | router.get("/sector/:sector", filteredBySector)
21 |
22 | // api to get data filtered by region
23 | router.get("/region/:region", filteredByRegion)
24 |
25 | // api to get data filtered by country
26 | router.get("/country/:country", filteredByCountry)
27 |
28 | // api to get data filtered by pestle
29 | router.get("/pestle/:pestle", filteredByPestle)
30 |
31 | // api to get data filtered by source
32 | router.get("/source/:source", filteredBySource)
33 |
34 | // api to get data filtered by intensity
35 | router.get("/intensity/:intensity", filteredByIntensity)
36 |
37 | // api to get data filtered by likelihood
38 | router.get("/likelihood/:likelihood", filteredByLikelihood)
39 |
40 | // api to get data filtered by any
41 | router.get("/any/:search", filteredByAny)
42 |
43 |
44 | export default router;
--------------------------------------------------------------------------------