diff --git a/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js b/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js
index ac3ce1d6f..a8b1ea737 100644
--- a/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js
+++ b/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js
@@ -164,6 +164,44 @@ export const deleteMonitorChecksByTeamId = createAsyncThunk(
}
}
);
+export const addDemoMonitors = createAsyncThunk(
+ "monitors/addDemoMonitors",
+ async (data, thunkApi) => {
+ try {
+ const { authToken } = data;
+ const res = await networkService.addDemoMonitors(authToken);
+ return res.data;
+ } catch (error) {
+ if (error.response && error.response.data) {
+ return thunkApi.rejectWithValue(error.response.data);
+ }
+ const payload = {
+ status: false,
+ msg: error.message ? error.message : "Unknown error",
+ };
+ return thunkApi.rejectWithValue(payload);
+ }
+ }
+);
+export const deleteAllMonitors = createAsyncThunk(
+ "monitors/deleteAllMonitors",
+ async (data, thunkApi) => {
+ try {
+ const { authToken } = data;
+ const res = await networkService.deleteAllMonitors(authToken);
+ return res.data;
+ } catch (error) {
+ if (error.response && error.response.data) {
+ return thunkApi.rejectWithValue(error.response.data);
+ }
+ const payload = {
+ status: false,
+ msg: error.message ? error.message : "Unknown error",
+ };
+ return thunkApi.rejectWithValue(payload);
+ }
+ }
+);
const uptimeMonitorsSlice = createSlice({
name: "uptimeMonitors",
@@ -306,6 +344,42 @@ const uptimeMonitorsSlice = createSlice({
state.msg = action.payload
? action.payload.msg
: "Failed to pause uptime monitor";
+ })
+ // *****************************************************
+ // Add Demo Monitors
+ // *****************************************************
+ .addCase(addDemoMonitors.pending, (state) => {
+ state.isLoading = true;
+ })
+ .addCase(addDemoMonitors.fulfilled, (state, action) => {
+ state.isLoading = false;
+ state.success = action.payload.success;
+ state.msg = action.payload.msg;
+ })
+ .addCase(addDemoMonitors.rejected, (state, action) => {
+ state.isLoading = false;
+ state.success = false;
+ state.msg = action.payload
+ ? action.payload.msg
+ : "Failed to add demo uptime monitors";
+ })
+ // *****************************************************
+ // Delete all Monitors
+ // *****************************************************
+ .addCase(deleteAllMonitors.pending, (state) => {
+ state.isLoading = true;
+ })
+ .addCase(deleteAllMonitors.fulfilled, (state, action) => {
+ state.isLoading = false;
+ state.success = action.payload.success;
+ state.msg = action.payload.msg;
+ })
+ .addCase(deleteAllMonitors.rejected, (state, action) => {
+ state.isLoading = false;
+ state.success = false;
+ state.msg = action.payload
+ ? action.payload.msg
+ : "Failed to delete all monitors";
});
},
});
diff --git a/Client/src/Pages/Settings/index.jsx b/Client/src/Pages/Settings/index.jsx
index d1f15ea8c..cd00f440f 100644
--- a/Client/src/Pages/Settings/index.jsx
+++ b/Client/src/Pages/Settings/index.jsx
@@ -1,5 +1,5 @@
import { useTheme } from "@emotion/react";
-import { Box, Button, Stack, styled, Typography } from "@mui/material";
+import { Box, Stack, styled, Typography } from "@mui/material";
import Field from "../../Components/Inputs/Field";
import Link from "../../Components/Link";
import Select from "../../Components/Inputs/Select";
@@ -7,7 +7,11 @@ import { logger } from "../../Utils/Logger";
import "./index.css";
import { useDispatch, useSelector } from "react-redux";
import { createToast } from "../../Utils/toastUtils";
-import { deleteMonitorChecksByTeamId } from "../../Features/UptimeMonitors/uptimeMonitorsSlice";
+import {
+ deleteMonitorChecksByTeamId,
+ addDemoMonitors,
+ deleteAllMonitors,
+} from "../../Features/UptimeMonitors/uptimeMonitorsSlice";
import PropTypes from "prop-types";
import LoadingButton from "@mui/lab/LoadingButton";
const Settings = ({ isAdmin }) => {
@@ -36,6 +40,34 @@ const Settings = ({ isAdmin }) => {
}
};
+ const handleInsertDemoMonitors = async () => {
+ try {
+ const action = await dispatch(addDemoMonitors({ authToken }));
+ if (addDemoMonitors.fulfilled.match(action)) {
+ createToast({ body: "Successfully added demo monitors" });
+ } else {
+ createToast({ body: "Failed to add demo monitors" });
+ }
+ } catch (error) {
+ logger.error(error);
+ createToast({ Body: "Failed to add demo monitors" });
+ }
+ };
+
+ const handleDeleteAllMonitors = async () => {
+ try {
+ const action = await dispatch(deleteAllMonitors({ authToken }));
+ if (deleteAllMonitors.fulfilled.match(action)) {
+ createToast({ body: "Successfully deleted all monitors" });
+ } else {
+ createToast({ body: "Failed to add demo monitors" });
+ }
+ } catch (error) {
+ logger.error(error);
+ createToast({ Body: "Failed to delete all monitors" });
+ }
+ };
+
const ConfigBox = styled("div")({
display: "flex",
flexDirection: "row",
@@ -140,6 +172,42 @@ const Settings = ({ isAdmin }) => {
)}
+ {isAdmin && (
+
+
+ Demo Monitors
+
+ Here you can add and remove demo monitors
+
+
+
+
+ Add demo monitors
+
+ Add demo monitors
+
+
+
+ Remove all monitors
+
+ Remove all monitors
+
+
+
+
+ )}
About
diff --git a/Client/src/Utils/NetworkService.js b/Client/src/Utils/NetworkService.js
index e4b7be526..a9d93b301 100644
--- a/Client/src/Utils/NetworkService.js
+++ b/Client/src/Utils/NetworkService.js
@@ -274,6 +274,46 @@ class NetworkService {
);
}
+ /**
+ * ************************************
+ * Adds demo monitors
+ * ************************************
+ *
+ * @async
+ * @param {string} authToken - The authorization token to be used in the request header.
+ * @returns {Promise} The response from the axios POST request.
+ */
+ async addDemoMonitors(authToken) {
+ return this.axiosInstance.post(
+ `/monitors/demo`,
+ {},
+ {
+ headers: {
+ Authorization: `Bearer ${authToken}`,
+ "Content-Type": "application/json",
+ },
+ }
+ );
+ }
+
+ /**
+ * ************************************
+ * Deletes all monitors for a team by team ID
+ * ************************************
+ *
+ * @async
+ * @param {string} authToken - The authorization token to be used in the request header.
+ * @returns {Promise} The response from the axios DELETE request.
+ */
+ async deleteAllMonitors(authToken) {
+ return this.axiosInstance.delete(`/monitors/`, {
+ headers: {
+ Authorization: `Bearer ${authToken}`,
+ "Content-Type": "application/json",
+ },
+ });
+ }
+
/**
* ************************************
* Gets the certificate expiry for a monitor
diff --git a/Client/src/assets/data/hostnames.json b/Client/src/assets/data/hostnames.json
deleted file mode 100644
index b66818c3a..000000000
--- a/Client/src/assets/data/hostnames.json
+++ /dev/null
@@ -1,1290 +0,0 @@
-[
- {
- "Company Name": "0to255",
- "Company Link ": "https://0to255.com"
- },
- {
- "Company Name": "10015.io",
- "Company Link ": "https://10015.io"
- },
- {
- "Company Name": "3DIcons",
- "Company Link ": "https://3dicons.co"
- },
- {
- "Company Name": "About.me",
- "Company Link ": "https://about.me"
- },
- {
- "Company Name": "Alias",
- "Company Link ": "https://alias.co"
- },
- {
- "Company Name": "All About Berlin",
- "Company Link ": "https://allaboutberlin.com"
- },
- {
- "Company Name": "All Acronyms",
- "Company Link ": "https://allacronyms.com"
- },
- {
- "Company Name": "All You Can Read ",
- "Company Link ": "https://allyoucanread.com"
- },
- {
- "Company Name": "AllTrails",
- "Company Link ": "https://alltrails.com"
- },
- {
- "Company Name": "Anotepad",
- "Company Link ": "https://anotepad.com"
- },
- {
- "Company Name": "AnswerSocrates",
- "Company Link ": "https://answersocrates.com"
- },
- {
- "Company Name": "AnswerThePublic ",
- "Company Link ": "https://answerthepublic.com"
- },
- {
- "Company Name": "Apollo ",
- "Company Link ": "https://apollo.io"
- },
- {
- "Company Name": "ArrayList",
- "Company Link ": "https://arraylist.org"
- },
- {
- "Company Name": "Ask Difference",
- "Company Link ": "https://askdifference.com"
- },
- {
- "Company Name": "Audd.io",
- "Company Link ": "https://audd.io"
- },
- {
- "Company Name": "Audiocheck",
- "Company Link ": "https://audiocheck.net"
- },
- {
- "Company Name": "Audionautix",
- "Company Link ": "https://audionautix.com"
- },
- {
- "Company Name": "Authentic Jobs",
- "Company Link ": "https://authenticjobs.com"
- },
- {
- "Company Name": "Behind the Name",
- "Company Link ": "https://behindthename.com"
- },
- {
- "Company Name": "Bilim Terimleri",
- "Company Link ": "https://terimler.org"
- },
- {
- "Company Name": "BitBof",
- "Company Link ": "https://bitbof.com"
- },
- {
- "Company Name": "Blank Page",
- "Company Link ": "https://blank.page"
- },
- {
- "Company Name": "Bonanza",
- "Company Link ": "https://bonanza.com"
- },
- {
- "Company Name": "BookCrossing",
- "Company Link ": "https://bookcrossing.com"
- },
- {
- "Company Name": "Browse AI",
- "Company Link ": "https://browse.ai"
- },
- {
- "Company Name": "Bubbl.us",
- "Company Link ": "https://bubbl.us"
- },
- {
- "Company Name": "Business Model Toolbox",
- "Company Link ": "https://bmtoolbox.net"
- },
- {
- "Company Name": "ByClickDownloader",
- "Company Link ": "https://byclickdownloader.com"
- },
- {
- "Company Name": "Calligraphr",
- "Company Link ": "https://calligraphr.com"
- },
- {
- "Company Name": "CertificateClaim",
- "Company Link ": "https://certificateclaim.com"
- },
- {
- "Company Name": "Chosic",
- "Company Link ": "https://chosic.com"
- },
- {
- "Company Name": "ClipDrop",
- "Company Link ": "https://clipdrop.co"
- },
- {
- "Company Name": "CloudConvert",
- "Company Link ": "https://cloudconvert.com"
- },
- {
- "Company Name": "CodingFont",
- "Company Link ": "https://codingfont.com"
- },
- {
- "Company Name": "Color Hunt",
- "Company Link ": "https://colorhunt.co"
- },
- {
- "Company Name": "ColorHexa",
- "Company Link ": "https://colorhexa.com"
- },
- {
- "Company Name": "Conversion-Tool",
- "Company Link ": "https://conversion-tool.com"
- },
- {
- "Company Name": "Cool Startup Jobs",
- "Company Link ": "https://coolstartupjobs.com"
- },
- {
- "Company Name": "Coroflot",
- "Company Link ": "https://coroflot.com"
- },
- {
- "Company Name": "Corrupt-a-File",
- "Company Link ": "https://corrupt-a-file.net"
- },
- {
- "Company Name": "Couchsurfing",
- "Company Link ": "https://couchsurfing.com"
- },
- {
- "Company Name": "Countries Been",
- "Company Link ": "https://countriesbeen.com"
- },
- {
- "Company Name": "Country Code",
- "Company Link ": "https://countrycode.org"
- },
- {
- "Company Name": "Creately",
- "Company Link ": "https://creately.com"
- },
- {
- "Company Name": "Creately ",
- "Company Link ": "https://creately.com"
- },
- {
- "Company Name": "Crossfade.io",
- "Company Link ": "https://crossfade.io"
- },
- {
- "Company Name": "Crunchbase",
- "Company Link ": "https://crunchbase.com"
- },
- {
- "Company Name": "CVmkr",
- "Company Link ": "https://cvwizard.com"
- },
- {
- "Company Name": "Daily Remote",
- "Company Link ": "https://dailyremote.com"
- },
- {
- "Company Name": "David Li",
- "Company Link ": "https://david.li"
- },
- {
- "Company Name": "DemandHunt",
- "Company Link ": "https://demandhunt.com"
- },
- {
- "Company Name": "Designify",
- "Company Link ": "https://designify.com"
- },
- {
- "Company Name": "Diff Checker",
- "Company Link ": "https://diffchecker.com"
- },
- {
- "Company Name": "DifferenceBetween.info",
- "Company Link ": "https://differencebetween.info"
- },
- {
- "Company Name": "Digital Glossary",
- "Company Link ": "https://digital-glossary.com"
- },
- {
- "Company Name": "Dimensions",
- "Company Link ": "https://dimensions.com"
- },
- {
- "Company Name": "Discoverify Music",
- "Company Link ": "https://discoverifymusic.com"
- },
- {
- "Company Name": "discu.eu",
- "Company Link ": "https://discu.eu"
- },
- {
- "Company Name": "Do It Yourself",
- "Company Link ": "https://doityourself.com"
- },
- {
- "Company Name": "Donkey Car",
- "Company Link ": "https://donkeycar.com"
- },
- {
- "Company Name": "draw.io",
- "Company Link ": "https://drawio.com"
- },
- {
- "Company Name": "Drumeo",
- "Company Link ": "https://drumeo.com"
- },
- {
- "Company Name": "Dummies",
- "Company Link ": "https://dummies.com"
- },
- {
- "Company Name": "Easel.ly",
- "Company Link ": "https://easel.ly"
- },
- {
- "Company Name": "Educalingo",
- "Company Link ": "https://educalingo.com"
- },
- {
- "Company Name": "Emoji Combos",
- "Company Link ": "https://emojicombos.com"
- },
- {
- "Company Name": "EquityBee",
- "Company Link ": "https://equitybee.com"
- },
- {
- "Company Name": "EquityZen",
- "Company Link ": "https://equityzen.com"
- },
- {
- "Company Name": "Escape Room Tips",
- "Company Link ": "https://escaperoomtips.com"
- },
- {
- "Company Name": "Every Noise",
- "Company Link ": "https://everynoise.com"
- },
- {
- "Company Name": "Every Time Zone",
- "Company Link ": "https://everytimezone.com"
- },
- {
- "Company Name": "Excalideck",
- "Company Link ": "https://excalideck.com"
- },
- {
- "Company Name": "Excalidraw",
- "Company Link ": "https://excalidraw.com"
- },
- {
- "Company Name": "Extract pics",
- "Company Link ": "https://extract.pics"
- },
- {
- "Company Name": "EZGIF",
- "Company Link ": "https://ezgif.com"
- },
- {
- "Company Name": "FactSlides",
- "Company Link ": "https://factslides.com"
- },
- {
- "Company Name": "FIGR ",
- "Company Link ": "https://figr.app"
- },
- {
- "Company Name": "Fine Dictionary",
- "Company Link ": "https://finedictionary.com"
- },
- {
- "Company Name": "Fiverr",
- "Company Link ": "https://fiverr.com"
- },
- {
- "Company Name": "Fix It Club",
- "Company Link ": "https://fixitclub.com"
- },
- {
- "Company Name": "FlexJobs",
- "Company Link ": "https://flexjobs.com"
- },
- {
- "Company Name": "Flightradar24",
- "Company Link ": "https://flightradar24.com"
- },
- {
- "Company Name": "FlowCV ",
- "Company Link ": "https://flowcv.com"
- },
- {
- "Company Name": "Foco Clipping",
- "Company Link ": "https://fococlipping.com"
- },
- {
- "Company Name": "Font Squirrel",
- "Company Link ": "https://fontsquirrel.com"
- },
- {
- "Company Name": "FontAwesome",
- "Company Link ": "https://fontawesome.com"
- },
- {
- "Company Name": "Fontello ",
- "Company Link ": "https://fontello.com"
- },
- {
- "Company Name": "Form to Chatbot",
- "Company Link ": "https://formtochatbot.com"
- },
- {
- "Company Name": "Founder Resources",
- "Company Link ": "https://founderresources.io"
- },
- {
- "Company Name": "Franz",
- "Company Link ": "https://meetfranz.com"
- },
- {
- "Company Name": "Fraze It",
- "Company Link ": "https://fraze.it"
- },
- {
- "Company Name": "Freecycle",
- "Company Link ": "https://freecycle.org"
- },
- {
- "Company Name": "FreeType",
- "Company Link ": "https://freetype.org"
- },
- {
- "Company Name": "FutureM",
- "Company Link ": "https://futureme.org"
- },
- {
- "Company Name": "Generated.Photos",
- "Company Link ": "https://generated.photos"
- },
- {
- "Company Name": "Get Human",
- "Company Link ": "https://gethuman.com"
- },
- {
- "Company Name": "Go Bento",
- "Company Link ": "https://gobento.com"
- },
- {
- "Company Name": "Good CV",
- "Company Link ": "https://goodcv.com"
- },
- {
- "Company Name": "Grammar Monster",
- "Company Link ": "https://grammar-monster.com"
- },
- {
- "Company Name": "Grammar Book",
- "Company Link ": "https://grammarbook.com"
- },
- {
- "Company Name": "Gummy Search",
- "Company Link ": "https://gummysearch.com"
- },
- {
- "Company Name": "Gumroad",
- "Company Link ": "https://gumroad.com"
- },
- {
- "Company Name": "HealthIcons",
- "Company Link ": "https://healthicons.org"
- },
- {
- "Company Name": "HexColor",
- "Company Link ": "https://hexcolor.co"
- },
- {
- "Company Name": "Hidden Life Radio",
- "Company Link ": "https://hiddenliferadio.com"
- },
- {
- "Company Name": "Hired",
- "Company Link ": "https://lhh.com"
- },
- {
- "Company Name": "Honey",
- "Company Link ": "https://joinhoney.com"
- },
- {
- "Company Name": "HowStuffWorks",
- "Company Link ": "https://howstuffworks.com"
- },
- {
- "Company Name": "HugeIcons Pro",
- "Company Link ": "https://hugeicons.com"
- },
- {
- "Company Name": "Humble Bundle",
- "Company Link ": "https://humblebundle.com"
- },
- {
- "Company Name": "I Have No TV",
- "Company Link ": "https://ihavenotv.com"
- },
- {
- "Company Name": "I Miss the Office",
- "Company Link ": "https://imisstheoffice.eu"
- },
- {
- "Company Name": "IcoMoon",
- "Company Link ": "https://icomoon.io"
- },
- {
- "Company Name": "Iconfinder",
- "Company Link ": "https://iconfinder.com"
- },
- {
- "Company Name": "Icon Packs",
- "Company Link ": "https://iconpacks.net"
- },
- {
- "Company Name": "Iconshock",
- "Company Link ": "https://iconshock.com"
- },
- {
- "Company Name": "Iconz Design",
- "Company Link ": "https://iconz.design"
- },
- {
- "Company Name": "iFixit",
- "Company Link ": "https://ifixit.com"
- },
- {
- "Company Name": "IFTTT",
- "Company Link ": "https://ifttt.com"
- },
- {
- "Company Name": "Illlustrations",
- "Company Link ": "https://illlustrations.co"
- },
- {
- "Company Name": "Illustration Kit",
- "Company Link ": "https://illustrationkit.com"
- },
- {
- "Company Name": "IMSDB",
- "Company Link ": "https://imsdb.com"
- },
- {
- "Company Name": "Incompetech",
- "Company Link ": "https://incompetech.com"
- },
- {
- "Company Name": "Incredibox",
- "Company Link ": "https://incredibox.com"
- },
- {
- "Company Name": "InnerBod",
- "Company Link ": "https://innerbody.com"
- },
- {
- "Company Name": "Instructables",
- "Company Link ": "https://instructables.com"
- },
- {
- "Company Name": "Integromat",
- "Company Link ": "https://make.com"
- },
- {
- "Company Name": "Investopedia",
- "Company Link ": "https://investopedia.com"
- },
- {
- "Company Name": "Japanese Wiki Corpus",
- "Company Link ": "https://japanesewiki.com"
- },
- {
- "Company Name": "Jitter.Video",
- "Company Link ": "https://jitter.video"
- },
- {
- "Company Name": "Jobspresso",
- "Company Link ": "https://jobspresso.co"
- },
- {
- "Company Name": "JPEG-Optimizer",
- "Company Link ": "https://jpeg-optimizer.com"
- },
- {
- "Company Name": "JS Remotely",
- "Company Link ": "https://jsremotely.com"
- },
- {
- "Company Name": "JScreenFix",
- "Company Link ": "https://jscreenfix.com"
- },
- {
- "Company Name": "JSON Resume",
- "Company Link ": "https://jsonresume.io"
- },
- {
- "Company Name": "Just Join",
- "Company Link ": "https://justjoin.it"
- },
- {
- "Company Name": "Just the Recipe",
- "Company Link ": "https://justtherecipe.com"
- },
- {
- "Company Name": "JustRemote",
- "Company Link ": "https://justremote.co"
- },
- {
- "Company Name": "JustWatch",
- "Company Link ": "https://justwatch.com"
- },
- {
- "Company Name": "Kanopy",
- "Company Link ": "https://kanopy.com"
- },
- {
- "Company Name": "Kassellabs",
- "Company Link ": "https://kassellabs.io"
- },
- {
- "Company Name": "Key Differences",
- "Company Link ": "https://keydifferences.com"
- },
- {
- "Company Name": "Keybase",
- "Company Link ": "https://keybase.io"
- },
- {
- "Company Name": "KeyValues",
- "Company Link ": "https://keyvalues.com"
- },
- {
- "Company Name": "KHInsider",
- "Company Link ": "https://khinsider.com"
- },
- {
- "Company Name": "Killed by Google",
- "Company Link ": "https://killedbygoogle.com"
- },
- {
- "Company Name": "Kimovil",
- "Company Link ": "https://kimovil.com"
- },
- {
- "Company Name": "Lalal.ai",
- "Company Link ": "https://www.lalal.ai"
- },
- {
- "Company Name": "Learn Anything",
- "Company Link ": "https://learn-anything.xyz"
- },
- {
- "Company Name": "LendingTree",
- "Company Link ": "https://lendingtree.com"
- },
- {
- "Company Name": "Lightyear.fm",
- "Company Link ": "https://lightyear.fm"
- },
- {
- "Company Name": "LittleSis",
- "Company Link ": "https://littlesis.org"
- },
- {
- "Company Name": "Looria",
- "Company Link ": "https://looria.com"
- },
- {
- "Company Name": "Lucidchart",
- "Company Link ": "https://lucidchart.com"
- },
- {
- "Company Name": "Lunar",
- "Company Link ": "https://lunar.fyi"
- },
- {
- "Company Name": "Manuals Lib",
- "Company Link ": "https://manualslib.com"
- },
- {
- "Company Name": "Map Crunch",
- "Company Link ": "https://mapcrunch.com"
- },
- {
- "Company Name": "Masterworks",
- "Company Link ": "https://masterworks.com"
- },
- {
- "Company Name": "MediaFire",
- "Company Link ": "https://mediafire.com"
- },
- {
- "Company Name": "Mind Mup",
- "Company Link ": "https://mindmup.com"
- },
- {
- "Company Name": "Mixlr",
- "Company Link ": "https://mixlr.com"
- },
- {
- "Company Name": "Moises AI",
- "Company Link ": "https://moises.ai"
- },
- {
- "Company Name": "Money",
- "Company Link ": "https://money.com"
- },
- {
- "Company Name": "Mountain Project",
- "Company Link ": "https://mountainproject.com"
- },
- {
- "Company Name": "Movie Map",
- "Company Link ": "https://movie-map.com"
- },
- {
- "Company Name": "Movie Sounds",
- "Company Link ": "https://movie-sounds.org"
- },
- {
- "Company Name": "MP3Cut",
- "Company Link ": "https://mp3cut.net"
- },
- {
- "Company Name": "Murmel",
- "Company Link ": "https://murmel.social"
- },
- {
- "Company Name": "Muscle Wiki",
- "Company Link ": "https://musclewiki.com"
- },
- {
- "Company Name": "Music-Map",
- "Company Link ": "https://music-map.com"
- },
- {
- "Company Name": "MusicTheory.net",
- "Company Link ": "https://musictheory.net"
- },
- {
- "Company Name": "MyFonts",
- "Company Link ": "https://myfonts.com"
- },
- {
- "Company Name": "MyFridgeFood",
- "Company Link ": "https://myfridgefood.com"
- },
- {
- "Company Name": "Nameberry",
- "Company Link ": "https://nameberry.com"
- },
- {
- "Company Name": "Namechk",
- "Company Link ": "https://namechk.com"
- },
- {
- "Company Name": "Ncase",
- "Company Link ": "https://ncase.me"
- },
- {
- "Company Name": "News in Levels",
- "Company Link ": "https://newsinlevels.com"
- },
- {
- "Company Name": "Noisli",
- "Company Link ": "https://noisli.com"
- },
- {
- "Company Name": "Notes.io",
- "Company Link ": "https://notes.io"
- },
- {
- "Company Name": "Novoresume",
- "Company Link ": "https://novoresume.com"
- },
- {
- "Company Name": "Ocoya",
- "Company Link ": "https://ocoya.com"
- },
- {
- "Company Name": "Old Computers Museum",
- "Company Link ": "https://oldcomputers.net"
- },
- {
- "Company Name": "Online Tone Generator",
- "Company Link ": "https://onlinetonegenerator.com"
- },
- {
- "Company Name": "Online-Convert",
- "Company Link ": "https://online-convert.com"
- },
- {
- "Company Name": "OnlineConversion",
- "Company Link ": "https://onlineconversion.com"
- },
- {
- "Company Name": "Online OCR",
- "Company Link ": "https://onlineocr.net"
- },
- {
- "Company Name": "OpenWeatherMap",
- "Company Link ": "https://openweathermap.org"
- },
- {
- "Company Name": "OrgPad",
- "Company Link ": "https://orgpad.com"
- },
- {
- "Company Name": "Passport Index",
- "Company Link ": "https://passportindex.org"
- },
- {
- "Company Name": "PDF Candy",
- "Company Link ": "https://pdfcandy.com"
- },
- {
- "Company Name": "PDF2DOC",
- "Company Link ": "https://pdf2doc.com"
- },
- {
- "Company Name": "PDFescape",
- "Company Link ": "https://pdfescape.com"
- },
- {
- "Company Name": "PfpMaker",
- "Company Link ": "https://pfpmaker.com"
- },
- {
- "Company Name": "PIDGI Wiki ",
- "Company Link ": "https://pidgi.net"
- },
- {
- "Company Name": "PimEyes",
- "Company Link ": "https://pimeyes.com"
- },
- {
- "Company Name": "Pipl ",
- "Company Link ": "https://pipl.com"
- },
- {
- "Company Name": "PixelBazaar",
- "Company Link ": "https://pixelbazaar.com"
- },
- {
- "Company Name": "PixelPaper",
- "Company Link ": "https://pixelpaper.io"
- },
- {
- "Company Name": "Ponly",
- "Company Link ": "https://ponly.com"
- },
- {
- "Company Name": "PowerToFly",
- "Company Link ": "https://powertofly.com"
- },
- {
- "Company Name": "Pretzel Rocks",
- "Company Link ": "https://pretzel.rocks"
- },
- {
- "Company Name": "PrintIt",
- "Company Link ": "https://printit.work"
- },
- {
- "Company Name": "Prismatext",
- "Company Link ": "https://prismatext.com"
- },
- {
- "Company Name": "Puffin Maps",
- "Company Link ": "https://puffinmaps.com"
- },
- {
- "Company Name": "Puzzle Loop ",
- "Company Link ": "https://puzzle-loop.com"
- },
- {
- "Company Name": "QuoteMaster",
- "Company Link ": "https://quotemaster.org"
- },
- {
- "Company Name": "Radio Garden",
- "Company Link ": "https://radio.garden"
- },
- {
- "Company Name": "Radiooooo",
- "Company Link ": "https://radiooooo.com"
- },
- {
- "Company Name": "Radiosondy",
- "Company Link ": "https://radiosondy.info"
- },
- {
- "Company Name": "Rainy Mood",
- "Company Link ": "https://rainymood.com"
- },
- {
- "Company Name": "Random Street View",
- "Company Link ": "https://randomstreetview.com"
- },
- {
- "Company Name": "Rap4Ever",
- "Company Link ": "https://rap4all.com"
- },
- {
- "Company Name": "RareFilm",
- "Company Link ": "https://rarefilm.net"
- },
- {
- "Company Name": "Rattibha",
- "Company Link ": "https://rattibha.com"
- },
- {
- "Company Name": "Reddit List ",
- "Company Link ": "https://redditlist.com"
- },
- {
- "Company Name": "RedditSearch.io",
- "Company Link ": "https://redditsearch.io"
- },
- {
- "Company Name": "Reelgood",
- "Company Link ": "https://reelgood.com"
- },
- {
- "Company Name": "Reface",
- "Company Link ": "https://reface.ai"
- },
- {
- "Company Name": "Rejected.us",
- "Company Link ": "https://rejected.us"
- },
- {
- "Company Name": "Relanote",
- "Company Link ": "https://relanote.com"
- },
- {
- "Company Name": "Remote Leaf",
- "Company Link ": "https://remoteleaf.com"
- },
- {
- "Company Name": "Remote OK",
- "Company Link ": "https://remoteok.com"
- },
- {
- "Company Name": "Remote Starter Kit ",
- "Company Link ": "https://remotestarterkit.com"
- },
- {
- "Company Name": "Remote.co",
- "Company Link ": "https://remote.co"
- },
- {
- "Company Name": "Remote Base ",
- "Company Link ": "https://remotebase.com"
- },
- {
- "Company Name": "Remote Bear",
- "Company Link ": "https://remotebear.io"
- },
- {
- "Company Name": "Remove.bg",
- "Company Link ": "https://remove.bg"
- },
- {
- "Company Name": "Respresso",
- "Company Link ": "https://respresso.io"
- },
- {
- "Company Name": "Reveddit",
- "Company Link ": "https://reveddit.com"
- },
- {
- "Company Name": "Rhymer",
- "Company Link ": "https://rhymer.com"
- },
- {
- "Company Name": "RhymeZone",
- "Company Link ": "https://rhymezone.com"
- },
- {
- "Company Name": "Ribbet",
- "Company Link ": "https://ribbet.com"
- },
- {
- "Company Name": "Roadmap.sh",
- "Company Link ": "https://roadmap.sh"
- },
- {
- "Company Name": "Roadtrippers",
- "Company Link ": "https://roadtrippers.com"
- },
- {
- "Company Name": "RxResu.me",
- "Company Link ": "https://rxresu.me"
- },
- {
- "Company Name": "SchemeColor",
- "Company Link ": "https://schemecolor.com"
- },
- {
- "Company Name": "Screenshot.Guru",
- "Company Link ": "https://screenshot.guru"
- },
- {
- "Company Name": "SeatGuru",
- "Company Link ": "https://seatguru.com"
- },
- {
- "Company Name": "Sessions",
- "Company Link ": "https://sessions.us"
- },
- {
- "Company Name": "Shottr",
- "Company Link ": "https://shottr.cc"
- },
- {
- "Company Name": "Signature Maker",
- "Company Link ": "https://signature-maker.net"
- },
- {
- "Company Name": "Skip The Drive",
- "Company Link ": "https://skipthedrive.com"
- },
- {
- "Company Name": "Slowby",
- "Company Link ": "https://slowby.travel"
- },
- {
- "Company Name": "Small World",
- "Company Link ": "https://smallworld.kiwi"
- },
- {
- "Company Name": "SmallPDF",
- "Company Link ": "https://smallpdf.com"
- },
- {
- "Company Name": "Social Image Maker",
- "Company Link ": "https://socialimagemaker.io"
- },
- {
- "Company Name": "Social Sizes",
- "Company Link ": "https://socialsizes.io"
- },
- {
- "Company Name": "SoundLove",
- "Company Link ": "https://soundlove.se"
- },
- {
- "Company Name": "Spline",
- "Company Link ": "https://spline.design"
- },
- {
- "Company Name": "Starkey Comics",
- "Company Link ": "https://starkeycomics.com"
- },
- {
- "Company Name": "Startups List",
- "Company Link ": "https://startups-list.com"
- },
- {
- "Company Name": "Statista",
- "Company Link ": "https://statista.com"
- },
- {
- "Company Name": "Stolen Camera Finder",
- "Company Link ": "https://stolencamerafinder.com"
- },
- {
- "Company Name": "Strobe.Cool",
- "Company Link ": "https://strobe.cool"
- },
- {
- "Company Name": "Sumo",
- "Company Link ": "https://sumo.app"
- },
- {
- "Company Name": "SuperMeme AI",
- "Company Link ": "https://supermeme.ai"
- },
- {
- "Company Name": "Synthesia",
- "Company Link ": "https://synthesia.io"
- },
- {
- "Company Name": "TablerIcons",
- "Company Link ": "https://tablericons.com"
- },
- {
- "Company Name": "Tango",
- "Company Link ": "https://tango.us"
- },
- {
- "Company Name": "TasteDive",
- "Company Link ": "https://tastedive.com"
- },
- {
- "Company Name": "TechSpecs",
- "Company Link ": "https://techspecs.io"
- },
- {
- "Company Name": "Teoria",
- "Company Link ": "https://teoria.com"
- },
- {
- "Company Name": "Text Faces",
- "Company Link ": "https://textfac.es"
- },
- {
- "Company Name": "The Balance Money",
- "Company Link ": "https://thebalancemoney.com"
- },
- {
- "Company Name": "The Punctuation Guide",
- "Company Link ": "https://thepunctuationguide.com"
- },
- {
- "Company Name": "This to That",
- "Company Link ": "https://thistothat.com"
- },
- {
- "Company Name": "This vs That",
- "Company Link ": "https://thisvsthat.io"
- },
- {
- "Company Name": "ThreadReaderApp ",
- "Company Link ": "https://threadreaderapp.com"
- },
- {
- "Company Name": "Thumbly",
- "Company Link ": "https://tokee.ai"
- },
- {
- "Company Name": "Tiii.me",
- "Company Link ": "https://tiii.me"
- },
- {
- "Company Name": "TikTok Video Downloader",
- "Company Link ": "https://ttvdl.com"
- },
- {
- "Company Name": "Time and Date",
- "Company Link ": "https://timeanddate.com"
- },
- {
- "Company Name": "Time.is",
- "Company Link ": "https://time.is"
- },
- {
- "Company Name": "Title Case",
- "Company Link ": "https://titlecase.com"
- },
- {
- "Company Name": "Toaster Central",
- "Company Link ": "https://toastercentral.com"
- },
- {
- "Company Name": "Tongue-Twister ",
- "Company Link ": "https://tongue-twister.net"
- },
- {
- "Company Name": "TradingView",
- "Company Link ": "https://tradingview.com"
- },
- {
- "Company Name": "Transparent Textures",
- "Company Link ": "https://transparenttextures.com"
- },
- {
- "Company Name": "Tubi TV",
- "Company Link ": "https://tubitv.com"
- },
- {
- "Company Name": "Tunefind",
- "Company Link ": "https://tunefind.com"
- },
- {
- "Company Name": "TuneMyMusic",
- "Company Link ": "https://tunemymusic.com"
- },
- {
- "Company Name": "Tweepsmap",
- "Company Link ": "https://fedica.com"
- },
- {
- "Company Name": "Two Peas and Their Pod",
- "Company Link ": "https://twopeasandtheirpod.com"
- },
- {
- "Company Name": "Typatone",
- "Company Link ": "https://typatone.com"
- },
- {
- "Company Name": "Under Glass",
- "Company Link ": "https://underglass.io"
- },
- {
- "Company Name": "UniCorner",
- "Company Link ": "https://unicorner.news"
- },
- {
- "Company Name": "Unita",
- "Company Link ": "https://unita.co"
- },
- {
- "Company Name": "UnitConverters",
- "Company Link ": "https://unitconverters.net"
- },
- {
- "Company Name": "Unreadit",
- "Company Link ": "https://unreadit.com"
- },
- {
- "Company Name": "Unscreen",
- "Company Link ": "https://unscreen.com"
- },
- {
- "Company Name": "UnTools ",
- "Company Link ": "https://untools.co"
- },
- {
- "Company Name": "Upwork",
- "Company Link ": "https://upwork.com"
- },
- {
- "Company Name": "UTF8 Icons",
- "Company Link ": "https://utf8icons.com"
- },
- {
- "Company Name": "Vector Magic",
- "Company Link ": "https://vectormagic.com"
- },
- {
- "Company Name": "Virtual Vacation",
- "Company Link ": "https://virtualvacation.us"
- },
- {
- "Company Name": "Virtual Vocations",
- "Company Link ": "https://virtualvocations.com"
- },
- {
- "Company Name": "Visiwig",
- "Company Link ": "https://visiwig.com"
- },
- {
- "Company Name": "Visual CV",
- "Company Link ": "https://visualcv.com"
- },
- {
- "Company Name": "Vocus.io",
- "Company Link ": "https://vocus.io"
- },
- {
- "Company Name": "Voscreen",
- "Company Link ": "https://voscreen.com"
- },
- {
- "Company Name": "Wanderprep",
- "Company Link ": "https://wanderprep.com"
- },
- {
- "Company Name": "Warmshowers",
- "Company Link ": "https:/warmshowers.org"
- },
- {
- "Company Name": "Watch Documentaries",
- "Company Link ": "https://watchdocumentaries.com"
- },
- {
- "Company Name": "We Work Remotely",
- "Company Link ": "https://weworkremotely.com"
- },
- {
- "Company Name": "Web2PDFConvert",
- "Company Link ": "https://web2pdfconvert.com"
- },
- {
- "Company Name": "Welcome to My Garden",
- "Company Link ": "https://welcometomygarden.org"
- },
- {
- "Company Name": "When2meet ",
- "Company Link ": "https://when2meet.com"
- },
- {
- "Company Name": "Where's George",
- "Company Link ": "https://wheresgeorge.com"
- },
- {
- "Company Name": "Where's Willy",
- "Company Link ": "https://whereswilly.com"
- },
- {
- "Company Name": "WikiHow",
- "Company Link ": "https://wikihow.com"
- },
- {
- "Company Name": "Windy",
- "Company Link ": "https://www.windy.com"
- },
- {
- "Company Name": "WonderHowTo",
- "Company Link ": "https://wonderhowto.com"
- },
- {
- "Company Name": "Working Nomads",
- "Company Link ": "https://workingnomads.com"
- },
- {
- "Company Name": "Wormhole",
- "Company Link ": "https://wormhole.app"
- },
- {
- "Company Name": "Y Combinator Jobs",
- "Company Link ": "https://ycombinator.com"
- },
- {
- "Company Name": "Yes Promo",
- "Company Link ": "https://yespromo.me"
- },
- {
- "Company Name": "YouGlish",
- "Company Link ": "https://youglish.com"
- },
- {
- "Company Name": "Zamzar",
- "Company Link ": "https://zamzar.com"
- },
- {
- "Company Name": "Zippyshare",
- "Company Link ": "https://zippyshare.com"
- },
- {
- "Company Name": "Zoom Earth",
- "Company Link ": "https://zoom.earth"
- },
- {
- "Company Name": "Zoom.it",
- "Company Link ": "https://zoom.it"
- }
-]
\ No newline at end of file
diff --git a/Server/controllers/authController.js b/Server/controllers/authController.js
index fe406a6b6..b3a809a09 100644
--- a/Server/controllers/authController.js
+++ b/Server/controllers/authController.js
@@ -17,6 +17,7 @@ require("dotenv").config();
const { errorMessages, successMessages } = require("../utils/messages");
var jwt = require("jsonwebtoken");
const SERVICE_NAME = "auth";
+const { getTokenFromHeaders } = require("../utils/utils");
/**
* Creates and returns JWT token with an arbitrary payload
@@ -30,17 +31,6 @@ const issueToken = (payload) => {
return jwt.sign(payload, process.env.JWT_SECRET, { expiresIn: tokenTTL });
};
-const getTokenFromHeaders = (headers) => {
- const authorizationHeader = headers.authorization;
- if (!authorizationHeader) throw new Error("No auth headers");
-
- const parts = authorizationHeader.split(" ");
- if (parts.length !== 2 || parts[0] !== "Bearer")
- throw new Error("Invalid auth headers");
-
- return parts[1];
-};
-
/**
* @function
* @param {express.Request} req
diff --git a/Server/controllers/monitorController.js b/Server/controllers/monitorController.js
index 4571a9a65..c40135cdb 100644
--- a/Server/controllers/monitorController.js
+++ b/Server/controllers/monitorController.js
@@ -18,6 +18,9 @@ const {
const sslChecker = require("ssl-checker");
const SERVICE_NAME = "monitorController";
const { errorMessages, successMessages } = require("../utils/messages");
+const jwt = require("jsonwebtoken");
+const { getTokenFromHeaders } = require("../utils/utils");
+
/**
* Returns all monitors
* @async
@@ -365,12 +368,24 @@ const deleteMonitor = async (req, res, next) => {
const deleteAllMonitors = async (req, res) => {
try {
- const deleteCount = await req.db.deleteAllMonitors();
+ console.log("WTF");
+ const token = getTokenFromHeaders(req.headers);
+ const { teamId } = jwt.verify(token, process.env.JWT_SECRET);
+ const { monitors, deletedCount } = await req.db.deleteAllMonitors(teamId);
+ await monitors.forEach(async (monitor) => {
+ await req.jobQueue.deleteJob(monitor);
+ await req.db.deleteChecks(monitor._id);
+ await req.db.deleteAlertByMonitorId(monitor._id);
+ await req.db.deletePageSpeedChecksByMonitorId(monitor._id);
+ await req.db.deleteNotificationsByMonitorId(monitor._id);
+ });
+
return res
.status(200)
- .json({ success: true, msg: `Deleted ${deleteCount} monitors` });
+ .json({ success: true, msg: `Deleted ${deletedCount} monitors` });
} catch (error) {
error.service = SERVICE_NAME;
+ error.method === undefined && error.method === "deleteAllMonitors";
next(error);
}
};
@@ -466,6 +481,26 @@ const pauseMonitor = async (req, res, next) => {
}
};
+const addDemoMonitors = async (req, res, next) => {
+ try {
+ const token = getTokenFromHeaders(req.headers);
+ const { _id, teamId } = jwt.verify(token, process.env.JWT_SECRET);
+ const demoMonitors = await req.db.addDemoMonitors(_id, teamId);
+ await demoMonitors.forEach(async (monitor) => {
+ await req.jobQueue.addJob(monitor._id, monitor);
+ });
+ return res.status(200).json({
+ success: true,
+ message: successMessages.MONITOR_DEMO_ADDED,
+ data: demoMonitors.length,
+ });
+ } catch (error) {
+ error.service = SERVICE_NAME;
+ error.method === undefined && error.method === "addDemoMonitors";
+ next(error);
+ }
+};
+
module.exports = {
getAllMonitors,
getMonitorAggregateStats,
@@ -479,4 +514,5 @@ module.exports = {
deleteAllMonitors,
editMonitor,
pauseMonitor,
+ addDemoMonitors,
};
diff --git a/Server/db/mongo/MongoDB.js b/Server/db/mongo/MongoDB.js
index d6a4a243f..73d55d509 100644
--- a/Server/db/mongo/MongoDB.js
+++ b/Server/db/mongo/MongoDB.js
@@ -73,6 +73,7 @@ const {
deleteAllMonitors,
deleteMonitorsByUserId,
editMonitor,
+ addDemoMonitors,
} = require("./modules/monitorModule");
//****************************************
@@ -153,6 +154,7 @@ module.exports = {
deleteMonitor,
deleteAllMonitors,
editMonitor,
+ addDemoMonitors,
createCheck,
getChecksCount,
getChecks,
diff --git a/Server/db/mongo/modules/checkModule.js b/Server/db/mongo/modules/checkModule.js
index 32968431d..da3ccb8f3 100644
--- a/Server/db/mongo/modules/checkModule.js
+++ b/Server/db/mongo/modules/checkModule.js
@@ -1,6 +1,7 @@
const Check = require("../../../models/Check");
const Monitor = require("../../../models/Monitor");
-const mongoose = require("mongoose");
+const logger = require("../../../utils/logger");
+const SERVICE_NAME = "checkModule";
const dateRangeLookup = {
day: new Date(new Date().setDate(new Date().getDate() - 1)),
week: new Date(new Date().setDate(new Date().getDate() - 7)),
@@ -24,21 +25,25 @@ const createCheck = async (checkData) => {
try {
const { monitorId, status } = checkData;
- const n = await Check.countDocuments({ monitorId }) + 1;
+ const n = (await Check.countDocuments({ monitorId })) + 1;
const check = await new Check({ ...checkData }).save();
const monitor = await Monitor.findById(monitorId);
if (!monitor) {
- throw new Error("Monitor not found");
+ logger.error("Monitor not found", {
+ service: SERVICE_NAME,
+ monitorId,
+ });
+ return;
}
if (monitor.uptimePercentage === undefined) {
- monitor.uptimePercentage = (status === true) ? 1 : 0;
+ monitor.uptimePercentage = status === true ? 1 : 0;
} else {
monitor.uptimePercentage =
- (monitor.uptimePercentage * (n - 1) + (status === true ? 1: 0)) / n;
+ (monitor.uptimePercentage * (n - 1) + (status === true ? 1 : 0)) / n;
}
await monitor.save();
diff --git a/Server/db/mongo/modules/monitorModule.js b/Server/db/mongo/modules/monitorModule.js
index e77ccc696..5eaec7bf9 100644
--- a/Server/db/mongo/modules/monitorModule.js
+++ b/Server/db/mongo/modules/monitorModule.js
@@ -4,6 +4,7 @@ const PageSpeedCheck = require("../../../models/PageSpeedCheck");
const { errorMessages } = require("../../../utils/messages");
const Notification = require("../../../models/Notification");
const { NormalizeData } = require("../../../utils/dataUtils");
+const demoMonitors = require("../../../utils/demoMonitors.json");
/**
* Get all monitors
@@ -450,10 +451,12 @@ const deleteMonitor = async (req, res) => {
* DELETE ALL MONITORS (TEMP)
*/
-const deleteAllMonitors = async (req, res) => {
+const deleteAllMonitors = async (teamId) => {
try {
- const deletedCount = await Monitor.deleteMany({});
- return deletedCount.deletedCount;
+ const monitors = await Monitor.find({ teamId });
+ const { deletedCount } = await Monitor.deleteMany({ teamId });
+
+ return { monitors, deletedCount };
} catch (error) {
throw error;
}
@@ -493,6 +496,28 @@ const editMonitor = async (candidateId, candidateMonitor) => {
);
return editedMonitor;
} catch (error) {
+ error.method = "editMonitor";
+ throw error;
+ }
+};
+
+const addDemoMonitors = async (userId, teamId) => {
+ try {
+ const demoMonitorsToInsert = demoMonitors.map((monitor) => {
+ return {
+ userId,
+ teamId,
+ name: monitor.name,
+ description: monitor.name,
+ type: "http",
+ url: monitor.url,
+ interval: 60000,
+ };
+ });
+ const insertedMonitors = await Monitor.insertMany(demoMonitorsToInsert);
+ return insertedMonitors;
+ } catch (error) {
+ error.method = "addDemoMonitors";
throw error;
}
};
@@ -508,4 +533,5 @@ module.exports = {
deleteAllMonitors,
deleteMonitorsByUserId,
editMonitor,
+ addDemoMonitors,
};
diff --git a/Server/routes/monitorRoute.js b/Server/routes/monitorRoute.js
index b29b7130a..c6bec5f0f 100644
--- a/Server/routes/monitorRoute.js
+++ b/Server/routes/monitorRoute.js
@@ -32,7 +32,7 @@ router.put(
);
router.delete(
- "/all",
+ "/",
isAllowed(["superadmin"]),
monitorController.deleteAllMonitors
);
@@ -43,4 +43,10 @@ router.post(
monitorController.pauseMonitor
);
+router.post(
+ "/demo",
+ isAllowed(["admin", "superadmin"]),
+ monitorController.addDemoMonitors
+);
+
module.exports = router;
diff --git a/Server/service/networkService.js b/Server/service/networkService.js
index e25a63ce5..0664ee05a 100644
--- a/Server/service/networkService.js
+++ b/Server/service/networkService.js
@@ -278,6 +278,7 @@ class NetworkService {
default:
logger.error(`Unsupported type: ${job.data.type}`, {
service: this.SERVICE_NAME,
+ method: "getStatus",
jobId: job.id,
});
return false;
@@ -296,11 +297,13 @@ class NetworkService {
async logAndStoreCheck(data, writeToDB) {
try {
const insertedCheck = await writeToDB(data);
- return insertedCheck.status;
+ if (insertedCheck !== null && insertedCheck !== undefined) {
+ return insertedCheck.status;
+ }
} catch (error) {
- console.log(error);
logger.error(`Error wrtiting check for ${data.monitorId}`, {
service: this.SERVICE_NAME,
+ method: "logAndStoreCheck",
monitorId: data.monitorId,
error: error,
});
diff --git a/Server/utils/demoMonitors.json b/Server/utils/demoMonitors.json
new file mode 100644
index 000000000..6f57940f2
--- /dev/null
+++ b/Server/utils/demoMonitors.json
@@ -0,0 +1,1271 @@
+[
+ {
+ "name": "0to255",
+ "url": "https://0to255.com"
+ },
+ {
+ "name": "10015.io",
+ "url": "https://10015.io"
+ },
+ {
+ "name": "3DIcons",
+ "url": "https://3dicons.co"
+ },
+ {
+ "name": "About.me",
+ "url": "https://about.me"
+ },
+ {
+ "name": "Alias",
+ "url": "https://alias.co"
+ },
+ {
+ "name": "All About Berlin",
+ "url": "https://allaboutberlin.com"
+ },
+ {
+ "name": "All Acronyms",
+ "url": "https://allacronyms.com"
+ },
+ {
+ "name": "All You Can Read ",
+ "url": "https://allyoucanread.com"
+ },
+ {
+ "name": "AllTrails",
+ "url": "https://alltrails.com"
+ },
+ {
+ "name": "Anotepad",
+ "url": "https://anotepad.com"
+ },
+ {
+ "name": "AnswerSocrates",
+ "url": "https://answersocrates.com"
+ },
+ {
+ "name": "AnswerThePublic ",
+ "url": "https://answerthepublic.com"
+ },
+ {
+ "name": "Apollo ",
+ "url": "https://apollo.io"
+ },
+ {
+ "name": "ArrayList",
+ "url": "https://arraylist.org"
+ },
+ {
+ "name": "Ask Difference",
+ "url": "https://askdifference.com"
+ },
+ {
+ "name": "Audd.io",
+ "url": "https://audd.io"
+ },
+ {
+ "name": "Audiocheck",
+ "url": "https://audiocheck.net"
+ },
+ {
+ "name": "Audionautix",
+ "url": "https://audionautix.com"
+ },
+ {
+ "name": "Authentic Jobs",
+ "url": "https://authenticjobs.com"
+ },
+ {
+ "name": "Behind the Name",
+ "url": "https://behindthename.com"
+ },
+ {
+ "name": "Bilim Terimleri",
+ "url": "https://terimler.org"
+ },
+ {
+ "name": "BitBof",
+ "url": "https://bitbof.com"
+ },
+ {
+ "name": "Blank Page",
+ "url": "https://blank.page"
+ },
+ {
+ "name": "Bonanza",
+ "url": "https://bonanza.com"
+ },
+ {
+ "name": "BookCrossing",
+ "url": "https://bookcrossing.com"
+ },
+ {
+ "name": "Browse AI",
+ "url": "https://browse.ai"
+ },
+ {
+ "name": "Bubbl.us",
+ "url": "https://bubbl.us"
+ },
+ {
+ "name": "Business Model Toolbox",
+ "url": "https://bmtoolbox.net"
+ },
+ {
+ "name": "ByClickDownloader",
+ "url": "https://byclickdownloader.com"
+ },
+ {
+ "name": "Calligraphr",
+ "url": "https://calligraphr.com"
+ },
+ {
+ "name": "CertificateClaim",
+ "url": "https://certificateclaim.com"
+ },
+ {
+ "name": "Chosic",
+ "url": "https://chosic.com"
+ },
+ {
+ "name": "ClipDrop",
+ "url": "https://clipdrop.co"
+ },
+ {
+ "name": "CloudConvert",
+ "url": "https://cloudconvert.com"
+ },
+ {
+ "name": "CodingFont",
+ "url": "https://codingfont.com"
+ },
+ {
+ "name": "Color Hunt",
+ "url": "https://colorhunt.co"
+ },
+ {
+ "name": "ColorHexa",
+ "url": "https://colorhexa.com"
+ },
+ {
+ "name": "Conversion-Tool",
+ "url": "https://conversion-tool.com"
+ },
+ {
+ "name": "Cool Startup Jobs",
+ "url": "https://coolstartupjobs.com"
+ },
+ {
+ "name": "Coroflot",
+ "url": "https://coroflot.com"
+ },
+ {
+ "name": "Corrupt-a-File",
+ "url": "https://corrupt-a-file.net"
+ },
+ {
+ "name": "Couchsurfing",
+ "url": "https://couchsurfing.com"
+ },
+ {
+ "name": "Countries Been",
+ "url": "https://countriesbeen.com"
+ },
+ {
+ "name": "Country Code",
+ "url": "https://countrycode.org"
+ },
+ {
+ "name": "Creately",
+ "url": "https://creately.com"
+ },
+ {
+ "name": "Creately ",
+ "url": "https://creately.com"
+ },
+ {
+ "name": "Crossfade.io",
+ "url": "https://crossfade.io"
+ },
+ {
+ "name": "Crunchbase",
+ "url": "https://crunchbase.com"
+ },
+ {
+ "name": "CVmkr",
+ "url": "https://cvwizard.com"
+ },
+ {
+ "name": "Daily Remote",
+ "url": "https://dailyremote.com"
+ },
+ {
+ "name": "David Li",
+ "url": "https://david.li"
+ },
+ {
+ "name": "DemandHunt",
+ "url": "https://demandhunt.com"
+ },
+ {
+ "name": "Designify",
+ "url": "https://designify.com"
+ },
+ {
+ "name": "Diff Checker",
+ "url": "https://diffchecker.com"
+ },
+ {
+ "name": "DifferenceBetween.info",
+ "url": "https://differencebetween.info"
+ },
+ {
+ "name": "Digital Glossary",
+ "url": "https://digital-glossary.com"
+ },
+ {
+ "name": "Dimensions",
+ "url": "https://dimensions.com"
+ },
+ {
+ "name": "Discoverify Music",
+ "url": "https://discoverifymusic.com"
+ },
+ {
+ "name": "discu.eu",
+ "url": "https://discu.eu"
+ },
+ {
+ "name": "Do It Yourself",
+ "url": "https://doityourself.com"
+ },
+ {
+ "name": "draw.io",
+ "url": "https://drawio.com"
+ },
+ {
+ "name": "Drumeo",
+ "url": "https://drumeo.com"
+ },
+ {
+ "name": "Dummies",
+ "url": "https://dummies.com"
+ },
+ {
+ "name": "Easel.ly",
+ "url": "https://easel.ly"
+ },
+ {
+ "name": "Educalingo",
+ "url": "https://educalingo.com"
+ },
+ {
+ "name": "Emoji Combos",
+ "url": "https://emojicombos.com"
+ },
+ {
+ "name": "EquityBee",
+ "url": "https://equitybee.com"
+ },
+ {
+ "name": "EquityZen",
+ "url": "https://equityzen.com"
+ },
+ {
+ "name": "Escape Room Tips",
+ "url": "https://escaperoomtips.com"
+ },
+ {
+ "name": "Every Noise",
+ "url": "https://everynoise.com"
+ },
+ {
+ "name": "Every Time Zone",
+ "url": "https://everytimezone.com"
+ },
+ {
+ "name": "Excalideck",
+ "url": "https://excalideck.com"
+ },
+ {
+ "name": "Excalidraw",
+ "url": "https://excalidraw.com"
+ },
+ {
+ "name": "Extract pics",
+ "url": "https://extract.pics"
+ },
+ {
+ "name": "EZGIF",
+ "url": "https://ezgif.com"
+ },
+ {
+ "name": "FactSlides",
+ "url": "https://factslides.com"
+ },
+ {
+ "name": "FIGR ",
+ "url": "https://figr.app"
+ },
+ {
+ "name": "Fine Dictionary",
+ "url": "https://finedictionary.com"
+ },
+ {
+ "name": "Fiverr",
+ "url": "https://fiverr.com"
+ },
+ {
+ "name": "Fix It Club",
+ "url": "https://fixitclub.com"
+ },
+ {
+ "name": "Flightradar24",
+ "url": "https://flightradar24.com"
+ },
+ {
+ "name": "FlowCV ",
+ "url": "https://flowcv.com"
+ },
+ {
+ "name": "Font Squirrel",
+ "url": "https://fontsquirrel.com"
+ },
+ {
+ "name": "FontAwesome",
+ "url": "https://fontawesome.com"
+ },
+ {
+ "name": "Fontello ",
+ "url": "https://fontello.com"
+ },
+ {
+ "name": "Form to Chatbot",
+ "url": "https://formtochatbot.com"
+ },
+ {
+ "name": "Founder Resources",
+ "url": "https://founderresources.io"
+ },
+ {
+ "name": "Franz",
+ "url": "https://meetfranz.com"
+ },
+ {
+ "name": "Fraze It",
+ "url": "https://fraze.it"
+ },
+ {
+ "name": "Freecycle",
+ "url": "https://freecycle.org"
+ },
+ {
+ "name": "FreeType",
+ "url": "https://freetype.org"
+ },
+ {
+ "name": "FutureM",
+ "url": "https://futureme.org"
+ },
+ {
+ "name": "Generated.Photos",
+ "url": "https://generated.photos"
+ },
+ {
+ "name": "Get Human",
+ "url": "https://gethuman.com"
+ },
+ {
+ "name": "Go Bento",
+ "url": "https://gobento.com"
+ },
+ {
+ "name": "Good CV",
+ "url": "https://goodcv.com"
+ },
+ {
+ "name": "Grammar Monster",
+ "url": "https://grammar-monster.com"
+ },
+ {
+ "name": "Grammar Book",
+ "url": "https://grammarbook.com"
+ },
+ {
+ "name": "Gummy Search",
+ "url": "https://gummysearch.com"
+ },
+ {
+ "name": "Gumroad",
+ "url": "https://gumroad.com"
+ },
+ {
+ "name": "HealthIcons",
+ "url": "https://healthicons.org"
+ },
+ {
+ "name": "HexColor",
+ "url": "https://hexcolor.co"
+ },
+ {
+ "name": "Hidden Life Radio",
+ "url": "https://hiddenliferadio.com"
+ },
+ {
+ "name": "Hired",
+ "url": "https://lhh.com"
+ },
+ {
+ "name": "Honey",
+ "url": "https://joinhoney.com"
+ },
+ {
+ "name": "HowStuffWorks",
+ "url": "https://howstuffworks.com"
+ },
+ {
+ "name": "HugeIcons Pro",
+ "url": "https://hugeicons.com"
+ },
+ {
+ "name": "Humble Bundle",
+ "url": "https://humblebundle.com"
+ },
+ {
+ "name": "I Have No TV",
+ "url": "https://ihavenotv.com"
+ },
+ {
+ "name": "I Miss the Office",
+ "url": "https://imisstheoffice.eu"
+ },
+ {
+ "name": "IcoMoon",
+ "url": "https://icomoon.io"
+ },
+ {
+ "name": "Iconfinder",
+ "url": "https://iconfinder.com"
+ },
+ {
+ "name": "Icon Packs",
+ "url": "https://iconpacks.net"
+ },
+ {
+ "name": "Iconshock",
+ "url": "https://iconshock.com"
+ },
+ {
+ "name": "Iconz Design",
+ "url": "https://iconz.design"
+ },
+ {
+ "name": "iFixit",
+ "url": "https://ifixit.com"
+ },
+ {
+ "name": "IFTTT",
+ "url": "https://ifttt.com"
+ },
+ {
+ "name": "Illlustrations",
+ "url": "https://illlustrations.co"
+ },
+ {
+ "name": "Illustration Kit",
+ "url": "https://illustrationkit.com"
+ },
+ {
+ "name": "IMSDB",
+ "url": "https://imsdb.com"
+ },
+ {
+ "name": "Incompetech",
+ "url": "https://incompetech.com"
+ },
+ {
+ "name": "Incredibox",
+ "url": "https://incredibox.com"
+ },
+ {
+ "name": "InnerBod",
+ "url": "https://innerbody.com"
+ },
+ {
+ "name": "Instructables",
+ "url": "https://instructables.com"
+ },
+ {
+ "name": "Integromat",
+ "url": "https://make.com"
+ },
+ {
+ "name": "Investopedia",
+ "url": "https://investopedia.com"
+ },
+ {
+ "name": "Japanese Wiki Corpus",
+ "url": "https://japanesewiki.com"
+ },
+ {
+ "name": "Jitter.Video",
+ "url": "https://jitter.video"
+ },
+ {
+ "name": "Jobspresso",
+ "url": "https://jobspresso.co"
+ },
+ {
+ "name": "JPEG-Optimizer",
+ "url": "https://jpeg-optimizer.com"
+ },
+ {
+ "name": "JS Remotely",
+ "url": "https://jsremotely.com"
+ },
+ {
+ "name": "JScreenFix",
+ "url": "https://jscreenfix.com"
+ },
+ {
+ "name": "JSON Resume",
+ "url": "https://jsonresume.io"
+ },
+ {
+ "name": "Just Join",
+ "url": "https://justjoin.it"
+ },
+ {
+ "name": "Just the Recipe",
+ "url": "https://justtherecipe.com"
+ },
+ {
+ "name": "JustRemote",
+ "url": "https://justremote.co"
+ },
+ {
+ "name": "JustWatch",
+ "url": "https://justwatch.com"
+ },
+ {
+ "name": "Kanopy",
+ "url": "https://kanopy.com"
+ },
+ {
+ "name": "Kassellabs",
+ "url": "https://kassellabs.io"
+ },
+ {
+ "name": "Key Differences",
+ "url": "https://keydifferences.com"
+ },
+ {
+ "name": "Keybase",
+ "url": "https://keybase.io"
+ },
+ {
+ "name": "KeyValues",
+ "url": "https://keyvalues.com"
+ },
+ {
+ "name": "KHInsider",
+ "url": "https://khinsider.com"
+ },
+ {
+ "name": "Killed by Google",
+ "url": "https://killedbygoogle.com"
+ },
+ {
+ "name": "Kimovil",
+ "url": "https://kimovil.com"
+ },
+ {
+ "name": "Lalal.ai",
+ "url": "https://www.lalal.ai"
+ },
+ {
+ "name": "Learn Anything",
+ "url": "https://learn-anything.xyz"
+ },
+ {
+ "name": "LendingTree",
+ "url": "https://lendingtree.com"
+ },
+ {
+ "name": "Lightyear.fm",
+ "url": "https://lightyear.fm"
+ },
+ {
+ "name": "LittleSis",
+ "url": "https://littlesis.org"
+ },
+ {
+ "name": "Looria",
+ "url": "https://looria.com"
+ },
+ {
+ "name": "Lucidchart",
+ "url": "https://lucidchart.com"
+ },
+ {
+ "name": "Lunar",
+ "url": "https://lunar.fyi"
+ },
+ {
+ "name": "Manuals Lib",
+ "url": "https://manualslib.com"
+ },
+ {
+ "name": "Map Crunch",
+ "url": "https://mapcrunch.com"
+ },
+ {
+ "name": "Masterworks",
+ "url": "https://masterworks.com"
+ },
+ {
+ "name": "MediaFire",
+ "url": "https://mediafire.com"
+ },
+ {
+ "name": "Mixlr",
+ "url": "https://mixlr.com"
+ },
+ {
+ "name": "Moises AI",
+ "url": "https://moises.ai"
+ },
+ {
+ "name": "Money",
+ "url": "https://money.com"
+ },
+ {
+ "name": "Mountain Project",
+ "url": "https://mountainproject.com"
+ },
+ {
+ "name": "Movie Map",
+ "url": "https://movie-map.com"
+ },
+ {
+ "name": "Movie Sounds",
+ "url": "https://movie-sounds.org"
+ },
+ {
+ "name": "MP3Cut",
+ "url": "https://mp3cut.net"
+ },
+ {
+ "name": "Murmel",
+ "url": "https://murmel.social"
+ },
+ {
+ "name": "Muscle Wiki",
+ "url": "https://musclewiki.com"
+ },
+ {
+ "name": "Music-Map",
+ "url": "https://music-map.com"
+ },
+ {
+ "name": "MusicTheory.net",
+ "url": "https://musictheory.net"
+ },
+ {
+ "name": "MyFonts",
+ "url": "https://myfonts.com"
+ },
+ {
+ "name": "MyFridgeFood",
+ "url": "https://myfridgefood.com"
+ },
+ {
+ "name": "Nameberry",
+ "url": "https://nameberry.com"
+ },
+ {
+ "name": "Namechk",
+ "url": "https://namechk.com"
+ },
+ {
+ "name": "Ncase",
+ "url": "https://ncase.me"
+ },
+ {
+ "name": "News in Levels",
+ "url": "https://newsinlevels.com"
+ },
+ {
+ "name": "Noisli",
+ "url": "https://noisli.com"
+ },
+ {
+ "name": "Notes.io",
+ "url": "https://notes.io"
+ },
+ {
+ "name": "Novoresume",
+ "url": "https://novoresume.com"
+ },
+ {
+ "name": "Ocoya",
+ "url": "https://ocoya.com"
+ },
+ {
+ "name": "Old Computers Museum",
+ "url": "https://oldcomputers.net"
+ },
+ {
+ "name": "Online Tone Generator",
+ "url": "https://onlinetonegenerator.com"
+ },
+ {
+ "name": "Online-Convert",
+ "url": "https://online-convert.com"
+ },
+ {
+ "name": "OnlineConversion",
+ "url": "https://onlineconversion.com"
+ },
+ {
+ "name": "Online OCR",
+ "url": "https://onlineocr.net"
+ },
+ {
+ "name": "OpenWeatherMap",
+ "url": "https://openweathermap.org"
+ },
+ {
+ "name": "OrgPad",
+ "url": "https://orgpad.com"
+ },
+ {
+ "name": "Passport Index",
+ "url": "https://passportindex.org"
+ },
+ {
+ "name": "PDF Candy",
+ "url": "https://pdfcandy.com"
+ },
+ {
+ "name": "PDF2DOC",
+ "url": "https://pdf2doc.com"
+ },
+ {
+ "name": "PDFescape",
+ "url": "https://pdfescape.com"
+ },
+ {
+ "name": "PfpMaker",
+ "url": "https://pfpmaker.com"
+ },
+ {
+ "name": "PIDGI Wiki ",
+ "url": "https://pidgi.net"
+ },
+ {
+ "name": "PimEyes",
+ "url": "https://pimeyes.com"
+ },
+ {
+ "name": "Pipl ",
+ "url": "https://pipl.com"
+ },
+ {
+ "name": "PixelBazaar",
+ "url": "https://pixelbazaar.com"
+ },
+ {
+ "name": "PixelPaper",
+ "url": "https://pixelpaper.io"
+ },
+ {
+ "name": "Ponly",
+ "url": "https://ponly.com"
+ },
+ {
+ "name": "PowerToFly",
+ "url": "https://powertofly.com"
+ },
+ {
+ "name": "Pretzel Rocks",
+ "url": "https://pretzel.rocks"
+ },
+ {
+ "name": "PrintIt",
+ "url": "https://printit.work"
+ },
+ {
+ "name": "Prismatext",
+ "url": "https://prismatext.com"
+ },
+ {
+ "name": "Puffin Maps",
+ "url": "https://puffinmaps.com"
+ },
+ {
+ "name": "Puzzle Loop ",
+ "url": "https://puzzle-loop.com"
+ },
+ {
+ "name": "QuoteMaster",
+ "url": "https://quotemaster.org"
+ },
+ {
+ "name": "Radio Garden",
+ "url": "https://radio.garden"
+ },
+ {
+ "name": "Radiooooo",
+ "url": "https://radiooooo.com"
+ },
+ {
+ "name": "Radiosondy",
+ "url": "https://radiosondy.info"
+ },
+ {
+ "name": "Rainy Mood",
+ "url": "https://rainymood.com"
+ },
+ {
+ "name": "Random Street View",
+ "url": "https://randomstreetview.com"
+ },
+ {
+ "name": "Rap4Ever",
+ "url": "https://rap4all.com"
+ },
+ {
+ "name": "RareFilm",
+ "url": "https://rarefilm.net"
+ },
+ {
+ "name": "Rattibha",
+ "url": "https://rattibha.com"
+ },
+ {
+ "name": "Reddit List ",
+ "url": "https://redditlist.com"
+ },
+ {
+ "name": "RedditSearch.io",
+ "url": "https://redditsearch.io"
+ },
+ {
+ "name": "Reelgood",
+ "url": "https://reelgood.com"
+ },
+ {
+ "name": "Reface",
+ "url": "https://reface.ai"
+ },
+ {
+ "name": "Rejected.us",
+ "url": "https://rejected.us"
+ },
+ {
+ "name": "Relanote",
+ "url": "https://relanote.com"
+ },
+ {
+ "name": "Remote Leaf",
+ "url": "https://remoteleaf.com"
+ },
+ {
+ "name": "Remote OK",
+ "url": "https://remoteok.com"
+ },
+ {
+ "name": "Remote Starter Kit ",
+ "url": "https://remotestarterkit.com"
+ },
+ {
+ "name": "Remote.co",
+ "url": "https://remote.co"
+ },
+ {
+ "name": "Remote Base ",
+ "url": "https://remotebase.com"
+ },
+ {
+ "name": "Remote Bear",
+ "url": "https://remotebear.io"
+ },
+ {
+ "name": "Remove.bg",
+ "url": "https://remove.bg"
+ },
+ {
+ "name": "Respresso",
+ "url": "https://respresso.io"
+ },
+ {
+ "name": "Reveddit",
+ "url": "https://reveddit.com"
+ },
+ {
+ "name": "Rhymer",
+ "url": "https://rhymer.com"
+ },
+ {
+ "name": "RhymeZone",
+ "url": "https://rhymezone.com"
+ },
+ {
+ "name": "Ribbet",
+ "url": "https://ribbet.com"
+ },
+ {
+ "name": "Roadmap.sh",
+ "url": "https://roadmap.sh"
+ },
+ {
+ "name": "Roadtrippers",
+ "url": "https://roadtrippers.com"
+ },
+ {
+ "name": "RxResu.me",
+ "url": "https://rxresu.me"
+ },
+ {
+ "name": "SchemeColor",
+ "url": "https://schemecolor.com"
+ },
+ {
+ "name": "Screenshot.Guru",
+ "url": "https://screenshot.guru"
+ },
+ {
+ "name": "SeatGuru",
+ "url": "https://seatguru.com"
+ },
+ {
+ "name": "Sessions",
+ "url": "https://sessions.us"
+ },
+ {
+ "name": "Shottr",
+ "url": "https://shottr.cc"
+ },
+ {
+ "name": "Signature Maker",
+ "url": "https://signature-maker.net"
+ },
+ {
+ "name": "Skip The Drive",
+ "url": "https://skipthedrive.com"
+ },
+ {
+ "name": "Slowby",
+ "url": "https://slowby.travel"
+ },
+ {
+ "name": "Small World",
+ "url": "https://smallworld.kiwi"
+ },
+ {
+ "name": "SmallPDF",
+ "url": "https://smallpdf.com"
+ },
+ {
+ "name": "Social Image Maker",
+ "url": "https://socialimagemaker.io"
+ },
+ {
+ "name": "Social Sizes",
+ "url": "https://socialsizes.io"
+ },
+ {
+ "name": "SoundLove",
+ "url": "https://soundlove.se"
+ },
+ {
+ "name": "Spline",
+ "url": "https://spline.design"
+ },
+ {
+ "name": "Starkey Comics",
+ "url": "https://starkeycomics.com"
+ },
+
+ {
+ "name": "Statista",
+ "url": "https://statista.com"
+ },
+ {
+ "name": "Stolen Camera Finder",
+ "url": "https://stolencamerafinder.com"
+ },
+ {
+ "name": "Strobe.Cool",
+ "url": "https://strobe.cool"
+ },
+ {
+ "name": "Sumo",
+ "url": "https://sumo.app"
+ },
+ {
+ "name": "SuperMeme AI",
+ "url": "https://supermeme.ai"
+ },
+ {
+ "name": "Synthesia",
+ "url": "https://synthesia.io"
+ },
+ {
+ "name": "TablerIcons",
+ "url": "https://tablericons.com"
+ },
+ {
+ "name": "Tango",
+ "url": "https://tango.us"
+ },
+ {
+ "name": "TasteDive",
+ "url": "https://tastedive.com"
+ },
+ {
+ "name": "TechSpecs",
+ "url": "https://techspecs.io"
+ },
+ {
+ "name": "Teoria",
+ "url": "https://teoria.com"
+ },
+ {
+ "name": "Text Faces",
+ "url": "https://textfac.es"
+ },
+ {
+ "name": "The Balance Money",
+ "url": "https://thebalancemoney.com"
+ },
+ {
+ "name": "The Punctuation Guide",
+ "url": "https://thepunctuationguide.com"
+ },
+ {
+ "name": "This to That",
+ "url": "https://thistothat.com"
+ },
+ {
+ "name": "This vs That",
+ "url": "https://thisvsthat.io"
+ },
+ {
+ "name": "ThreadReaderApp ",
+ "url": "https://threadreaderapp.com"
+ },
+ {
+ "name": "Thumbly",
+ "url": "https://tokee.ai"
+ },
+ {
+ "name": "Tiii.me",
+ "url": "https://tiii.me"
+ },
+ {
+ "name": "TikTok Video Downloader",
+ "url": "https://ttvdl.com"
+ },
+ {
+ "name": "Time and Date",
+ "url": "https://timeanddate.com"
+ },
+ {
+ "name": "Time.is",
+ "url": "https://time.is"
+ },
+ {
+ "name": "Title Case",
+ "url": "https://titlecase.com"
+ },
+ {
+ "name": "Toaster Central",
+ "url": "https://toastercentral.com"
+ },
+ {
+ "name": "Tongue-Twister ",
+ "url": "https://tongue-twister.net"
+ },
+ {
+ "name": "TradingView",
+ "url": "https://tradingview.com"
+ },
+ {
+ "name": "Transparent Textures",
+ "url": "https://transparenttextures.com"
+ },
+ {
+ "name": "Tubi TV",
+ "url": "https://tubitv.com"
+ },
+ {
+ "name": "Tunefind",
+ "url": "https://tunefind.com"
+ },
+ {
+ "name": "TuneMyMusic",
+ "url": "https://tunemymusic.com"
+ },
+ {
+ "name": "Tweepsmap",
+ "url": "https://fedica.com"
+ },
+ {
+ "name": "Two Peas and Their Pod",
+ "url": "https://twopeasandtheirpod.com"
+ },
+ {
+ "name": "Typatone",
+ "url": "https://typatone.com"
+ },
+ {
+ "name": "Under Glass",
+ "url": "https://underglass.io"
+ },
+ {
+ "name": "UniCorner",
+ "url": "https://unicorner.news"
+ },
+ {
+ "name": "Unita",
+ "url": "https://unita.co"
+ },
+ {
+ "name": "UnitConverters",
+ "url": "https://unitconverters.net"
+ },
+ {
+ "name": "Unreadit",
+ "url": "https://unreadit.com"
+ },
+ {
+ "name": "Unscreen",
+ "url": "https://unscreen.com"
+ },
+ {
+ "name": "UnTools ",
+ "url": "https://untools.co"
+ },
+ {
+ "name": "Upwork",
+ "url": "https://upwork.com"
+ },
+ {
+ "name": "UTF8 Icons",
+ "url": "https://utf8icons.com"
+ },
+ {
+ "name": "Vector Magic",
+ "url": "https://vectormagic.com"
+ },
+ {
+ "name": "Virtual Vacation",
+ "url": "https://virtualvacation.us"
+ },
+ {
+ "name": "Virtual Vocations",
+ "url": "https://virtualvocations.com"
+ },
+ {
+ "name": "Visiwig",
+ "url": "https://visiwig.com"
+ },
+ {
+ "name": "Visual CV",
+ "url": "https://visualcv.com"
+ },
+ {
+ "name": "Vocus.io",
+ "url": "https://vocus.io"
+ },
+ {
+ "name": "Voscreen",
+ "url": "https://voscreen.com"
+ },
+ {
+ "name": "Wanderprep",
+ "url": "https://wanderprep.com"
+ },
+ {
+ "name": "Warmshowers",
+ "url": "https:/warmshowers.org"
+ },
+ {
+ "name": "Watch Documentaries",
+ "url": "https://watchdocumentaries.com"
+ },
+ {
+ "name": "We Work Remotely",
+ "url": "https://weworkremotely.com"
+ },
+ {
+ "name": "Web2PDFConvert",
+ "url": "https://web2pdfconvert.com"
+ },
+ {
+ "name": "Welcome to My Garden",
+ "url": "https://welcometomygarden.org"
+ },
+ {
+ "name": "When2meet ",
+ "url": "https://when2meet.com"
+ },
+ {
+ "name": "Where's George",
+ "url": "https://wheresgeorge.com"
+ },
+ {
+ "name": "Where's Willy",
+ "url": "https://whereswilly.com"
+ },
+ {
+ "name": "WikiHow",
+ "url": "https://wikihow.com"
+ },
+ {
+ "name": "Windy",
+ "url": "https://www.windy.com"
+ },
+ {
+ "name": "WonderHowTo",
+ "url": "https://wonderhowto.com"
+ },
+ {
+ "name": "Working Nomads",
+ "url": "https://workingnomads.com"
+ },
+ {
+ "name": "Wormhole",
+ "url": "https://wormhole.app"
+ },
+ {
+ "name": "Y Combinator Jobs",
+ "url": "https://ycombinator.com"
+ },
+ {
+ "name": "Yes Promo",
+ "url": "https://yespromo.me"
+ },
+ {
+ "name": "YouGlish",
+ "url": "https://youglish.com"
+ },
+ {
+ "name": "Zamzar",
+ "url": "https://zamzar.com"
+ },
+ {
+ "name": "Zippyshare",
+ "url": "https://zippyshare.com"
+ },
+ {
+ "name": "Zoom Earth",
+ "url": "https://zoom.earth"
+ },
+ {
+ "name": "Zoom.it",
+ "url": "https://zoom.it"
+ }
+]
diff --git a/Server/utils/messages.js b/Server/utils/messages.js
index 53a8f689f..e67e4e7e7 100644
--- a/Server/utils/messages.js
+++ b/Server/utils/messages.js
@@ -83,6 +83,7 @@ const successMessages = {
MONITOR_DELETE: "Monitor deleted successfully",
MONITOR_EDIT: "Monitor edited successfully",
MONITOR_CERTIFICATE: "Got monitor certificate successfully",
+ MONITOR_DEMO_ADDED: "Successfully added demo monitors",
//Job Queue
JOB_QUEUE_DELETE_JOB: "Job removed successfully",
diff --git a/Server/utils/utils.js b/Server/utils/utils.js
index 934c99492..4331a4610 100644
--- a/Server/utils/utils.js
+++ b/Server/utils/utils.js
@@ -16,6 +16,18 @@ const ParseBoolean = (value) => {
}
};
+const getTokenFromHeaders = (headers) => {
+ const authorizationHeader = headers.authorization;
+ if (!authorizationHeader) throw new Error("No auth headers");
+
+ const parts = authorizationHeader.split(" ");
+ if (parts.length !== 2 || parts[0] !== "Bearer")
+ throw new Error("Invalid auth headers");
+
+ return parts[1];
+};
+
module.exports = {
ParseBoolean,
+ getTokenFromHeaders,
};