├── client
├── public
│ ├── _redirects
│ ├── CTA.png
│ ├── hero.png
│ ├── avatar.png
│ ├── favicon.ico
│ ├── logo192.png
│ ├── logo512.png
│ ├── logos
│ │ ├── 3M.png
│ │ ├── AIG.png
│ │ ├── AMD.png
│ │ ├── Box.png
│ │ ├── Dow.png
│ │ ├── HCA.png
│ │ ├── HP.png
│ │ ├── IBM.png
│ │ ├── TD.png
│ │ ├── TJX.png
│ │ ├── X.png
│ │ ├── Adobe.png
│ │ ├── Apple.png
│ │ ├── Arrow.png
│ │ ├── Asana.png
│ │ ├── Bolt.png
│ │ ├── Brex.png
│ │ ├── Canva.png
│ │ ├── Cigna.png
│ │ ├── Cisco.png
│ │ ├── Delta.png
│ │ ├── Ebay.png
│ │ ├── Etsy.png
│ │ ├── FedEx.png
│ │ ├── Figma.png
│ │ ├── Glean.png
│ │ ├── Hulu.png
│ │ ├── Intel.png
│ │ ├── Kayak.png
│ │ ├── Lyft.png
│ │ ├── Mako.png
│ │ ├── Merck.png
│ │ ├── Meta.png
│ │ ├── NASA.png
│ │ ├── Nike.png
│ │ ├── Nucor.png
│ │ ├── Nuro.png
│ │ ├── Okta.png
│ │ ├── Pepsi.png
│ │ ├── Plaid.png
│ │ ├── Quora.png
│ │ ├── Ramp.png
│ │ ├── Slack.png
│ │ ├── Snap.png
│ │ ├── Sysco.png
│ │ ├── TIAA.png
│ │ ├── Tesla.png
│ │ ├── Uber.png
│ │ ├── Visa.png
│ │ ├── Waymo.png
│ │ ├── Wish.png
│ │ ├── Yelp.png
│ │ ├── Yext.png
│ │ ├── Zoom.png
│ │ ├── AbbVie.png
│ │ ├── Addepar.png
│ │ ├── Affirm.png
│ │ ├── Airbnb.png
│ │ ├── Airtable.png
│ │ ├── Allstate.png
│ │ ├── Amazon.png
│ │ ├── Anduril.png
│ │ ├── Autodesk.png
│ │ ├── Barclays.png
│ │ ├── Best_Buy.png
│ │ ├── Boeing.png
│ │ ├── CarMax.png
│ │ ├── Citadel.png
│ │ ├── Cohere.png
│ │ ├── Coinbase.png
│ │ ├── Cruise.png
│ │ ├── Datadog.png
│ │ ├── Deepmind.png
│ │ ├── Discord.png
│ │ ├── Disney.png
│ │ ├── Docusign.png
│ │ ├── DoorDash.png
│ │ ├── Dropbox.png
│ │ ├── Duolingo.png
│ │ ├── Elastic.png
│ │ ├── Expedia.png
│ │ ├── Fidelity.png
│ │ ├── Flexport.png
│ │ ├── Fox_News.png
│ │ ├── GitHub.png
│ │ ├── Google.png
│ │ ├── GrubHub.png
│ │ ├── HubSpot.png
│ │ ├── Humana.png
│ │ ├── Indeed.png
│ │ ├── Intuit.png
│ │ ├── Kelloggs.png
│ │ ├── Lennar.png
│ │ ├── Linkedin.png
│ │ ├── Macy's.png
│ │ ├── MetLife.png
│ │ ├── Micron.png
│ │ ├── MongoDB.png
│ │ ├── Netflix.png
│ │ ├── Nextdoor.png
│ │ ├── Notion.png
│ │ ├── Nutanix.png
│ │ ├── Nvidia.png
│ │ ├── OpenAI.png
│ │ ├── Optiver.png
│ │ ├── Oracle.png
│ │ ├── Palantir.png
│ │ ├── PayPal.png
│ │ ├── Peloton.png
│ │ ├── Pintrest.png
│ │ ├── Publix.png
│ │ ├── Qualcomm.png
│ │ ├── Raytheon.png
│ │ ├── Red_Hat.png
│ │ ├── Reddit.png
│ │ ├── Redfin.png
│ │ ├── Retool.png
│ │ ├── Rippling.png
│ │ ├── Roblox.png
│ │ ├── Samsara.png
│ │ ├── Samsung.png
│ │ ├── Scale_AI.png
│ │ ├── Shopify.png
│ │ ├── SpaceX.png
│ │ ├── Spectrum.png
│ │ ├── Splunk.png
│ │ ├── Spotify.png
│ │ ├── Square.png
│ │ ├── StoneX.png
│ │ ├── Tableau.png
│ │ ├── Tanium.png
│ │ ├── TikTok.png
│ │ ├── Twilio.png
│ │ ├── Twitch.png
│ │ ├── US_Foods.png
│ │ ├── VMware.png
│ │ ├── Verily.png
│ │ ├── Walmart.png
│ │ ├── Wayfair.png
│ │ ├── Workday.png
│ │ ├── Zillow.png
│ │ ├── Albertsons.png
│ │ ├── Anthropic.png
│ │ ├── Atlassian.png
│ │ ├── Blackrock.png
│ │ ├── Bloomberg.png
│ │ ├── ByteDance.png
│ │ ├── Cloudflare.png
│ │ ├── Coca_Cola.png
│ │ ├── D.E._Shaw.png
│ │ ├── Databricks.png
│ │ ├── Five_Rings.png
│ │ ├── Honeywell.png
│ │ ├── Instacart.png
│ │ ├── John_Deere.png
│ │ ├── MasterCard.png
│ │ ├── McDonalds.png
│ │ ├── Microsoft.png
│ │ ├── Nationwide.png
│ │ ├── Neuralink.png
│ │ ├── Occidental.png
│ │ ├── PBF_Energy.png
│ │ ├── Postmates.png
│ │ ├── Prudential.png
│ │ ├── Qualtrics.png
│ │ ├── Riot_Games.png
│ │ ├── Robinhood.png
│ │ ├── Salesforce.png
│ │ ├── ServiceNow.png
│ │ ├── Snowflake.png
│ │ ├── Starbucks.png
│ │ ├── State_Farm.png
│ │ ├── TD_Synnex.png
│ │ ├── Travelers.png
│ │ ├── Two_Sigma.png
│ │ ├── Akuna_Capital.png
│ │ ├── Blue_Origin.png
│ │ ├── Capital_One.png
│ │ ├── Caterpillar.png
│ │ ├── Dollar_Tree.png
│ │ ├── Epic_Systems.png
│ │ ├── Flow_Traders.png
│ │ ├── Freddie_Mac.png
│ │ ├── General_Mills.png
│ │ ├── Goldman_Sachs.png
│ │ ├── Hugging_Face.png
│ │ ├── IMC_Trading.png
│ │ ├── J.P._Morgan.png
│ │ ├── Jane_Street.png
│ │ ├── Jump_Trading.png
│ │ ├── New_York_Life.png
│ │ ├── Progressive.png
│ │ ├── Radix_Trading.png
│ │ ├── Tyson_Foods.png
│ │ ├── Union_Pacific.png
│ │ ├── UserTesting.png
│ │ ├── Warner_Bros.png
│ │ ├── Wells_Fargo.png
│ │ ├── Charles_Schwab.png
│ │ ├── ConocoPhillips.png
│ │ ├── Dollar_General.png
│ │ ├── Energy_Transfer.png
│ │ ├── General_Motors.png
│ │ ├── Liberty_Mutual.png
│ │ ├── Lockheed_Martin.png
│ │ ├── Morgan_Stanley.png
│ │ ├── Tower_Research.png
│ │ ├── United_Airlines.png
│ │ ├── Virtu_Financial.png
│ │ ├── Abbot_Laboratories.png
│ │ ├── American_Airlines.png
│ │ ├── American_Express.png
│ │ ├── Berkshire_Hathaway.png
│ │ ├── General_Dynamics.png
│ │ ├── General_Electric.png
│ │ ├── Johnson_&_Johnson.png
│ │ ├── Northrop_Grumman.png
│ │ ├── Performance_Food.png
│ │ ├── Proctor_&_Gamble.png
│ │ ├── Wolverine_Trading.png
│ │ ├── Bristol_Myers_Squibb.png
│ │ ├── Hudson_River_Trading.png
│ │ ├── Northwestern_Mutual.png
│ │ ├── Renaissance_Technologies.png
│ │ ├── Thermo_Fisher_Scientific.png
│ │ └── Yelp
│ ├── pipelines.png
│ ├── preview.png
│ ├── manifest.json
│ └── index.html
├── .prettierignore
├── src
│ ├── static
│ │ └── ratings
│ │ │ ├── demon.png
│ │ │ ├── frown.png
│ │ │ ├── neutral.png
│ │ │ ├── smiley.png
│ │ │ └── BigSmiley.png
│ ├── util
│ │ ├── linkedinUtils.js
│ │ ├── mongoUtils.js
│ │ ├── generalUtils.js
│ │ ├── apiRoutes.js
│ │ ├── companyUtils.js
│ │ ├── tokenUtils.js
│ │ └── fetchUtils.js
│ ├── components
│ │ ├── ConditionalLink.js
│ │ ├── Footer.js
│ │ ├── ProfilePicture.js
│ │ ├── landing
│ │ │ ├── Hero.js
│ │ │ ├── CTAButton.js
│ │ │ ├── Marquee.js
│ │ │ ├── CTA.js
│ │ │ ├── About.js
│ │ │ └── People.js
│ │ ├── Error404.js
│ │ ├── CompanyCard.js
│ │ ├── TitleQuerySearchInput.js
│ │ ├── DatePicker.js
│ │ ├── QuerySearchInput.js
│ │ ├── ExperienceQuerySearchInput.js
│ │ └── PipelineDisplay.js
│ ├── hooks
│ │ ├── useAuthContext.js
│ │ ├── useAdminContext.js
│ │ ├── useEarlyAccess.js
│ │ ├── usePatchJson.js
│ │ └── useValidateExperience.js
│ ├── pages
│ │ ├── Loading.js
│ │ ├── Home.js
│ │ ├── (admin)
│ │ │ ├── Admin.js
│ │ │ └── AdminDashboard.js
│ │ ├── Code.js
│ │ └── Newsletter.js
│ ├── index.css
│ ├── index.js
│ ├── context
│ │ ├── EarlyAccessContext.js
│ │ ├── AdminContext.js
│ │ └── AuthContext.js
│ ├── data
│ │ └── index.js
│ ├── App.css
│ └── App.js
├── .env.example
├── .prettierrc
├── tailwind.config.js
├── .eslintrc.json
└── package.json
├── preview.png
├── .vscode
└── settings.json
├── server
├── routes
│ ├── earlyAccess.js
│ ├── mongodbId.js
│ ├── admin.js
│ ├── imageModeration.js
│ ├── pfps.js
│ ├── school.js
│ ├── auth.js
│ ├── token.js
│ ├── profiles.js
│ ├── offers.js
│ ├── emails.js
│ └── companies.js
├── models
│ ├── emailModel.js
│ ├── offerModel.js
│ ├── experienceModel.js
│ ├── schoolModel.js
│ ├── companyModel.js
│ ├── userModel.js
│ ├── profileModel.js
│ └── adminModel.js
├── .env.example
├── controllers
│ ├── mongodbIdController.js
│ ├── earlyAccessController.js
│ ├── adminController.js
│ ├── imageModerationController.js
│ ├── pfpController.js
│ └── schoolController.js
├── utils
│ ├── apiRoutes.js
│ └── generalUtils.js
├── package.json
├── middleware
│ ├── token.js
│ ├── admin.js
│ ├── user.js
│ └── profile.js
├── app.test.js
├── emails
│ └── welcome.js
└── index.js
├── .gitignore
├── LICENSE
├── CONTRIBUTING.md
└── CODE_OF_CONDUCT.md
/client/public/_redirects:
--------------------------------------------------------------------------------
1 | /* /index.html 200
--------------------------------------------------------------------------------
/client/.prettierignore:
--------------------------------------------------------------------------------
1 | src/components/PipelineCard.js
--------------------------------------------------------------------------------
/preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/preview.png
--------------------------------------------------------------------------------
/client/public/CTA.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/CTA.png
--------------------------------------------------------------------------------
/client/public/hero.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/hero.png
--------------------------------------------------------------------------------
/client/public/avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/avatar.png
--------------------------------------------------------------------------------
/client/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/favicon.ico
--------------------------------------------------------------------------------
/client/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logo192.png
--------------------------------------------------------------------------------
/client/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logo512.png
--------------------------------------------------------------------------------
/client/public/logos/3M.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/3M.png
--------------------------------------------------------------------------------
/client/public/logos/AIG.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/AIG.png
--------------------------------------------------------------------------------
/client/public/logos/AMD.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/AMD.png
--------------------------------------------------------------------------------
/client/public/logos/Box.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Box.png
--------------------------------------------------------------------------------
/client/public/logos/Dow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Dow.png
--------------------------------------------------------------------------------
/client/public/logos/HCA.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/HCA.png
--------------------------------------------------------------------------------
/client/public/logos/HP.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/HP.png
--------------------------------------------------------------------------------
/client/public/logos/IBM.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/IBM.png
--------------------------------------------------------------------------------
/client/public/logos/TD.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/TD.png
--------------------------------------------------------------------------------
/client/public/logos/TJX.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/TJX.png
--------------------------------------------------------------------------------
/client/public/logos/X.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/X.png
--------------------------------------------------------------------------------
/client/public/pipelines.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/pipelines.png
--------------------------------------------------------------------------------
/client/public/preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/preview.png
--------------------------------------------------------------------------------
/client/public/logos/Adobe.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Adobe.png
--------------------------------------------------------------------------------
/client/public/logos/Apple.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Apple.png
--------------------------------------------------------------------------------
/client/public/logos/Arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Arrow.png
--------------------------------------------------------------------------------
/client/public/logos/Asana.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Asana.png
--------------------------------------------------------------------------------
/client/public/logos/Bolt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Bolt.png
--------------------------------------------------------------------------------
/client/public/logos/Brex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Brex.png
--------------------------------------------------------------------------------
/client/public/logos/Canva.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Canva.png
--------------------------------------------------------------------------------
/client/public/logos/Cigna.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Cigna.png
--------------------------------------------------------------------------------
/client/public/logos/Cisco.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Cisco.png
--------------------------------------------------------------------------------
/client/public/logos/Delta.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Delta.png
--------------------------------------------------------------------------------
/client/public/logos/Ebay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Ebay.png
--------------------------------------------------------------------------------
/client/public/logos/Etsy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Etsy.png
--------------------------------------------------------------------------------
/client/public/logos/FedEx.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/FedEx.png
--------------------------------------------------------------------------------
/client/public/logos/Figma.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Figma.png
--------------------------------------------------------------------------------
/client/public/logos/Glean.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Glean.png
--------------------------------------------------------------------------------
/client/public/logos/Hulu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Hulu.png
--------------------------------------------------------------------------------
/client/public/logos/Intel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Intel.png
--------------------------------------------------------------------------------
/client/public/logos/Kayak.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Kayak.png
--------------------------------------------------------------------------------
/client/public/logos/Lyft.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Lyft.png
--------------------------------------------------------------------------------
/client/public/logos/Mako.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Mako.png
--------------------------------------------------------------------------------
/client/public/logos/Merck.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Merck.png
--------------------------------------------------------------------------------
/client/public/logos/Meta.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Meta.png
--------------------------------------------------------------------------------
/client/public/logos/NASA.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/NASA.png
--------------------------------------------------------------------------------
/client/public/logos/Nike.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Nike.png
--------------------------------------------------------------------------------
/client/public/logos/Nucor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Nucor.png
--------------------------------------------------------------------------------
/client/public/logos/Nuro.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Nuro.png
--------------------------------------------------------------------------------
/client/public/logos/Okta.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Okta.png
--------------------------------------------------------------------------------
/client/public/logos/Pepsi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Pepsi.png
--------------------------------------------------------------------------------
/client/public/logos/Plaid.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Plaid.png
--------------------------------------------------------------------------------
/client/public/logos/Quora.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Quora.png
--------------------------------------------------------------------------------
/client/public/logos/Ramp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Ramp.png
--------------------------------------------------------------------------------
/client/public/logos/Slack.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Slack.png
--------------------------------------------------------------------------------
/client/public/logos/Snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Snap.png
--------------------------------------------------------------------------------
/client/public/logos/Sysco.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Sysco.png
--------------------------------------------------------------------------------
/client/public/logos/TIAA.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/TIAA.png
--------------------------------------------------------------------------------
/client/public/logos/Tesla.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Tesla.png
--------------------------------------------------------------------------------
/client/public/logos/Uber.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Uber.png
--------------------------------------------------------------------------------
/client/public/logos/Visa.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Visa.png
--------------------------------------------------------------------------------
/client/public/logos/Waymo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Waymo.png
--------------------------------------------------------------------------------
/client/public/logos/Wish.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Wish.png
--------------------------------------------------------------------------------
/client/public/logos/Yelp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Yelp.png
--------------------------------------------------------------------------------
/client/public/logos/Yext.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Yext.png
--------------------------------------------------------------------------------
/client/public/logos/Zoom.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Zoom.png
--------------------------------------------------------------------------------
/client/public/logos/AbbVie.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/AbbVie.png
--------------------------------------------------------------------------------
/client/public/logos/Addepar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Addepar.png
--------------------------------------------------------------------------------
/client/public/logos/Affirm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Affirm.png
--------------------------------------------------------------------------------
/client/public/logos/Airbnb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Airbnb.png
--------------------------------------------------------------------------------
/client/public/logos/Airtable.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Airtable.png
--------------------------------------------------------------------------------
/client/public/logos/Allstate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Allstate.png
--------------------------------------------------------------------------------
/client/public/logos/Amazon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Amazon.png
--------------------------------------------------------------------------------
/client/public/logos/Anduril.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Anduril.png
--------------------------------------------------------------------------------
/client/public/logos/Autodesk.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Autodesk.png
--------------------------------------------------------------------------------
/client/public/logos/Barclays.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Barclays.png
--------------------------------------------------------------------------------
/client/public/logos/Best_Buy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Best_Buy.png
--------------------------------------------------------------------------------
/client/public/logos/Boeing.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Boeing.png
--------------------------------------------------------------------------------
/client/public/logos/CarMax.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/CarMax.png
--------------------------------------------------------------------------------
/client/public/logos/Citadel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Citadel.png
--------------------------------------------------------------------------------
/client/public/logos/Cohere.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Cohere.png
--------------------------------------------------------------------------------
/client/public/logos/Coinbase.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Coinbase.png
--------------------------------------------------------------------------------
/client/public/logos/Cruise.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Cruise.png
--------------------------------------------------------------------------------
/client/public/logos/Datadog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Datadog.png
--------------------------------------------------------------------------------
/client/public/logos/Deepmind.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Deepmind.png
--------------------------------------------------------------------------------
/client/public/logos/Discord.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Discord.png
--------------------------------------------------------------------------------
/client/public/logos/Disney.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Disney.png
--------------------------------------------------------------------------------
/client/public/logos/Docusign.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Docusign.png
--------------------------------------------------------------------------------
/client/public/logos/DoorDash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/DoorDash.png
--------------------------------------------------------------------------------
/client/public/logos/Dropbox.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Dropbox.png
--------------------------------------------------------------------------------
/client/public/logos/Duolingo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Duolingo.png
--------------------------------------------------------------------------------
/client/public/logos/Elastic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Elastic.png
--------------------------------------------------------------------------------
/client/public/logos/Expedia.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Expedia.png
--------------------------------------------------------------------------------
/client/public/logos/Fidelity.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Fidelity.png
--------------------------------------------------------------------------------
/client/public/logos/Flexport.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Flexport.png
--------------------------------------------------------------------------------
/client/public/logos/Fox_News.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Fox_News.png
--------------------------------------------------------------------------------
/client/public/logos/GitHub.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/GitHub.png
--------------------------------------------------------------------------------
/client/public/logos/Google.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Google.png
--------------------------------------------------------------------------------
/client/public/logos/GrubHub.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/GrubHub.png
--------------------------------------------------------------------------------
/client/public/logos/HubSpot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/HubSpot.png
--------------------------------------------------------------------------------
/client/public/logos/Humana.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Humana.png
--------------------------------------------------------------------------------
/client/public/logos/Indeed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Indeed.png
--------------------------------------------------------------------------------
/client/public/logos/Intuit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Intuit.png
--------------------------------------------------------------------------------
/client/public/logos/Kelloggs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Kelloggs.png
--------------------------------------------------------------------------------
/client/public/logos/Lennar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Lennar.png
--------------------------------------------------------------------------------
/client/public/logos/Linkedin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Linkedin.png
--------------------------------------------------------------------------------
/client/public/logos/Macy's.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Macy's.png
--------------------------------------------------------------------------------
/client/public/logos/MetLife.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/MetLife.png
--------------------------------------------------------------------------------
/client/public/logos/Micron.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Micron.png
--------------------------------------------------------------------------------
/client/public/logos/MongoDB.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/MongoDB.png
--------------------------------------------------------------------------------
/client/public/logos/Netflix.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Netflix.png
--------------------------------------------------------------------------------
/client/public/logos/Nextdoor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Nextdoor.png
--------------------------------------------------------------------------------
/client/public/logos/Notion.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Notion.png
--------------------------------------------------------------------------------
/client/public/logos/Nutanix.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Nutanix.png
--------------------------------------------------------------------------------
/client/public/logos/Nvidia.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Nvidia.png
--------------------------------------------------------------------------------
/client/public/logos/OpenAI.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/OpenAI.png
--------------------------------------------------------------------------------
/client/public/logos/Optiver.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Optiver.png
--------------------------------------------------------------------------------
/client/public/logos/Oracle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Oracle.png
--------------------------------------------------------------------------------
/client/public/logos/Palantir.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Palantir.png
--------------------------------------------------------------------------------
/client/public/logos/PayPal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/PayPal.png
--------------------------------------------------------------------------------
/client/public/logos/Peloton.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Peloton.png
--------------------------------------------------------------------------------
/client/public/logos/Pintrest.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Pintrest.png
--------------------------------------------------------------------------------
/client/public/logos/Publix.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Publix.png
--------------------------------------------------------------------------------
/client/public/logos/Qualcomm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Qualcomm.png
--------------------------------------------------------------------------------
/client/public/logos/Raytheon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Raytheon.png
--------------------------------------------------------------------------------
/client/public/logos/Red_Hat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Red_Hat.png
--------------------------------------------------------------------------------
/client/public/logos/Reddit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Reddit.png
--------------------------------------------------------------------------------
/client/public/logos/Redfin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Redfin.png
--------------------------------------------------------------------------------
/client/public/logos/Retool.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Retool.png
--------------------------------------------------------------------------------
/client/public/logos/Rippling.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Rippling.png
--------------------------------------------------------------------------------
/client/public/logos/Roblox.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Roblox.png
--------------------------------------------------------------------------------
/client/public/logos/Samsara.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Samsara.png
--------------------------------------------------------------------------------
/client/public/logos/Samsung.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Samsung.png
--------------------------------------------------------------------------------
/client/public/logos/Scale_AI.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Scale_AI.png
--------------------------------------------------------------------------------
/client/public/logos/Shopify.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Shopify.png
--------------------------------------------------------------------------------
/client/public/logos/SpaceX.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/SpaceX.png
--------------------------------------------------------------------------------
/client/public/logos/Spectrum.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Spectrum.png
--------------------------------------------------------------------------------
/client/public/logos/Splunk.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Splunk.png
--------------------------------------------------------------------------------
/client/public/logos/Spotify.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Spotify.png
--------------------------------------------------------------------------------
/client/public/logos/Square.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Square.png
--------------------------------------------------------------------------------
/client/public/logos/StoneX.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/StoneX.png
--------------------------------------------------------------------------------
/client/public/logos/Tableau.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Tableau.png
--------------------------------------------------------------------------------
/client/public/logos/Tanium.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Tanium.png
--------------------------------------------------------------------------------
/client/public/logos/TikTok.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/TikTok.png
--------------------------------------------------------------------------------
/client/public/logos/Twilio.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Twilio.png
--------------------------------------------------------------------------------
/client/public/logos/Twitch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Twitch.png
--------------------------------------------------------------------------------
/client/public/logos/US_Foods.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/US_Foods.png
--------------------------------------------------------------------------------
/client/public/logos/VMware.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/VMware.png
--------------------------------------------------------------------------------
/client/public/logos/Verily.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Verily.png
--------------------------------------------------------------------------------
/client/public/logos/Walmart.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Walmart.png
--------------------------------------------------------------------------------
/client/public/logos/Wayfair.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Wayfair.png
--------------------------------------------------------------------------------
/client/public/logos/Workday.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Workday.png
--------------------------------------------------------------------------------
/client/public/logos/Zillow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Zillow.png
--------------------------------------------------------------------------------
/client/public/logos/Albertsons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Albertsons.png
--------------------------------------------------------------------------------
/client/public/logos/Anthropic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Anthropic.png
--------------------------------------------------------------------------------
/client/public/logos/Atlassian.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Atlassian.png
--------------------------------------------------------------------------------
/client/public/logos/Blackrock.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Blackrock.png
--------------------------------------------------------------------------------
/client/public/logos/Bloomberg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Bloomberg.png
--------------------------------------------------------------------------------
/client/public/logos/ByteDance.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/ByteDance.png
--------------------------------------------------------------------------------
/client/public/logos/Cloudflare.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Cloudflare.png
--------------------------------------------------------------------------------
/client/public/logos/Coca_Cola.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Coca_Cola.png
--------------------------------------------------------------------------------
/client/public/logos/D.E._Shaw.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/D.E._Shaw.png
--------------------------------------------------------------------------------
/client/public/logos/Databricks.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Databricks.png
--------------------------------------------------------------------------------
/client/public/logos/Five_Rings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Five_Rings.png
--------------------------------------------------------------------------------
/client/public/logos/Honeywell.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Honeywell.png
--------------------------------------------------------------------------------
/client/public/logos/Instacart.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Instacart.png
--------------------------------------------------------------------------------
/client/public/logos/John_Deere.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/John_Deere.png
--------------------------------------------------------------------------------
/client/public/logos/MasterCard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/MasterCard.png
--------------------------------------------------------------------------------
/client/public/logos/McDonalds.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/McDonalds.png
--------------------------------------------------------------------------------
/client/public/logos/Microsoft.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Microsoft.png
--------------------------------------------------------------------------------
/client/public/logos/Nationwide.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Nationwide.png
--------------------------------------------------------------------------------
/client/public/logos/Neuralink.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Neuralink.png
--------------------------------------------------------------------------------
/client/public/logos/Occidental.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Occidental.png
--------------------------------------------------------------------------------
/client/public/logos/PBF_Energy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/PBF_Energy.png
--------------------------------------------------------------------------------
/client/public/logos/Postmates.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Postmates.png
--------------------------------------------------------------------------------
/client/public/logos/Prudential.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Prudential.png
--------------------------------------------------------------------------------
/client/public/logos/Qualtrics.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Qualtrics.png
--------------------------------------------------------------------------------
/client/public/logos/Riot_Games.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Riot_Games.png
--------------------------------------------------------------------------------
/client/public/logos/Robinhood.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Robinhood.png
--------------------------------------------------------------------------------
/client/public/logos/Salesforce.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Salesforce.png
--------------------------------------------------------------------------------
/client/public/logos/ServiceNow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/ServiceNow.png
--------------------------------------------------------------------------------
/client/public/logos/Snowflake.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Snowflake.png
--------------------------------------------------------------------------------
/client/public/logos/Starbucks.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Starbucks.png
--------------------------------------------------------------------------------
/client/public/logos/State_Farm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/State_Farm.png
--------------------------------------------------------------------------------
/client/public/logos/TD_Synnex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/TD_Synnex.png
--------------------------------------------------------------------------------
/client/public/logos/Travelers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Travelers.png
--------------------------------------------------------------------------------
/client/public/logos/Two_Sigma.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Two_Sigma.png
--------------------------------------------------------------------------------
/client/public/logos/Akuna_Capital.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Akuna_Capital.png
--------------------------------------------------------------------------------
/client/public/logos/Blue_Origin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Blue_Origin.png
--------------------------------------------------------------------------------
/client/public/logos/Capital_One.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Capital_One.png
--------------------------------------------------------------------------------
/client/public/logos/Caterpillar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Caterpillar.png
--------------------------------------------------------------------------------
/client/public/logos/Dollar_Tree.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Dollar_Tree.png
--------------------------------------------------------------------------------
/client/public/logos/Epic_Systems.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Epic_Systems.png
--------------------------------------------------------------------------------
/client/public/logos/Flow_Traders.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Flow_Traders.png
--------------------------------------------------------------------------------
/client/public/logos/Freddie_Mac.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Freddie_Mac.png
--------------------------------------------------------------------------------
/client/public/logos/General_Mills.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/General_Mills.png
--------------------------------------------------------------------------------
/client/public/logos/Goldman_Sachs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Goldman_Sachs.png
--------------------------------------------------------------------------------
/client/public/logos/Hugging_Face.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Hugging_Face.png
--------------------------------------------------------------------------------
/client/public/logos/IMC_Trading.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/IMC_Trading.png
--------------------------------------------------------------------------------
/client/public/logos/J.P._Morgan.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/J.P._Morgan.png
--------------------------------------------------------------------------------
/client/public/logos/Jane_Street.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Jane_Street.png
--------------------------------------------------------------------------------
/client/public/logos/Jump_Trading.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Jump_Trading.png
--------------------------------------------------------------------------------
/client/public/logos/New_York_Life.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/New_York_Life.png
--------------------------------------------------------------------------------
/client/public/logos/Progressive.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Progressive.png
--------------------------------------------------------------------------------
/client/public/logos/Radix_Trading.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Radix_Trading.png
--------------------------------------------------------------------------------
/client/public/logos/Tyson_Foods.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Tyson_Foods.png
--------------------------------------------------------------------------------
/client/public/logos/Union_Pacific.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Union_Pacific.png
--------------------------------------------------------------------------------
/client/public/logos/UserTesting.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/UserTesting.png
--------------------------------------------------------------------------------
/client/public/logos/Warner_Bros.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Warner_Bros.png
--------------------------------------------------------------------------------
/client/public/logos/Wells_Fargo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Wells_Fargo.png
--------------------------------------------------------------------------------
/client/src/static/ratings/demon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/src/static/ratings/demon.png
--------------------------------------------------------------------------------
/client/src/static/ratings/frown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/src/static/ratings/frown.png
--------------------------------------------------------------------------------
/client/src/static/ratings/neutral.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/src/static/ratings/neutral.png
--------------------------------------------------------------------------------
/client/src/static/ratings/smiley.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/src/static/ratings/smiley.png
--------------------------------------------------------------------------------
/client/public/logos/Charles_Schwab.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Charles_Schwab.png
--------------------------------------------------------------------------------
/client/public/logos/ConocoPhillips.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/ConocoPhillips.png
--------------------------------------------------------------------------------
/client/public/logos/Dollar_General.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Dollar_General.png
--------------------------------------------------------------------------------
/client/public/logos/Energy_Transfer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Energy_Transfer.png
--------------------------------------------------------------------------------
/client/public/logos/General_Motors.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/General_Motors.png
--------------------------------------------------------------------------------
/client/public/logos/Liberty_Mutual.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Liberty_Mutual.png
--------------------------------------------------------------------------------
/client/public/logos/Lockheed_Martin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Lockheed_Martin.png
--------------------------------------------------------------------------------
/client/public/logos/Morgan_Stanley.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Morgan_Stanley.png
--------------------------------------------------------------------------------
/client/public/logos/Tower_Research.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Tower_Research.png
--------------------------------------------------------------------------------
/client/public/logos/United_Airlines.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/United_Airlines.png
--------------------------------------------------------------------------------
/client/public/logos/Virtu_Financial.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Virtu_Financial.png
--------------------------------------------------------------------------------
/client/src/static/ratings/BigSmiley.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/src/static/ratings/BigSmiley.png
--------------------------------------------------------------------------------
/client/.env.example:
--------------------------------------------------------------------------------
1 | REACT_APP_NODE_ENV=
2 |
3 | REACT_APP_API_URL=
4 |
5 | REACT_APP_LINKEDIN_CLIENT_ID=
6 | REACT_APP_LINKEDIN_SCOPE=
7 |
--------------------------------------------------------------------------------
/client/public/logos/Abbot_Laboratories.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Abbot_Laboratories.png
--------------------------------------------------------------------------------
/client/public/logos/American_Airlines.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/American_Airlines.png
--------------------------------------------------------------------------------
/client/public/logos/American_Express.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/American_Express.png
--------------------------------------------------------------------------------
/client/public/logos/Berkshire_Hathaway.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Berkshire_Hathaway.png
--------------------------------------------------------------------------------
/client/public/logos/General_Dynamics.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/General_Dynamics.png
--------------------------------------------------------------------------------
/client/public/logos/General_Electric.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/General_Electric.png
--------------------------------------------------------------------------------
/client/public/logos/Johnson_&_Johnson.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Johnson_&_Johnson.png
--------------------------------------------------------------------------------
/client/public/logos/Northrop_Grumman.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Northrop_Grumman.png
--------------------------------------------------------------------------------
/client/public/logos/Performance_Food.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Performance_Food.png
--------------------------------------------------------------------------------
/client/public/logos/Proctor_&_Gamble.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Proctor_&_Gamble.png
--------------------------------------------------------------------------------
/client/public/logos/Wolverine_Trading.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Wolverine_Trading.png
--------------------------------------------------------------------------------
/client/public/logos/Bristol_Myers_Squibb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Bristol_Myers_Squibb.png
--------------------------------------------------------------------------------
/client/public/logos/Hudson_River_Trading.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Hudson_River_Trading.png
--------------------------------------------------------------------------------
/client/public/logos/Northwestern_Mutual.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Northwestern_Mutual.png
--------------------------------------------------------------------------------
/client/public/logos/Renaissance_Technologies.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Renaissance_Technologies.png
--------------------------------------------------------------------------------
/client/public/logos/Thermo_Fisher_Scientific.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pipelines-lol/pipelines/HEAD/client/public/logos/Thermo_Fisher_Scientific.png
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "prettier.insertPragma": false,
3 | "prettier.bracketSameLine": false,
4 | "editor.codeActionsOnSave": ["source.fixAll.eslint"],
5 | "editor.formatOnSave": true
6 | }
7 |
--------------------------------------------------------------------------------
/client/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "trailingComma": "es5",
3 | "tabWidth": 4,
4 | "semi": false,
5 | "singleQuote": true,
6 | "plugins": [
7 | "prettier-plugin-tailwindcss"
8 | ]
9 | }
--------------------------------------------------------------------------------
/client/src/util/linkedinUtils.js:
--------------------------------------------------------------------------------
1 | export const CLIENT_ID = process.env.REACT_APP_LINKEDIN_CLIENT_ID
2 | export const REDIRECT_URI = process.env.REACT_APP_LINKEDIN_REDIRECT_URI
3 | export const SCOPE = process.env.REACT_APP_LINKEDIN_SCOPE
4 |
--------------------------------------------------------------------------------
/server/routes/earlyAccess.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const { checkCode } = require("../controllers/earlyAccessController");
3 |
4 | const router = express.Router();
5 |
6 | // check code
7 | router.post("/check", checkCode);
8 |
9 | module.exports = router;
10 |
--------------------------------------------------------------------------------
/server/models/emailModel.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 |
3 | const Schema = mongoose.Schema;
4 |
5 | const emailSchema = new Schema(
6 | {
7 | email: String,
8 | },
9 | { timestamps: true }
10 | );
11 |
12 | module.exports = mongoose.model("Email", emailSchema);
13 |
--------------------------------------------------------------------------------
/server/routes/mongodbId.js:
--------------------------------------------------------------------------------
1 | const express = require('express')
2 | const {
3 | checkMongodbId
4 | } = require('../controllers/mongodbIdController')
5 |
6 | const router = express.Router()
7 |
8 | // GET a check of a single id
9 | router.get('/:id', checkMongodbId)
10 |
11 | module.exports = router;
--------------------------------------------------------------------------------
/client/src/components/ConditionalLink.js:
--------------------------------------------------------------------------------
1 | import { Link } from 'react-router-dom'
2 |
3 | export const ConditionalLink = ({ children, condition, ...props }) => {
4 | return !!condition && props.to ? (
5 | {children}
6 | ) : (
7 | <>{children}>
8 | )
9 | }
10 |
--------------------------------------------------------------------------------
/server/.env.example:
--------------------------------------------------------------------------------
1 | NODE_ENV=
2 | PORT=
3 | DB_CONNECT=
4 | JWT_SECRET=
5 |
6 | API_URL=
7 |
8 | BUCKET_NAME=
9 | BUCKET_REGION=
10 | AWS_ACCESS_KEY_ID=
11 | AWS_SECRET_ACCESS_KEY=
12 |
13 | LINKEDIN_CLIENT_ID=
14 | LINKEDIN_CLIENT_SECRET=
15 |
16 | RESEND_EMAIL=
17 | RESEND_API_KEY=
18 |
19 | EARLY_ACCESS_CODE=
--------------------------------------------------------------------------------
/server/routes/admin.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const { loginAdmin, verifyToken } = require("../controllers/adminController");
3 |
4 | const router = express.Router();
5 |
6 | // LOGIN user
7 | router.post("/login", loginAdmin);
8 |
9 | // VERIFY admin token
10 | router.post("/verify", verifyToken);
11 |
12 | module.exports = router;
13 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # npm
2 | node_modules
3 | package-lock.json
4 | *.log
5 | *.gz
6 |
7 | # Coveralls
8 | .nyc_output
9 | coverage
10 |
11 | # Environmental Vars
12 | .env
13 |
14 | # Development testing
15 | testing/
16 |
17 | # Benchmarking
18 | benchmarks/graphs
19 | build/
20 |
21 | # ignore additional files using core.excludesFile
22 | # https://git-scm.com/docs/gitignore
--------------------------------------------------------------------------------
/client/src/hooks/useAuthContext.js:
--------------------------------------------------------------------------------
1 | import { AuthContext } from '../context/AuthContext'
2 | import { useContext } from 'react'
3 |
4 | export const useAuthContext = () => {
5 | const context = useContext(AuthContext)
6 |
7 | if (!context) {
8 | throw Error('useAuthContext must be used inside an AuthContextProvider')
9 | }
10 |
11 | return context
12 | }
13 |
--------------------------------------------------------------------------------
/client/src/hooks/useAdminContext.js:
--------------------------------------------------------------------------------
1 | import { AdminContext } from '../context/AdminContext'
2 | import { useContext } from 'react'
3 |
4 | export const useAdmin = () => {
5 | const context = useContext(AdminContext)
6 |
7 | if (!context) {
8 | throw Error(
9 | 'useAdminContext must be used inside an AdminContextProvider'
10 | )
11 | }
12 |
13 | return context
14 | }
15 |
--------------------------------------------------------------------------------
/server/controllers/mongodbIdController.js:
--------------------------------------------------------------------------------
1 | const mongoose = require('mongoose')
2 |
3 | const checkMongodbId = async (req, res) => {
4 | const { id } = req.params
5 |
6 | if (!mongoose.Types.ObjectId.isValid(id)) {
7 | return res.status(200).json({ response: false })
8 | } else {
9 | return res.status(200).json({ response: true })
10 | }
11 | }
12 |
13 | module.exports = {
14 | checkMongodbId
15 | }
--------------------------------------------------------------------------------
/server/models/offerModel.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 | const Schema = mongoose.Schema;
3 |
4 | const OfferSchema = new Schema({
5 | companyId: { type: Schema.Types.ObjectId, ref: "Company" },
6 | companyName: String, // Store as lowercase in the database
7 | title: String,
8 | startDate: Date,
9 | endDate: Date,
10 | isIndefinite: Boolean,
11 | });
12 |
13 | module.exports = mongoose.model("Offer", OfferSchema);
14 |
--------------------------------------------------------------------------------
/client/src/hooks/useEarlyAccess.js:
--------------------------------------------------------------------------------
1 | import { EarlyAccessContext } from '../context/EarlyAccessContext'
2 | import { useContext } from 'react'
3 |
4 | export const useEarlyAccess = () => {
5 | const context = useContext(EarlyAccessContext)
6 |
7 | if (!context) {
8 | throw Error(
9 | 'useEarlyAccessContext must be used inside an EarlyAccessContextProvider'
10 | )
11 | }
12 |
13 | return context
14 | }
15 |
--------------------------------------------------------------------------------
/server/controllers/earlyAccessController.js:
--------------------------------------------------------------------------------
1 | const checkCode = async (req, res) => {
2 | const { code } = req.body;
3 |
4 | if (!code) {
5 | return res.status(400).json({ error: "No code provided." });
6 | }
7 | if (code !== process.env.EARLY_ACCESS_CODE) {
8 | return res.status(400).json({ error: "Incorrect code." });
9 | }
10 |
11 | res.status(200).json({ code });
12 | };
13 |
14 | module.exports = {
15 | checkCode,
16 | };
17 |
--------------------------------------------------------------------------------
/server/routes/imageModeration.js:
--------------------------------------------------------------------------------
1 | const express = require('express')
2 | const {
3 | recognizeImage
4 | } = require('../controllers/imageModerationController')
5 |
6 | const router = express.Router()
7 |
8 | const multer = require('multer')
9 |
10 | const storage = multer.memoryStorage()
11 | const upload = multer({ storage: storage })
12 |
13 | // POST a check of a single image
14 | router.post('/', upload.single('pfp'), recognizeImage)
15 |
16 | module.exports = router;
--------------------------------------------------------------------------------
/server/models/experienceModel.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 | const Schema = mongoose.Schema;
3 |
4 | const ExperienceSchema = new Schema({
5 | companyId: { type: Schema.Types.ObjectId, ref: "Company" },
6 | companyName: String, // Store as lowercase in the database
7 | displayName: String,
8 | title: String,
9 | startDate: Date,
10 | endDate: Date,
11 | isIndefinite: Boolean,
12 | rating: Number,
13 | logo: String,
14 | });
15 |
16 | module.exports = mongoose.model("Experience", ExperienceSchema);
17 |
--------------------------------------------------------------------------------
/server/routes/pfps.js:
--------------------------------------------------------------------------------
1 | const express = require('express')
2 | const {
3 | getPfp,
4 | updatePfp
5 | } = require('../controllers/pfpController')
6 |
7 | const router = express.Router()
8 |
9 | const multer = require('multer')
10 |
11 | const storage = multer.memoryStorage()
12 | const upload = multer({ storage: storage })
13 |
14 | // GET a single pfp (by id)
15 | router.get('/:id', getPfp)
16 |
17 | // UPDATE a single pfp (by id)
18 | router.patch('/:id', upload.single('pfp'), updatePfp);
19 |
20 | module.exports = router;
--------------------------------------------------------------------------------
/server/models/schoolModel.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 | const Schema = mongoose.Schema;
3 |
4 | const schoolSchema = new Schema({
5 | name: {
6 | type: String,
7 | required: true,
8 | },
9 | domains: [String],
10 | state_province: String,
11 | country: String,
12 | alpha_two_code: String,
13 | webpages: [String],
14 | schoolTally: {
15 | type: Map,
16 | of: Number,
17 | },
18 | rank: Number,
19 | logo: String,
20 | });
21 |
22 | module.exports = mongoose.model("School", schoolSchema);
23 |
--------------------------------------------------------------------------------
/client/src/util/mongoUtils.js:
--------------------------------------------------------------------------------
1 | import { HOST } from './apiRoutes'
2 | import { fetchWithAuth } from './fetchUtils'
3 |
4 | export const isMongoDBId = async (id) => {
5 | try {
6 | const response = await fetchWithAuth({
7 | url: `${HOST}/api/mongodbId/${id}`,
8 | method: 'GET',
9 | headers: {
10 | 'Content-Type': 'application/json',
11 | },
12 | })
13 |
14 | return response
15 | } catch (error) {
16 | console.error(error.message)
17 | return true
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/client/src/util/generalUtils.js:
--------------------------------------------------------------------------------
1 | export function isObjEmpty(obj) {
2 | return Object.keys(obj).length === 0
3 | }
4 |
5 | export function binarySearch(arr, target) {
6 | let left = 0
7 | let right = arr.length - 1
8 | while (left <= right) {
9 | let mid = Math.floor((left + right) / 2)
10 | if (arr[mid] === target) {
11 | return mid
12 | } else if (arr[mid] < target) {
13 | left = mid + 1 // Search in the right half
14 | } else {
15 | right = mid - 1 // Search in the left half
16 | }
17 | }
18 |
19 | return -1
20 | }
21 |
--------------------------------------------------------------------------------
/client/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "Pipelines",
3 | "name": "Find your pipeline.",
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/src/util/apiRoutes.js:
--------------------------------------------------------------------------------
1 | const HOST =
2 | process.env.REACT_APP_NODE_ENV === 'DEV'
3 | ? 'http://localhost:4000'
4 | : process.env.REACT_APP_NODE_ENV === 'PROD'
5 | ? process.env.REACT_APP_API_URL
6 | : (console.error('Unknown mode:', process.env.MODE), null)
7 |
8 | const HOMEPAGE =
9 | process.env.REACT_APP_NODE_ENV === 'DEV'
10 | ? 'http://localhost:3000'
11 | : process.env.REACT_APP_NODE_ENV === 'PROD'
12 | ? 'https://pipelines.lol'
13 | : (console.error('Unknown mode:', process.env.MODE), null)
14 |
15 | export { HOMEPAGE, HOST }
16 |
--------------------------------------------------------------------------------
/server/utils/apiRoutes.js:
--------------------------------------------------------------------------------
1 | const dotenv = require("dotenv");
2 |
3 | dotenv.config();
4 |
5 | const config = {
6 | HOST:
7 | process.env.NODE_ENV === "DEV"
8 | ? "http://localhost:4000"
9 | : process.env.NODE_ENV === "PROD"
10 | ? process.env.API_URL
11 | : (console.error("Unknown mode:", process.env.MODE), null),
12 |
13 | HOMEPAGE:
14 | process.env.NODE_ENV === "DEV"
15 | ? "http://localhost:3000"
16 | : process.env.NODE_ENV === "PROD"
17 | ? "https://pipelines.lol"
18 | : (console.error("Unknown mode:", process.env.MODE), null),
19 | };
20 |
21 | module.exports = config;
22 |
--------------------------------------------------------------------------------
/server/routes/school.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const {
3 | searchSchools,
4 | getSchool,
5 | updateSchool,
6 | createSchool,
7 | deleteSchool,
8 | } = require("../controllers/schoolController");
9 |
10 | const read = express.Router();
11 | const write = express.Router();
12 |
13 | write.post("/create", createSchool);
14 |
15 | // GET schools by query
16 | read.get("/get/schools/:query", searchSchools);
17 |
18 | read.patch("/update/:id", updateSchool);
19 |
20 | read.get("/get/:id", getSchool);
21 |
22 | write.get("/delete/:id", deleteSchool);
23 |
24 | module.exports = {
25 | read,
26 | write,
27 | };
28 |
--------------------------------------------------------------------------------
/client/src/pages/Loading.js:
--------------------------------------------------------------------------------
1 | import { Triangle } from 'react-loader-spinner'
2 | function Loading() {
3 | return (
4 | <>
5 |
6 |
15 |
16 | >
17 | )
18 | }
19 |
20 | export default Loading
21 |
--------------------------------------------------------------------------------
/client/src/index.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | @layer utilities {
6 | .paused {
7 | animation-play-state: paused;
8 | }
9 | }
10 |
11 | body {
12 | margin: 0;
13 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto',
14 | 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans',
15 | 'Helvetica Neue', sans-serif;
16 | -webkit-font-smoothing: antialiased;
17 | -moz-osx-font-smoothing: grayscale;
18 | background-color: black;
19 | }
20 |
21 | code {
22 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
23 | monospace;
24 | }
25 |
--------------------------------------------------------------------------------
/server/routes/auth.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const {
3 | loginUser,
4 | verifyToken,
5 | getLinkedinInfo,
6 | refreshLinkedinToken,
7 | } = require("../controllers/authController");
8 |
9 | // middleware
10 | const { verifyUser } = require("../middleware/user");
11 |
12 | const router = express.Router();
13 |
14 | // LOGIN user
15 | router.post("/login", verifyUser, loginUser);
16 |
17 | // VERIFY linkedin token
18 | router.post("/verify", verifyToken);
19 |
20 | // GET linkedin user info
21 | router.get("/linkedin/userinfo", getLinkedinInfo);
22 |
23 | // REFRESH linkedin token
24 | router.post("/linkedin/refresh", refreshLinkedinToken);
25 |
26 | module.exports = router;
27 |
--------------------------------------------------------------------------------
/server/routes/token.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const { v4: uuidv4 } = require("uuid");
3 | const { generateToken } = require("../middleware/token");
4 |
5 | const router = express.Router();
6 |
7 | const getToken = async (req, res) => {
8 | // Extract profileId from request parameters
9 | const { linkedinToken, adminToken } = req.query;
10 |
11 | // generate sessionId
12 | const sessionId = uuidv4();
13 |
14 | // generate token with profileId included in the payload if it exists
15 | const token = generateToken(sessionId, linkedinToken, adminToken);
16 |
17 | res.json(token);
18 | };
19 |
20 | // GET token
21 | router.get("/", getToken);
22 |
23 | module.exports = router;
24 |
--------------------------------------------------------------------------------
/client/src/util/companyUtils.js:
--------------------------------------------------------------------------------
1 | import { companies } from '../data/companyData'
2 |
3 | // capitalizes the title of a company
4 | // lower case name -> display name
5 | export function capitalizeCompanyTitle(str) {
6 | // shoutout bobdagoat
7 | if (typeof str !== 'string' || str.trim() === '') {
8 | // bad input
9 | return str
10 | }
11 |
12 | const formattedCompany = companies.find(
13 | (company) => company.name.toLowerCase() === str.toLowerCase()
14 | )
15 |
16 | if (formattedCompany) {
17 | return formattedCompany.name
18 | }
19 |
20 | return str
21 | .split(' ')
22 | .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
23 | .join(' ')
24 | }
25 |
--------------------------------------------------------------------------------
/server/routes/profiles.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const {
3 | getProfiles,
4 | getProfile,
5 | getRandomProfiles,
6 | deleteProfile,
7 | updateProfile,
8 | } = require("../controllers/profileController");
9 |
10 | const read = express.Router();
11 | const write = express.Router();
12 |
13 | // GET all profiles
14 | read.get("/", getProfiles);
15 |
16 | // GET a single profile
17 | read.get("/get/:id", getProfile);
18 |
19 | // GET a certain amount of random profiles
20 | read.get("/random", getRandomProfiles);
21 |
22 | // DELETE a profile
23 | write.delete("/:id", deleteProfile);
24 |
25 | // UPDATE a profile
26 | write.patch("/:id", updateProfile);
27 |
28 | module.exports = {
29 | read,
30 | write,
31 | };
32 |
--------------------------------------------------------------------------------
/server/routes/offers.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const {
3 | createOffer,
4 | updateOffer,
5 | deleteOffer,
6 | getOffer,
7 | getAllOffers,
8 | } = require("../controllers/offerController.js");
9 |
10 | const router = express.Router();
11 |
12 | // CREATE an offer for a profile
13 | router.post("/:profileId", createOffer);
14 |
15 | // UPDATE an offer for a profile
16 | router.put("/:profileId/:offerId", updateOffer);
17 |
18 | // DELETE an offer for a profile
19 | router.delete("/:profileId/:offerId", deleteOffer);
20 |
21 | // GET an offer for a profile
22 | router.get("/:profileId/:offerId", getOffer);
23 |
24 | // GET all offers for a profile
25 | router.get("/:profileId", getAllOffers);
26 |
27 | module.exports = router;
28 |
--------------------------------------------------------------------------------
/server/utils/generalUtils.js:
--------------------------------------------------------------------------------
1 | function binarySearch(arr, target) {
2 | let left = 0;
3 | let right = arr.length - 1;
4 | while (left <= right) {
5 | let mid = Math.floor((left + right) / 2);
6 | if (arr[mid] === target) {
7 | return mid;
8 | } else if (arr[mid] < target) {
9 | left = mid + 1; // Search in the right half
10 | } else {
11 | right = mid - 1; // Search in the left half
12 | }
13 | }
14 |
15 | return -1;
16 | }
17 |
18 | function shuffleArray(array) {
19 | for (let i = array.length - 1; i > 0; i--) {
20 | const j = Math.floor(Math.random() * (i + 1));
21 | [array[i], array[j]] = [array[j], array[i]];
22 | }
23 | return array;
24 | }
25 |
26 | module.exports = { binarySearch, shuffleArray };
27 |
--------------------------------------------------------------------------------
/client/src/components/Footer.js:
--------------------------------------------------------------------------------
1 | import { Link } from 'react-router-dom'
2 |
3 | const Footer = () => {
4 | return (
5 | <>
6 |
7 |
8 | @2024 pipelines.lol. All rights reserved.
9 |
10 |
14 | Have a suggestion?
15 |
16 |
17 | >
18 | )
19 | }
20 |
21 | export default Footer
22 |
--------------------------------------------------------------------------------
/server/models/companyModel.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 | const Schema = mongoose.Schema;
3 |
4 | const companySchema = new Schema({
5 | name: {
6 | type: String,
7 | required: true,
8 | },
9 | displayName: {
10 | type: String,
11 | required: true,
12 | },
13 | logo: String,
14 | description: String,
15 | rating: Number,
16 | prevCompanies: {
17 | type: Map,
18 | of: Number,
19 | },
20 | postCompanies: {
21 | type: Map,
22 | of: Number,
23 | },
24 | tenure: Number,
25 | Employees: [{ type: Schema.Types.ObjectId, ref: "Profile" }],
26 | interns: [{ type: Schema.Types.ObjectId, ref: "Profile" }],
27 | ratedEmployees: [{ type: Schema.Types.ObjectId, ref: "Profile" }],
28 | });
29 |
30 | module.exports = mongoose.model("Company", companySchema);
31 |
--------------------------------------------------------------------------------
/server/models/userModel.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 | const Schema = mongoose.Schema;
3 |
4 | const userSchema = new Schema(
5 | {
6 | email: {
7 | type: String,
8 | unique: true,
9 | required: true,
10 | },
11 | profileId: String,
12 | },
13 | { timestamps: true }
14 | );
15 |
16 | userSchema.statics.login = async function (email) {
17 | // validation
18 | if (!email) {
19 | throw new Error("Email is required.");
20 | }
21 |
22 | let user = await this.findOne({ email });
23 |
24 | if (!user) {
25 | user = await this.create({ email, profileId: null });
26 | }
27 |
28 | //* Logs
29 | console.log(`User logged in: ${email}`);
30 | console.log(user);
31 |
32 | return user;
33 | };
34 |
35 | module.exports = mongoose.model("User", userSchema);
36 |
--------------------------------------------------------------------------------
/client/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom/client'
3 | import './index.css'
4 | import App from './App'
5 |
6 | // context
7 | import { AuthContextProvider } from './context/AuthContext'
8 | import { AdminContextProvider } from './context/AdminContext'
9 | import { EarlyAccessContextProvider } from './context/EarlyAccessContext'
10 |
11 | // store contexts here
12 | const contextProviders = [
13 | EarlyAccessContextProvider,
14 | AuthContextProvider,
15 | AdminContextProvider,
16 | ]
17 |
18 | const root = ReactDOM.createRoot(document.getElementById('root'))
19 | root.render(
20 |
21 | {contextProviders.reduceRight(
22 | (acc, Provider) => {
23 | return {acc}
24 | },
25 |
26 | )}
27 |
28 | )
29 |
--------------------------------------------------------------------------------
/server/routes/emails.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const {
3 | addToNewsletter,
4 | sendEmails,
5 | addEmail,
6 | getEmails,
7 | getEmailById,
8 | removeEmail,
9 | removeEmailById,
10 | } = require("../controllers/emailController");
11 |
12 | const read = express.Router();
13 | const write = express.Router();
14 |
15 | // send email + add to newsletter
16 | read.post("/newsletter", addToNewsletter);
17 |
18 | // SEND emails
19 | write.post("/send", sendEmails);
20 |
21 | // CREATE an email
22 | write.post("/", addEmail);
23 |
24 | // GET emails
25 | write.get("/", getEmails);
26 |
27 | // GET an email by id
28 | write.get("/:id", getEmailById);
29 |
30 | // DELETE an email
31 | write.delete("/:email", removeEmail);
32 |
33 | // DELETE an email by id
34 | write.delete("/:id", removeEmailById);
35 |
36 | module.exports = {
37 | read,
38 | write,
39 | };
40 |
--------------------------------------------------------------------------------
/client/src/pages/Home.js:
--------------------------------------------------------------------------------
1 | import About from '../components/landing/About'
2 | import CTA from '../components/landing/CTA'
3 | import Hero from '../components/landing/Hero'
4 | import SlidingImages from '../components/landing/Marquee'
5 | import Offerings from '../components/landing/Offerings'
6 | import People from '../components/landing/People'
7 | import Testimonies from '../components/landing/Testimony'
8 |
9 | function Home() {
10 | return (
11 | <>
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | >
22 | )
23 | }
24 |
25 | export default Home
26 |
--------------------------------------------------------------------------------
/client/src/context/EarlyAccessContext.js:
--------------------------------------------------------------------------------
1 | import { createContext, useEffect, useState } from 'react'
2 | import Cookies from 'js-cookie'
3 |
4 | export const EarlyAccessContext = createContext()
5 |
6 | export const EarlyAccessContextProvider = ({ children }) => {
7 | const [earlyAccess, setEarlyAccess] = useState(false)
8 |
9 | useEffect(() => {
10 | // check if user originally had early access
11 | const access = Cookies.get('earlyAccess')
12 | if (access === 'true') {
13 | setEarlyAccess(true)
14 | }
15 | }, [])
16 |
17 | const setAccess = (access) => {
18 | setEarlyAccess(access)
19 | Cookies.set('earlyAccess', access.toString())
20 | }
21 |
22 | return (
23 |
24 | {children}
25 |
26 | )
27 | }
28 |
--------------------------------------------------------------------------------
/client/src/util/tokenUtils.js:
--------------------------------------------------------------------------------
1 | import Cookies from 'js-cookie'
2 |
3 | import { HOST } from './apiRoutes'
4 |
5 | export const generateToken = async () => {
6 | const linkedinToken = localStorage.getItem('linkedinToken')
7 | const adminToken = localStorage.getItem('adminToken')
8 |
9 | // Use fetch to get a new session ID if one does not already exist
10 | try {
11 | const url = `${HOST}/api/token${linkedinToken ? `?linkedinToken=${linkedinToken}` : ''}${adminToken ? `&adminToken=${adminToken}` : ''}`
12 | const response = await fetch(url)
13 |
14 | if (!response.ok) {
15 | throw new Error('Network response was not ok')
16 | }
17 |
18 | const data = await response.json()
19 | Cookies.set('token', data) // Store the session ID
20 | return data
21 | } catch (error) {
22 | console.error('Error:', error)
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/server/controllers/adminController.js:
--------------------------------------------------------------------------------
1 | const jwt = require("jsonwebtoken");
2 |
3 | const Admin = require("../models/adminModel");
4 | const { verifyAdminToken } = require("../middleware/admin");
5 |
6 | const createToken = (_id) => {
7 | return jwt.sign({ _id }, process.env.JWT_SECRET, { expiresIn: "3d" });
8 | };
9 |
10 | const verifyToken = async (req, res) => {
11 | const { token } = req.body;
12 |
13 | const isAdmin = await verifyAdminToken(token);
14 |
15 | res.status(200).json({ isAdmin });
16 | };
17 |
18 | const loginAdmin = async (req, res) => {
19 | const { email, password } = req.body;
20 |
21 | try {
22 | const admin = await Admin.login(email, password);
23 |
24 | // create token
25 | const token = createToken(admin._id);
26 |
27 | res.status(200).json({ _id: admin._id, token });
28 | } catch (error) {
29 | res.status(400).json({ error: error.message });
30 | }
31 | };
32 |
33 | module.exports = {
34 | loginAdmin,
35 | verifyToken,
36 | };
37 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2024 Aidan O., Arthur P., Lewin B., and Tom N.
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8 |
--------------------------------------------------------------------------------
/client/src/pages/(admin)/Admin.js:
--------------------------------------------------------------------------------
1 | import { Routes, Route } from 'react-router-dom'
2 | import AdminLogin from './AdminLogin'
3 | import AdminDashboard from './AdminDashboard'
4 |
5 | import { useAdmin } from '../../hooks/useAdminContext'
6 |
7 | import { error404 } from '../../components/Error404'
8 |
9 | const Admin = () => {
10 | const { admin } = useAdmin()
11 |
12 | return (
13 |
14 | } />
15 | {
16 |
21 | ) : (
22 | error404(
23 | 'You do not have permission to view this page.'
24 | )
25 | )
26 | }
27 | />
28 | // Add more admin routes here
29 | }
30 |
31 | )
32 | }
33 |
34 | export default Admin
35 |
--------------------------------------------------------------------------------
/server/models/profileModel.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 | const random = require("mongoose-simple-random");
3 | const Experience = require("./experienceModel"); // Import the Experience model
4 | const Offer = require("./offerModel"); // Import the Offer model
5 |
6 | const Schema = mongoose.Schema;
7 |
8 | const profileSchema = new Schema(
9 | {
10 | userId: String,
11 | firstName: String,
12 | lastName: String,
13 | username: String,
14 | linkedin: String,
15 | pfp: String,
16 | position: String,
17 | location: String,
18 | anonymous: Boolean,
19 | school: String,
20 | pipeline: [Experience.schema],
21 | offers: [Offer.schema],
22 | created: Boolean,
23 | },
24 | { timestamps: true }
25 | );
26 | profileSchema.plugin(random);
27 |
28 | // static methods
29 | profileSchema.statics.getByUserId = async function (userId) {
30 | const profile = await this.findOne({ userId });
31 |
32 | if (!profile) {
33 | throw Error(`Invalid user ID.`);
34 | }
35 |
36 | return profile;
37 | };
38 |
39 | module.exports = mongoose.model("Profile", profileSchema);
40 |
--------------------------------------------------------------------------------
/server/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "server",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "start": "node index.js",
9 | "dev": "nodemon index.js"
10 | },
11 | "author": "",
12 | "license": "ISC",
13 | "dependencies": {
14 | "@aws-sdk/client-s3": "^3.485.0",
15 | "@aws-sdk/s3-request-presigner": "^3.485.0",
16 | "aws-sdk": "^2.1533.0",
17 | "axios": "^1.6.5",
18 | "bcrypt": "^5.1.1",
19 | "body-parser": "^1.20.2",
20 | "cors": "^2.8.5",
21 | "crypto": "^1.0.1",
22 | "dotenv": "^16.3.1",
23 | "express": "^4.18.2",
24 | "jsonwebtoken": "^9.0.2",
25 | "math": "^0.0.3",
26 | "mathjs": "^12.4.1",
27 | "mongoose": "^8.0.3",
28 | "mongoose-simple-random": "^0.4.1",
29 | "multer": "^1.4.5-lts.1",
30 | "querystring": "^0.2.1",
31 | "resend": "^3.2.0",
32 | "uuid": "^9.0.1",
33 | "validator": "^13.11.0"
34 | },
35 | "devDependencies": {
36 | "jest": "^29.7.0",
37 | "nodemon": "^3.0.3",
38 | "supertest": "^6.3.4"
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/client/src/hooks/usePatchJson.js:
--------------------------------------------------------------------------------
1 | import { useState } from 'react'
2 | import Cookies from 'js-cookie'
3 |
4 | const usePatchJson = async (url, dataToUpdate) => {
5 | // State to manage response data
6 | const [responseData, setResponseData] = useState(null)
7 | // State to manage loading state
8 | const [loading, setLoading] = useState(true)
9 | // State to manage error state
10 | const [error, setError] = useState(null)
11 |
12 | try {
13 | const response = await fetch(url, {
14 | method: 'PATCH',
15 | headers: {
16 | 'Content-Type': 'application/json',
17 | Authorization: `Bearer ${Cookies.get('sessionId')}`,
18 | },
19 | body: JSON.stringify(dataToUpdate), // Assuming you have data to update
20 | })
21 |
22 | if (!response.ok) {
23 | throw new Error(`Failed to update data. Status: ${response.status}`)
24 | }
25 |
26 | const result = await response.json()
27 | setResponseData(result)
28 | } catch (error) {
29 | setError(error.message)
30 | } finally {
31 | setLoading(false)
32 | }
33 |
34 | // Return the state values
35 | return { responseData, loading, error }
36 | }
37 |
38 | export default usePatchJson
39 |
--------------------------------------------------------------------------------
/client/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: [
4 | './src/**/*.{js,jsx,ts,tsx}',
5 | './node_modules/tailwind-datepicker-react/dist/**/*.js',
6 | ],
7 | theme: {
8 | extend: {
9 | colors: {
10 | 'pipelines-gray-100': '#F7F7F7',
11 | 'pipelines-gray-500': '#444444',
12 | 'pipeline-blue-200': '#0265AC',
13 | },
14 | animation: {
15 | 'infinite-scroll': 'infinite-scroll 265s linear infinite',
16 | blob: 'blob 7s infinite',
17 | },
18 | keyframes: {
19 | 'infinite-scroll': {
20 | from: { transform: 'translateX(0)' },
21 | to: { transform: 'translateX(-180%)' },
22 | },
23 | blob: {
24 | '0%': {
25 | transform: 'translate(0px, 0px) scale(1)',
26 | },
27 | '50%': {
28 | transform: 'translate(0px, -5px) scale(1.2)',
29 | },
30 | '100%': {
31 | transform: 'translate(0px, 0px) scale(1)',
32 | },
33 | },
34 | },
35 | },
36 | },
37 | plugins: [require('daisyui'), require('flowbite/plugin')],
38 | }
39 |
--------------------------------------------------------------------------------
/server/routes/companies.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const bodyParser = require("body-parser");
3 | const {
4 | createCompany,
5 | getCompany,
6 | getCompanyByName,
7 | getCompanies,
8 | getEmployees,
9 | updateCompany,
10 | updateCompanies,
11 | deleteCompany,
12 | } = require("../controllers/companyController");
13 |
14 | const read = express.Router();
15 | const write = express.Router();
16 |
17 | //read a specific company
18 | write.post("/create", bodyParser.json(), createCompany);
19 |
20 | //get a specific company
21 | read.get("/get/:id", getCompany);
22 |
23 | // get a specific company by name
24 | read.get("/getBy", getCompanyByName);
25 |
26 | //get multiple companies based on a query
27 | read.get("/get/companies/:query", getCompanies);
28 |
29 | // get profiles of employees that work at company
30 | read.get("/employees/:id", getEmployees);
31 |
32 | //Update a specific company
33 | // ! TEMP READ COMMAND
34 | // TODO: change up backend to remove client changing of companies
35 | read.patch("/update/:id", bodyParser.json(), updateCompany);
36 |
37 | //Update a specific company
38 | // ! TEMP READ COMMAND
39 | // TODO: change up backend to remove client changing of companies
40 | read.patch("/update", bodyParser.json(), updateCompanies);
41 |
42 | //Delete a specific company
43 | write.delete("/delete/:id", deleteCompany);
44 |
45 | module.exports = {
46 | read,
47 | write,
48 | };
49 |
--------------------------------------------------------------------------------
/server/middleware/token.js:
--------------------------------------------------------------------------------
1 | const jwt = require("jsonwebtoken");
2 |
3 | const generateToken = (sessionId, linkedinToken, adminToken) => {
4 | // Create payload object with sessionId
5 | const payload = { id: sessionId };
6 |
7 | // If linkedinToken exists, include it in the payload
8 | if (linkedinToken) {
9 | payload.linkedinToken = linkedinToken;
10 | }
11 |
12 | // If adminToken exists, include it in the payload
13 | if (adminToken) {
14 | payload.adminToken = adminToken;
15 | }
16 |
17 | // Generate token with payload
18 | const token = jwt.sign(payload, process.env.JWT_SECRET, {
19 | expiresIn: "1d",
20 | });
21 |
22 | return token;
23 | };
24 |
25 | const verifyToken = (req, res, next) => {
26 | const authHeader = req.headers.authorization;
27 |
28 | if (!authHeader) {
29 | return res.status(401).json({ msg: "No authorization token provided." });
30 | }
31 |
32 | const tokenParts = authHeader.split(" ");
33 | if (tokenParts.length !== 2 || tokenParts[0] !== "Bearer") {
34 | return res.status(401).json({ msg: "Token format is 'Bearer '." });
35 | }
36 |
37 | const token = tokenParts[1];
38 |
39 | try {
40 | jwt.verify(token, process.env.JWT_SECRET);
41 | next();
42 | } catch (err) {
43 | console.error(err);
44 | return res.status(401).json({ msg: "Invalid or expired token." });
45 | }
46 | };
47 |
48 | module.exports = {
49 | generateToken,
50 | verifyToken,
51 | };
52 |
--------------------------------------------------------------------------------
/client/src/components/ProfilePicture.js:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from 'react'
2 | import { useParams } from 'react-router-dom'
3 |
4 | import { HOST } from '../util/apiRoutes'
5 | import { fetchWithAuth } from '../util/fetchUtils'
6 |
7 | export const ProfilePicture = ({ profile, setPfp }) => {
8 | const { id } = useParams()
9 |
10 | const [fetchedPfp, setFetchedPfp] = useState(null)
11 |
12 | const fetchPfp = async () => {
13 | try {
14 | const data = await fetchWithAuth({
15 | url: `${HOST}/api/pfp/${id}`,
16 | method: 'GET',
17 | })
18 |
19 | setPfp(data.pfp)
20 | setFetchedPfp(data.pfp)
21 | } catch (error) {
22 | console.error(error.message)
23 | setPfp(null)
24 | }
25 | }
26 |
27 | useEffect(() => {
28 | const fetchInfo = async () => {
29 | await fetchPfp()
30 | }
31 |
32 | fetchInfo()
33 | }, [])
34 |
35 | const src = fetchedPfp || '/avatar.png'
36 |
37 | return (
38 | <>
39 |
40 |
45 |
46 | >
47 | )
48 | }
49 |
--------------------------------------------------------------------------------
/client/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "es2021": true,
5 | "node": true // hm...https://github.com/facebook/create-react-app/issues/12212
6 | },
7 | "extends": [
8 | "eslint:recommended",
9 | "plugin:react/recommended",
10 | "plugin:prettier/recommended"
11 | ],
12 | "parserOptions": {
13 | "ecmaVersion": "latest",
14 | "sourceType": "module",
15 | "ecmaFeatures": {
16 | "jsx": true
17 | }
18 | },
19 | "plugins": ["react"],
20 | "rules": {
21 | "react/react-in-jsx-scope": "off",
22 | "react/jsx-uses-react": "off",
23 | "react/prop-types": 0,
24 | "no-prototype-builtins": "off",
25 | "prettier/prettier": [
26 | "error",
27 | {
28 | "endOfLine": "auto"
29 | }
30 | ],
31 | "eqeqeq": ["error", "always"],
32 | "no-eval": "error",
33 | "no-implied-eval": "error",
34 | "no-return-await": "error",
35 | "no-self-compare": "error",
36 | "no-throw-literal": "error",
37 | "no-unused-expressions": [
38 | "error",
39 | { "allowShortCircuit": true, "allowTernary": true }
40 | ],
41 | "no-useless-return": "error",
42 | "no-void": "error",
43 | "wrap-iife": ["error", "any"]
44 | },
45 | "settings": {
46 | "react": {
47 | "version": "detect"
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/client/src/context/AdminContext.js:
--------------------------------------------------------------------------------
1 | import { createContext, useReducer, useEffect } from 'react'
2 |
3 | import { fetchWithAuth } from '../util/fetchUtils'
4 | import { HOST } from '../util/apiRoutes'
5 |
6 | export const AdminContext = createContext()
7 |
8 | export const adminReducer = (state, action) => {
9 | switch (action.type) {
10 | case 'SET_ADMIN':
11 | return { admin: action.payload } // action.payload should be a boolean value
12 | default:
13 | return state
14 | }
15 | }
16 |
17 | const verifyToken = async (token) => {
18 | try {
19 | const { isAdmin } = await fetchWithAuth({
20 | url: `${HOST}/api/admin/verify`,
21 | method: 'POST',
22 | data: { token },
23 | })
24 | return isAdmin
25 | } catch (error) {
26 | console.error('Error verifying token:', error)
27 | return false
28 | }
29 | }
30 |
31 | export const AdminContextProvider = ({ children }) => {
32 | const [state, dispatch] = useReducer(adminReducer, {
33 | admin: false, // Default to null
34 | })
35 |
36 | useEffect(() => {
37 | const token = localStorage.getItem('adminToken')
38 | if (token) {
39 | verifyToken(token).then((isValidToken) => {
40 | dispatch({ type: 'SET_ADMIN', payload: isValidToken })
41 | })
42 | }
43 | }, [])
44 |
45 | return (
46 |
47 | {children}
48 |
49 | )
50 | }
51 |
--------------------------------------------------------------------------------
/client/src/components/landing/Hero.js:
--------------------------------------------------------------------------------
1 | import CTAButton from './CTAButton'
2 |
3 | export default function Hero() {
4 | return (
5 |
15 |
16 |
17 | Visualize Tech
18 |
19 | Career Pipelines
20 |
21 | With Ease
22 |
23 |
24 |
25 | Track, visualize, and explore your career journey. From top
26 | tech giants to small startups, discover career path insights
27 | effortlessly.
28 |
29 |
30 |
31 |
32 | )
33 | }
34 |
--------------------------------------------------------------------------------
/client/src/components/landing/CTAButton.js:
--------------------------------------------------------------------------------
1 | import { useNavigate } from 'react-router-dom'
2 | export default function CTAButton({ text, to, href }) {
3 | const navigate = useNavigate()
4 | if (href) {
5 | return (
6 | <>
7 |
11 |
12 |
13 | {text}
14 |
15 | >
16 | )
17 | }
18 |
19 | return (
20 | <>
21 | navigate(to)}
23 | className="group relative z-0 mt-6 inline-flex cursor-pointer items-center justify-center overflow-hidden rounded-lg bg-pipelines-gray-100 px-10 py-2 font-medium tracking-tighter text-black/80 hover:text-white"
24 | >
25 |
26 |
27 | {text}
28 |
29 | >
30 | )
31 | }
32 |
--------------------------------------------------------------------------------
/server/models/adminModel.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 | const bcrypt = require("bcrypt");
3 | const validator = require("validator");
4 |
5 | const Schema = mongoose.Schema;
6 |
7 | const adminSchema = new Schema(
8 | {
9 | email: {
10 | type: String,
11 | unique: true,
12 | required: true,
13 | },
14 | password: {
15 | type: String,
16 | required: true,
17 | },
18 | },
19 | { timestamps: true }
20 | );
21 |
22 | adminSchema.statics.signup = async function (email, password) {
23 | // validation
24 | if (!email || !password) {
25 | throw Error(`All fields must be filled.`);
26 | }
27 | if (!validator.isEmail(email)) {
28 | throw Error(`Email is invalid.`);
29 | }
30 |
31 | // Enable when strong passwords are needed.
32 | // if (!validator.isStrongPassword(password)) {
33 | // throw Error(`Password is not strong enough.`)
34 | // }
35 |
36 | const exists = await this.findOne({ email });
37 |
38 | if (exists) {
39 | throw Error(`Email already in use.`);
40 | }
41 |
42 | const salt = await bcrypt.genSalt(10);
43 | const hash = await bcrypt.hash(password, salt);
44 |
45 | const admin = await this.create({ email, password: hash });
46 |
47 | return admin;
48 | };
49 |
50 | adminSchema.statics.login = async function (email, password) {
51 | // validation
52 | if (!email) {
53 | throw new Error("Email is required.");
54 | }
55 |
56 | let admin = await this.findOne({ email });
57 |
58 | if (!admin) {
59 | throw new Error("Invalid email.");
60 | }
61 |
62 | const match = await bcrypt.compare(password, admin.password);
63 |
64 | if (!match) {
65 | throw new Error(`Incorrect password.`);
66 | }
67 |
68 | return admin;
69 | };
70 |
71 | module.exports = mongoose.model("Admin", adminSchema);
72 |
--------------------------------------------------------------------------------
/server/middleware/admin.js:
--------------------------------------------------------------------------------
1 | const jwt = require("jsonwebtoken");
2 |
3 | const Admin = require("../models/adminModel");
4 |
5 | const verifyAdminToken = async (token) => {
6 | try {
7 | // Get decoded token
8 | const decodedToken = jwt.verify(token, process.env.JWT_SECRET);
9 |
10 | // Extract the id from the decoded token
11 | const { _id } = decodedToken;
12 |
13 | // Check if an admin account exists with the provided _id
14 | const admin = await Admin.findById(_id);
15 |
16 | // Return true if an admin account exists, false otherwise
17 | return admin ? true : false;
18 | } catch (err) {
19 | console.error(err);
20 | return false;
21 | }
22 | };
23 |
24 | const verifyAdmin = async (req, res, next) => {
25 | // Log the requested URL
26 | console.log("Requested URL:", req.originalUrl);
27 |
28 | const authHeader = req.headers.authorization;
29 |
30 | if (!authHeader) {
31 | return res.status(401).json({ msg: "No authorization token provided." });
32 | }
33 |
34 | const tokenParts = authHeader.split(" ");
35 | if (tokenParts.length !== 2 || tokenParts[0] !== "Bearer") {
36 | return res.status(401).json({ msg: "Token format is 'Bearer '." });
37 | }
38 |
39 | // extract admin token from MOTHER token
40 | const token = tokenParts[1];
41 |
42 | // try to get an admin token
43 | try {
44 | const decodedToken = jwt.verify(token, process.env.JWT_SECRET);
45 | const adminToken = decodedToken.adminToken;
46 |
47 | // Verify the token has admin privileges
48 | if (!adminToken || !(await verifyAdminToken(adminToken))) {
49 | throw new Error("Invalid admin token.");
50 | }
51 | } catch (err) {
52 | console.log(err);
53 | return res.status(403).json({
54 | msg: "User does not have the required privileges for this request.",
55 | });
56 | }
57 |
58 | next();
59 | };
60 |
61 | module.exports = {
62 | verifyAdminToken,
63 | verifyAdmin,
64 | };
65 |
--------------------------------------------------------------------------------
/client/src/components/Error404.js:
--------------------------------------------------------------------------------
1 | import { useNavigate } from 'react-router-dom'
2 | import { HOMEPAGE } from '../util/apiRoutes'
3 |
4 | export const error404 = (error_text) => {
5 | const navigate = useNavigate()
6 | return (
7 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | 404 Error
23 |
24 |
25 | {error_text}
26 |
27 |
28 | Sorry about that! Please visit our homepage to get
29 | where you need to go.
30 |
31 |
{
34 | navigate('/')
35 | }}
36 | >
37 | Take me home!
38 |
39 |
40 |
41 |
42 |
43 | )
44 | }
45 |
--------------------------------------------------------------------------------
/client/src/data/index.js:
--------------------------------------------------------------------------------
1 | const mockPipelineData = [
2 | {
3 | _id: '1',
4 | profileId: 'profile1',
5 | firstName: 'John',
6 | lastName: 'Doe',
7 | pfp: 'https://placekitten.com/200/300',
8 | anonymous: false,
9 | pipeline: [
10 | {
11 | _id: 'exp1',
12 | company: 'Amazon',
13 | title: 'Software Engineer',
14 | date: 'Jan 2022 - Present',
15 | },
16 | ],
17 | },
18 | {
19 | _id: '2',
20 | profileId: 'profile2',
21 | firstName: 'Jane',
22 | lastName: 'Smith',
23 | pfp: 'https://placekitten.com/200/300',
24 | anonymous: true,
25 | pipeline: [
26 | {
27 | _id: 'exp2',
28 | company: 'Apple',
29 | title: 'Product Manager',
30 | date: 'Mar 2020 - Dec 2021',
31 | },
32 | ],
33 | },
34 | {
35 | _id: '3',
36 | profileId: 'profile3',
37 | firstName: 'Alice',
38 | lastName: 'Johnson',
39 | pfp: 'https://placekitten.com/200/300',
40 | anonymous: false,
41 | pipeline: [
42 | {
43 | _id: 'exp3',
44 | company: 'Google',
45 | title: 'UX Designer',
46 | date: 'Jul 2019 - Feb 2021',
47 | },
48 | ],
49 | },
50 | {
51 | id: '4',
52 | profileId: 'profile4',
53 | firstName: 'Bob',
54 | lastName: 'Williams',
55 | pfp: 'https://placekitten.com/200/300',
56 | anonymous: true,
57 | pipeline: [
58 | {
59 | _id: 'exp4',
60 | company: 'Jane Street',
61 | title: 'Software Engineer',
62 | date: 'Jan 2018 - Jun 2019',
63 | },
64 | ],
65 | },
66 | ]
67 |
68 | export default mockPipelineData
69 |
--------------------------------------------------------------------------------
/client/src/context/AuthContext.js:
--------------------------------------------------------------------------------
1 | import { createContext, useReducer, useEffect } from 'react'
2 | import Cookies from 'js-cookie'
3 |
4 | import { fetchWithAuth } from '../util/fetchUtils'
5 | import { HOST } from '../util/apiRoutes'
6 |
7 | export const AuthContext = createContext()
8 |
9 | export const authReducer = (state, action) => {
10 | switch (action.type) {
11 | case 'LOGIN':
12 | return { user: action.payload }
13 | case 'LOGOUT':
14 | return { user: null }
15 | case 'CREATED':
16 | return { user: { ...state.user, profileCreated: true } }
17 | default:
18 | return state
19 | }
20 | }
21 |
22 | const verifyToken = async (email, token) => {
23 | try {
24 | const { isVerified } = await fetchWithAuth({
25 | url: `${HOST}/api/user/verify`,
26 | method: 'POST',
27 | data: { email, token },
28 | })
29 | return isVerified
30 | } catch (error) {
31 | console.error('Error verifying token:', error)
32 | return false
33 | }
34 | }
35 |
36 | export const AuthContextProvider = ({ children }) => {
37 | const [state, dispatch] = useReducer(authReducer, {
38 | user: null,
39 | })
40 |
41 | useEffect(() => {
42 | const user = JSON.parse(localStorage.getItem('user'))
43 | const token = Cookies.get('token')
44 |
45 | if (user && token) {
46 | verifyToken(user.email, token).then((isValidToken) => {
47 | if (isValidToken) {
48 | dispatch({ type: 'LOGIN', payload: user })
49 |
50 | if (user.profileCreated) {
51 | dispatch({ type: 'CREATED', payload: user })
52 | }
53 | }
54 | })
55 | }
56 | }, [])
57 |
58 | return (
59 |
60 | {children}
61 |
62 | )
63 | }
64 |
--------------------------------------------------------------------------------
/client/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | Pipelines.lol - Find Your Next Company
13 |
14 |
16 |
17 |
18 |
19 |
21 |
22 |
23 |
24 |
25 |
27 |
28 |
29 |
30 |
31 | Hi There! To use Pipelines, you will need to enable JavaScript in your browser.
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/server/middleware/user.js:
--------------------------------------------------------------------------------
1 | const axios = require("axios");
2 | const jwt = require("jsonwebtoken");
3 |
4 | const getEmailFromToken = async (token) => {
5 | try {
6 | // decode mother jwt
7 | const decodedToken = jwt.verify(token, process.env.JWT_SECRET);
8 |
9 | // extract linkedin token from mother jwt
10 | const linkedinToken = decodedToken.linkedinToken;
11 |
12 | // this request gets basic profile info from linkedin token
13 | const { data } = await axios.get("https://api.linkedin.com/v2/userinfo", {
14 | headers: {
15 | Authorization: `Bearer ${linkedinToken}`,
16 | },
17 | });
18 |
19 | // get the email from linkedin data
20 | return data.email;
21 | } catch (err) {
22 | console.error(err);
23 | return null;
24 | }
25 | };
26 |
27 | const verifyUser = async (req, res, next) => {
28 | const { email } = req.body;
29 |
30 | // Log the requested URL
31 | console.log("Requested URL:", req.originalUrl);
32 |
33 | // verify token has linkedin token with
34 | // requested user's email
35 | const authHeader = req.headers.authorization;
36 |
37 | if (!authHeader) {
38 | return res.status(401).json({ msg: "No authorization token provided." });
39 | }
40 |
41 | const tokenParts = authHeader.split(" ");
42 | if (tokenParts.length !== 2 || tokenParts[0] !== "Bearer") {
43 | return res.status(401).json({ msg: "Token format is 'Bearer '." });
44 | }
45 |
46 | const token = tokenParts[1];
47 |
48 | try {
49 | const emailFromToken = await getEmailFromToken(token);
50 |
51 | if (!emailFromToken) {
52 | throw new Error("Invalid token.");
53 | }
54 |
55 | // compare emails and break out if they dont match
56 | if (email !== emailFromToken) {
57 | return res.status(403).json({
58 | msg: "Invalid Linkedin token for user login.",
59 | });
60 | }
61 | } catch (err) {
62 | return res.status(401).json({ msg: "Invalid or expired Linkedin token." });
63 | }
64 |
65 | next();
66 | };
67 |
68 | module.exports = {
69 | verifyUser,
70 | getEmailFromToken,
71 | };
72 |
--------------------------------------------------------------------------------
/client/src/App.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | .App {
6 | text-align: center;
7 | }
8 |
9 | .App-logo {
10 | height: 40vmin;
11 | pointer-events: none;
12 | }
13 |
14 | @media (prefers-reduced-motion: no-preference) {
15 | .App-logo {
16 | animation: App-logo-spin infinite 20s linear;
17 | }
18 | }
19 |
20 | .App-header {
21 | background-color: #282c34;
22 | min-height: 100vh;
23 | display: flex;
24 | flex-direction: column;
25 | align-items: center;
26 | justify-content: center;
27 | font-size: calc(10px + 2vmin);
28 | color: white;
29 | }
30 |
31 | .App-link {
32 | color: #61dafb;
33 | }
34 |
35 | @keyframes App-logo-spin {
36 | from {
37 | transform: rotate(0deg);
38 | }
39 | to {
40 | transform: rotate(360deg);
41 | }
42 | }
43 | .underline-hover {
44 | position: relative;
45 | text-decoration: none;
46 | color: white;
47 | font-weight: light;
48 | text-transform: uppercase;
49 | transition: color 0.3s ease-in-out;
50 | }
51 |
52 | .underline-hover:hover,
53 | .underline-hover.active {
54 | color: #0265ac;
55 | }
56 |
57 | .highlight {
58 | color: #0265ac;
59 | }
60 |
61 | .underline-hover span {
62 | position: absolute;
63 | bottom: 0;
64 | left: 50%;
65 | transform: translateX(-50%);
66 | width: 0;
67 | height: 1px;
68 | background-color: white;
69 | transition: all 0.3s ease-in-out;
70 | }
71 |
72 | .underline-hover:hover span,
73 | .underline-hover.active span {
74 | width: 60%;
75 | }
76 |
77 | .underline-force {
78 | position: relative;
79 | text-decoration: none;
80 | font-weight: light;
81 | text-transform: uppercase;
82 | }
83 |
84 | .underline-force span {
85 | position: absolute;
86 | bottom: 0;
87 | left: 50%;
88 | transform: translateX(-50%);
89 | width: 0;
90 | height: 1px;
91 | background-color: white;
92 | transition: all 0.3s ease-in-out;
93 | }
94 |
95 | .underline-force span,
96 | .underline-force.active span {
97 | width: 60%;
98 | }
99 |
--------------------------------------------------------------------------------
/server/app.test.js:
--------------------------------------------------------------------------------
1 | const request = require("supertest");
2 | const router = require("./routes/companies");
3 | const Company = require("./models/companyModel");
4 | const mongoose = require("mongoose");
5 | const server = require("./index");
6 | const app = require("./index");
7 |
8 | const api = request(router);
9 |
10 | describe("Company tests", () => {
11 | describe("POST calls", () => {
12 | test("create-company", async () => {
13 | //build a new item
14 | const newCompany = { name: "TestCompany" };
15 | const response = await api.post("/create").send(newCompany);
16 |
17 | const companies = await Company.find({});
18 |
19 | expect(companies[companies.length - 1].name).toBe("TestCompany");
20 | });
21 |
22 | test("update-company", async () => {
23 | const name = "TestCompany";
24 | const newCompany = {
25 | rating: 5,
26 | };
27 |
28 | const response = await api.put(`/update/${name}`).send(newCompany);
29 | expect(response.ok).toBeTruthy();
30 | });
31 |
32 | test("delete-company", async () => {
33 | const name = "TestCompany";
34 | const response = await api.delete(`/delete/${name}`);
35 | });
36 | });
37 |
38 | describe("GET calls", () => {
39 | test("get-company", async () => {
40 | const name = "TestCompany";
41 | const response = await api.get(`/get/${name}`);
42 |
43 | // Check if the response status is okay (status code 200-299)
44 | expect(response.ok).toBeTruthy();
45 |
46 | // Parse the JSON in the response
47 | const jsonData = await response.body;
48 |
49 | // Now you can assert or perform further checks on the extracted JSON data
50 | expect(jsonData).toHaveProperty("name");
51 | expect(jsonData.name).toBe("TestCompany");
52 | // Add more assertions based on your JSON structure
53 | });
54 | });
55 | });
56 |
57 | describe("User tests", () => {
58 | test("create-profile", async () => {
59 | c;
60 | });
61 | });
62 |
63 | afterAll((done) => {
64 | // Closing the DB connection allows Jest to exit successfully.
65 | mongoose.connection.close();
66 | done();
67 | });
68 |
--------------------------------------------------------------------------------
/server/controllers/imageModerationController.js:
--------------------------------------------------------------------------------
1 | const aws = require('aws-sdk');
2 |
3 | // Configure AWS SDK with your credentials and region
4 | aws.config.update({
5 | accessKeyId: process.env.AWS_ACCESS_KEY_ID,
6 | secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
7 | region: process.env.BUCKET_REGION,
8 | });
9 |
10 | // Create an instance of Rekognition
11 | const rekognition = new aws.Rekognition();
12 |
13 | const recognizeImage = async (req, res) => {
14 | try {
15 | // if there is no file, then no changes will be made
16 | if (!req.file) {
17 | return res.status(200).json(profile);
18 | }
19 | let { buffer } = req.file
20 |
21 | // Perform Rekognition operation
22 | const moderationResult = await moderateImage(buffer);
23 |
24 | // Send the result back to the client
25 | res.json({ moderationResult });
26 | } catch (error) {
27 | console.error(error);
28 | res.status(500).json({ error: 'Internal Server Error' });
29 | }
30 | }
31 |
32 | async function moderateImage(binaryData) {
33 | const params = {
34 | Image: {
35 | Bytes: binaryData,
36 | },
37 | MinConfidence: 70,
38 | };
39 |
40 | try {
41 | const { ModerationLabels } = await rekognition.detectModerationLabels(params).promise();
42 |
43 | // If no labels found -> image doesn't contain any forbidden content
44 | if (!ModerationLabels || ModerationLabels.length === 0) {
45 | return [];
46 | }
47 |
48 | // If some labels found -> compare them with forbidden labels
49 | const forbiddenLabels = ['Explicit Nudity', 'Violence', 'Visually Disturbing', 'Rude Gestures', 'Tobacco', 'Gambling', 'Hate Symbols'];
50 | const labels = ModerationLabels.map((label) => label.ParentName).filter(Boolean);
51 | const foundForbiddenLabels = labels.filter((label) => forbiddenLabels.includes(label));
52 |
53 | return foundForbiddenLabels;
54 | } catch (error) {
55 | console.error(`Error in image moderation: ${error}`);
56 | throw error;
57 | }
58 | }
59 |
60 | module.exports = {
61 | recognizeImage
62 | }
63 |
--------------------------------------------------------------------------------
/client/src/pages/(admin)/AdminDashboard.js:
--------------------------------------------------------------------------------
1 | import { useState } from 'react'
2 |
3 | // dashboards
4 | import { CompanyPage } from './pages/CompanyDashboard'
5 | import { EmailPage } from './pages/EmailDashboard'
6 |
7 | function AdminDashboard() {
8 | const [page, setPage] = useState('company')
9 |
10 | return (
11 |
22 | {/* Sidenav */}
23 |
24 |
25 |
Admin Dashboard
26 |
27 |
28 | setPage('company')}>
29 | Companies
30 |
31 | setPage('email')}>
32 | Emails
33 |
34 | {/* Add more navigation links here */}
35 |
36 |
37 |
38 | {/* Main Dashboard Content */}
39 |
46 | {page === 'company' ? (
47 |
48 | ) : page === 'email' ? (
49 |
50 | ) : (
51 | <>>
52 | )}
53 |
54 |
55 | )
56 | }
57 |
58 | export default AdminDashboard
59 |
--------------------------------------------------------------------------------
/client/src/util/fetchUtils.js:
--------------------------------------------------------------------------------
1 | import Cookies from 'js-cookie'
2 |
3 | import { generateToken } from './tokenUtils'
4 |
5 | export const fetchWithAuth = async ({
6 | url,
7 | method,
8 | data = {},
9 | headers = {},
10 | retry = false,
11 | }) => {
12 | // Default headers including Authorization
13 | const defaultHeaders = {
14 | 'Content-Type': 'application/json',
15 | Authorization: `Bearer ${Cookies.get('token')}`,
16 | }
17 |
18 | // Combine default headers with any custom headers passed in
19 | const combinedHeaders = { ...defaultHeaders, ...headers }
20 |
21 | const fetchOptions = {
22 | method: method,
23 | headers: combinedHeaders,
24 | }
25 |
26 | if (data && Object.keys(data).length) {
27 | fetchOptions.body = JSON.stringify(data)
28 | }
29 |
30 | try {
31 | const response = await fetch(url, fetchOptions)
32 |
33 | // if this is the first catch at an unauthorized call
34 | // try and regenerate the token
35 | if (!retry && response.status === 401) {
36 | // Invalid token, regenerate it and retry the request
37 | const newToken = await generateToken()
38 | combinedHeaders.Authorization = `Bearer ${newToken}`
39 |
40 | // Retry the request with the new token
41 | return fetchWithAuth({
42 | url,
43 | method,
44 | data,
45 | headers: combinedHeaders,
46 | retry: true,
47 | })
48 | }
49 |
50 | if (!response.ok) {
51 | const errorMessage = await getErrorMessage(response)
52 | throw new Error(errorMessage)
53 | }
54 |
55 | return response.json()
56 | } catch (error) {
57 | throw new Error(
58 | error.message || 'An error occurred during the fetch operation.'
59 | )
60 | }
61 | }
62 |
63 | async function getErrorMessage(response) {
64 | try {
65 | const error = await response.json()
66 | return (
67 | error.error ||
68 | error.message ||
69 | error.msg ||
70 | `Error occurred with response ${error.response}`
71 | )
72 | } catch (err) {
73 | return `Error occurred with response ${response.status} ${response.statusText}`
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/client/src/components/CompanyCard.js:
--------------------------------------------------------------------------------
1 | // assets
2 | import BigSmiley from '../static/ratings/BigSmiley.png'
3 | import smiley from '../static/ratings/smiley.png'
4 | import neutral from '../static/ratings/neutral.png'
5 | import frown from '../static/ratings/frown.png'
6 | import demon from '../static/ratings/demon.png'
7 |
8 | export const CompanyCard = ({ company }) => {
9 | const options = [demon, frown, neutral, smiley, BigSmiley]
10 |
11 | return (
12 |
13 |
14 |
18 |
19 |
20 | {company.name}
21 |
22 |
23 |
24 |
25 |
{company.info}
26 | {company.rating !== null ? (
27 |
28 |
29 | Rating:
30 |
31 |
35 |
36 |
40 |
41 |
42 |
43 | ) : (
44 |
45 | )}
46 |
47 |
48 | )
49 | }
50 |
--------------------------------------------------------------------------------
/client/public/logos/Yelp:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
9 |
13 |
17 |
21 |
25 |
26 |
--------------------------------------------------------------------------------
/server/middleware/profile.js:
--------------------------------------------------------------------------------
1 | const axios = require("axios");
2 | const jwt = require("jsonwebtoken");
3 | const Profile = require("../models/profileModel");
4 | const User = require("../models/userModel");
5 |
6 | const getProfileIdFromToken = async (token) => {
7 | try {
8 | // get decoded token
9 | const decodedToken = jwt.verify(token, process.env.JWT_SECRET);
10 |
11 | // extract linkedin token and use this as user identifier
12 | const linkedinToken = decodedToken.linkedinToken;
13 |
14 | // this request gets basic profile info from linkedin token
15 | const { data } = await axios.get("https://api.linkedin.com/v2/userinfo", {
16 | headers: {
17 | Authorization: `Bearer ${linkedinToken}`,
18 | },
19 | });
20 | const email = data.email;
21 |
22 | // Query MongoDB model to find user with matching email
23 | const user = await User.findOne({ email: email });
24 | if (!user) {
25 | throw Error(`User not found: ${email}`);
26 | }
27 |
28 | // Find profile using user's _id
29 | const profile = await Profile.findOne({ userId: user._id });
30 | if (!profile) {
31 | throw Error(`Profile not found for user: ${user._id}`);
32 | }
33 |
34 | // extract id from profile object
35 | const profileId = profile._id.toString();
36 |
37 | // return profile id
38 | return profileId;
39 | } catch (err) {
40 | console.error(err);
41 | return null;
42 | }
43 | };
44 |
45 | const verifyProfile = async (req, res, next) => {
46 | // Log the requested URL
47 | console.log("Requested URL:", req.originalUrl);
48 |
49 | const authHeader = req.headers.authorization;
50 |
51 | if (!authHeader) {
52 | return res.status(401).json({ msg: "No authorization token provided." });
53 | }
54 |
55 | const tokenParts = authHeader.split(" ");
56 | if (tokenParts.length !== 2 || tokenParts[0] !== "Bearer") {
57 | return res.status(401).json({ msg: "Token format is 'Bearer '." });
58 | }
59 |
60 | const token = tokenParts[1];
61 |
62 | // Extract the ID from the end of the URL path
63 | const idParts = req.originalUrl.split("/");
64 | const requestedProfileId = idParts[idParts.length - 1];
65 |
66 | const profileIdFromToken = await getProfileIdFromToken(token);
67 |
68 | if (!profileIdFromToken) {
69 | return res.status(401).json({ msg: "Invalid or expired token." });
70 | }
71 |
72 | if (profileIdFromToken !== requestedProfileId) {
73 | return res.status(403).json({
74 | msg: "Profile ID in the token does not match the requested profile ID.",
75 | });
76 | }
77 |
78 | next();
79 | };
80 |
81 | module.exports = {
82 | verifyProfile,
83 | };
84 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing Guidelines
2 |
3 | First off, thank you for considering contributing to Pipelines. We're still in the early stages of development and we're excited to have you join us on this journey. If you don't already know what Pipelines is, we recommend learning more about the project by visiting our [website](https://pipelines.lol). This will give you a better understanding of what we're trying to accomplish and build here.
4 |
5 | The following is a set of guidelines for contributing to Pipelines. These are mostly guidelines, not rules. Use your best judgment, and feel free to propose changes to this document in a pull request.
6 |
7 | _Pull requests, bug reports, and all other forms of contribution are welcomed and highly encouraged!_ :octocat:
8 |
9 | ### Contents
10 |
11 | - [Code of Conduct](#book-code-of-conduct)
12 | - [Opening an Issue](#inbox_tray-opening-an-issue)
13 | - [Reporting Security Issues](#lock-reporting-security-issues)
14 |
15 | > **This guide serves to set clear expectations for everyone involved with the project so that we can improve it together while also creating a welcoming space for everyone to participate in the development of Pipelines. Following these guidelines will help ensure a positive experience for contributors and maintainers.**
16 |
17 | ## :book: Code of Conduct
18 |
19 | Please review our [Code of Conduct](/CODE_OF_CONDUCT.md). It is in effect at all times. We expect it to be honored by everyone who contributes to this project. Acting in accordance with this code is a requirement for contributing to the project.
20 |
21 | ## :inbox_tray: Opening an Issue
22 |
23 | Before [creating an issue](https://help.github.com/en/github/managing-your-work-on-github/creating-an-issue), confirm that a similar issue has not already been reported. If you find a closed issue that seems to be the same as the one you're experiencing, open a new issue and link to the original issue in the body of your new one.
24 |
25 | When creating an issue, please provide as much detail as possible. This includes:
26 |
27 | - A clear and descriptive title
28 | - A detailed description of the issue
29 | - Steps to reproduce the issue
30 | - Expected behavior
31 | - Actual behavior
32 | - Screenshots, if applicable
33 | - Any other relevant information
34 |
35 | ### :lock: Reporting Security Issues
36 |
37 | **Do not** file a public issue for security vulnerabilities. Instead, please email **support@pipelines.lol**. This will help ensure that any vulnerabilities that are found are addressed as quickly as possible. If you are not sure whether you are dealing with a security issue, please err on the side of caution, and report it via email.
38 |
39 | # TODO: Finish this document
40 |
--------------------------------------------------------------------------------
/client/src/components/landing/Marquee.js:
--------------------------------------------------------------------------------
1 | import { companies } from '../../data/companyData'
2 |
3 | const LogoMarquee = () => {
4 | const logos = Array.from(
5 | { length: 30 },
6 | () => companies[Math.floor(Math.random() * companies.length)]
7 | )
8 | return (
9 | <>
10 |
11 |
12 | {logos.map((logo, index) => (
13 |
14 |
19 |
20 | ))}
21 |
22 |
26 | {logos.map((logo, index) => (
27 |
28 |
33 |
34 | ))}
35 |
36 |
37 | >
38 | )
39 | }
40 |
41 | const SlidingImages = () => {
42 | return (
43 | <>
44 |
45 |
46 | Pipelines is Trusted by Engineers at Top Tech Companies
47 |
48 |
49 |
50 | >
51 | )
52 | }
53 |
54 | export default SlidingImages
55 |
--------------------------------------------------------------------------------
/client/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "client",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@formkit/auto-animate": "^0.8.1",
7 | "@fortawesome/fontawesome-svg-core": "^6.5.1",
8 | "@fortawesome/free-solid-svg-icons": "^6.5.1",
9 | "@fortawesome/react-fontawesome": "^0.2.0",
10 | "@testing-library/jest-dom": "^5.17.0",
11 | "@testing-library/react": "^13.4.0",
12 | "@testing-library/user-event": "^13.5.0",
13 | "aws-sdk": "^2.1532.0",
14 | "daisyui": "^4.6.0",
15 | "dotenv": "^16.3.1",
16 | "flowbite": "^2.3.0",
17 | "flowbite-react": "^0.8.0",
18 | "framer-motion": "^10.18.0",
19 | "js-cookie": "^3.0.5",
20 | "lucide-react": "^0.307.0",
21 | "react": "^18.2.0",
22 | "react-dom": "^18.2.0",
23 | "react-loader-spinner": "^6.1.6",
24 | "react-router-dom": "^6.21.2",
25 | "react-scripts": "5.0.1",
26 | "tailwind-datepicker-react": "^1.4.3",
27 | "tailwind-merge": "^2.2.0",
28 | "web-vitals": "^2.1.4"
29 | },
30 | "scripts": {
31 | "start": "react-scripts start",
32 | "build": "react-scripts build",
33 | "test": "react-scripts test",
34 | "eject": "react-scripts eject",
35 | "lint": "eslint \"src/**/*.{js,jsx}\"",
36 | "format": "prettier --write \"src/**/*.{js,jsx}\"",
37 | "lint:fix": "eslint --fix \"src/**/*.{js,jsx}\""
38 | },
39 | "eslintConfig": {
40 | "extends": [
41 | "react-app",
42 | "react-app/jest"
43 | ]
44 | },
45 | "browserslist": {
46 | "production": [
47 | ">0.2%",
48 | "not dead",
49 | "not op_mini all"
50 | ],
51 | "development": [
52 | "last 1 chrome version",
53 | "last 1 firefox version",
54 | "last 1 safari version"
55 | ]
56 | },
57 | "devDependencies": {
58 | "@babel/plugin-proposal-private-property-in-object": "^7.21.11",
59 | "eslint": "^8.56.0",
60 | "eslint-config-airbnb": "^19.0.4",
61 | "eslint-config-prettier": "^9.1.0",
62 | "eslint-config-standard": "^17.1.0",
63 | "eslint-plugin-import": "^2.29.1",
64 | "eslint-plugin-jsx-a11y": "^6.8.0",
65 | "eslint-plugin-n": "^16.6.2",
66 | "eslint-plugin-prettier": "^5.1.3",
67 | "eslint-plugin-promise": "^6.1.1",
68 | "eslint-plugin-react": "^7.33.2",
69 | "eslint-plugin-react-hooks": "^4.6.0",
70 | "prettier": "^3.2.4",
71 | "prettier-plugin-tailwindcss": "^0.5.11",
72 | "tailwindcss": "^3.3.7"
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/client/src/hooks/useValidateExperience.js:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from 'react'
2 |
3 | const useValidateExperience = (experience) => {
4 | const [companyName, setCompanyName] = useState('')
5 | const [displayName, setDisplayName] = useState('')
6 | const [title, setTitle] = useState('')
7 | const [startDate, setStartDate] = useState('')
8 | const [endDate, setEndDate] = useState('')
9 | const [isIndefinite, setIsIndefinite] = useState(false)
10 | const [rating, setRating] = useState(0)
11 | const [selectedOption, setSelectedOption] = useState(1)
12 | const [companyId, setCompanyId] = useState('')
13 | const [first, setFirst] = useState(true)
14 | const [globalId, setId] = useState(0)
15 | const [logo, setLogo] = useState('')
16 |
17 | // initialize experience if one exists
18 | useEffect(() => {
19 | if (experience) {
20 | // Set basic experience details
21 | setCompanyName(experience.companyName)
22 | setDisplayName(experience.displayName)
23 | setTitle(experience.title)
24 | setCompanyId(experience.companyId)
25 | setRating(experience.rating)
26 | setSelectedOption(experience.rating / 20)
27 | setIsIndefinite(experience.isIndefinite)
28 |
29 | // Set ID and logo, with default values if not provided
30 | setId(experience.tempId2 || 0)
31 | setLogo(experience.logo || '')
32 |
33 | // Initialize startDate and endDate
34 | let startDate = ''
35 | let endDate = ''
36 |
37 | // Set startDate if provided
38 | if (experience.startDate) {
39 | startDate = new Date(experience.startDate)
40 | }
41 |
42 | // Set endDate if provided and not indefinite
43 | if (experience.endDate && !experience.isIndefinite) {
44 | endDate = new Date(experience.endDate)
45 | }
46 |
47 | // Update state with calculated startDate and endDate
48 | setStartDate(startDate)
49 | setEndDate(endDate)
50 | }
51 | }, [experience])
52 |
53 | return {
54 | globalId,
55 | companyName,
56 | displayName,
57 | companyId,
58 | title,
59 | startDate,
60 | endDate,
61 | isIndefinite,
62 | rating,
63 | selectedOption,
64 | first,
65 | logo,
66 | setCompanyName,
67 | setDisplayName,
68 | setCompanyId,
69 | setTitle,
70 | setIsIndefinite,
71 | setSelectedOption,
72 | setRating,
73 | setFirst,
74 | setStartDate,
75 | setEndDate,
76 | setId,
77 | setLogo,
78 | }
79 | }
80 |
81 | export default useValidateExperience
82 |
--------------------------------------------------------------------------------
/client/src/pages/Code.js:
--------------------------------------------------------------------------------
1 | import { useNavigate } from 'react-router-dom'
2 | import { useEarlyAccess } from '../hooks/useEarlyAccess'
3 | import { useState } from 'react'
4 |
5 | import { HOST } from '../util/apiRoutes'
6 | import { fetchWithAuth } from '../util/fetchUtils'
7 |
8 | function Code() {
9 | const [code, setCode] = useState()
10 |
11 | const [errorMessage, setErrorMessage] = useState('')
12 |
13 | const navigate = useNavigate()
14 | const { setAccess } = useEarlyAccess()
15 |
16 | const handleSubmit = async (e) => {
17 | e.preventDefault()
18 |
19 | // authentication
20 | try {
21 | await fetchWithAuth({
22 | url: `${HOST}/api/earlyAccess/check`,
23 | method: 'POST',
24 | data: { code },
25 | })
26 |
27 | setAccess(true)
28 | navigate('/')
29 | } catch (error) {
30 | console.error('Error:', error.message)
31 | setErrorMessage(error.message)
32 | setAccess(false)
33 | }
34 | }
35 |
36 | return (
37 |
47 |
48 | {/* Input field for code */}
49 |
50 |
68 |
69 |
70 | {errorMessage &&
{errorMessage}
}
71 |
72 |
73 | )
74 | }
75 |
76 | export default Code
77 |
--------------------------------------------------------------------------------
/client/src/components/TitleQuerySearchInput.js:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from 'react'
2 | import { titles } from '../data/companyData'
3 |
4 | export const TitleQuerySearchInput = ({ value, handleSearch }) => {
5 | const [query, setQuery] = useState('')
6 | const [results, setResults] = useState([])
7 | const hasResults = results.length > 0
8 |
9 | // initialize company if one exists
10 | useEffect(() => {
11 | // reset query before checking if theres a previous value
12 | setQuery('')
13 |
14 | // check if there was a previous value
15 | // if there was, set query to it
16 | if (value) {
17 | setQuery(value)
18 | }
19 | }, [value])
20 |
21 | const handleInputChange = async (event) => {
22 | const inputValue = event.target.value
23 | setQuery(inputValue)
24 |
25 | // make sure theres an input before querying
26 | if (inputValue.length > 0) {
27 | const filteredCompanies = titles.filter((title) =>
28 | title.toLowerCase().startsWith(inputValue.toLowerCase())
29 | )
30 | setResults(filteredCompanies)
31 | } else {
32 | setResults([])
33 | }
34 |
35 | await handleSearch(inputValue)
36 | }
37 |
38 | const handleTitleButtonClick = async (title) => {
39 | // reset text input
40 | setQuery(title)
41 | setResults([])
42 |
43 | await handleSearch(title)
44 | }
45 |
46 | return (
47 | <>
48 |
83 | >
84 | )
85 | }
86 |
--------------------------------------------------------------------------------
/client/src/components/DatePicker.js:
--------------------------------------------------------------------------------
1 | import { useEffect, useState, useRef } from 'react'
2 | import Datepicker from 'tailwind-datepicker-react'
3 | import { ArrowLeft, ArrowRight } from 'lucide-react'
4 |
5 | const options = {
6 | autoHide: true,
7 | todayBtn: false,
8 | clearBtn: true,
9 | clearBtnText: 'Clear',
10 | maxDate: new Date('2030-01-01'),
11 | minDate: new Date('1950-01-01'),
12 | theme: {
13 | background: 'bg-gray-700',
14 | todayBtn: '',
15 | clearBtn: '',
16 | icons: 'bg-gray-700 text-white hover:bg-opacity-20',
17 | text: 'text-white hover:bg-opacity-20',
18 | disabledText: '',
19 | input: '',
20 | inputIcon: '',
21 | selected: 'bg-pipeline-blue-200 hover:bg-opacity-80',
22 | },
23 | icons: {
24 | // () => ReactElement | JSX.Element
25 | prev: () => ,
26 | next: () => ,
27 | },
28 | datepickerClassNames: 'top-32 right-10',
29 | language: 'en',
30 | disabledDates: [],
31 | inputNameProp: 'date',
32 | inputIdProp: 'date',
33 | inputPlaceholderProp: 'Select Date ',
34 | inputDateFormatProp: {
35 | day: 'numeric',
36 | month: 'long',
37 | year: 'numeric',
38 | },
39 | }
40 |
41 | export const DatePicker = ({ value, onChange }) => {
42 | const [date, setDate] = useState(value || null)
43 | const [show, setShow] = useState(false)
44 | const wrapperRef = useRef(null)
45 |
46 | const handleChange = (selectedDate) => {
47 | setDate(selectedDate)
48 | onChange(selectedDate)
49 | }
50 | const handleClose = (state) => {
51 | setShow(state)
52 | }
53 |
54 | useEffect(() => {
55 | if (value) {
56 | setDate(value)
57 | }
58 | }, [value])
59 |
60 | useEffect(() => {
61 | function handleClickOutside(event) {
62 | if (
63 | wrapperRef.current &&
64 | !wrapperRef.current.contains(event.target)
65 | ) {
66 | setShow(false)
67 | }
68 | }
69 | document.addEventListener('mousedown', handleClickOutside)
70 | return () => {
71 | document.removeEventListener('mousedown', handleClickOutside)
72 | }
73 | }, [wrapperRef])
74 |
75 | return (
76 |
77 |
84 | setShow(true)}
98 | readOnly
99 | />
100 |
101 |
102 | )
103 | }
104 |
--------------------------------------------------------------------------------
/server/controllers/pfpController.js:
--------------------------------------------------------------------------------
1 | const Profile = require('../models/profileModel')
2 | const mongoose = require('mongoose')
3 | const crypto = require('crypto')
4 |
5 | // const sharp = require('sharp')
6 |
7 | const { S3Client, PutObjectCommand, GetObjectCommand } = require('@aws-sdk/client-s3')
8 | const { getSignedUrl } = require('@aws-sdk/s3-request-presigner')
9 |
10 | const randomImageName = (bytes = 32) => crypto.randomBytes(bytes).toString('hex')
11 |
12 | const BUCKET_NAME = process.env.BUCKET_NAME
13 | const BUCKET_REGION = process.env.BUCKET_REGION
14 | const AWS_ACCESS_KEY_ID = process.env.AWS_ACCESS_KEY_ID
15 | const AWS_SECRET_ACCESS_KEY = process.env.AWS_SECRET_ACCESS_KEY
16 |
17 | const s3 = new S3Client({
18 | credentials: {
19 | accessKeyId: AWS_ACCESS_KEY_ID,
20 | secretAccessKey: AWS_SECRET_ACCESS_KEY,
21 | },
22 | region: BUCKET_REGION
23 | })
24 |
25 | const isLinkedInImage = (pfp) => {
26 | const linkedInImageRegex = /^https:\/\/media\.licdn\.com\/dms\/image\/.+$/;
27 |
28 | return linkedInImageRegex.test(pfp);
29 | };
30 |
31 | const getPfp = async (req, res) => {
32 | const { id } = req.params
33 |
34 | const profile = await Profile.findById(id);
35 |
36 | if (!profile) {
37 | return res.status(404).json({ error: 'No such Profile.' });
38 | }
39 |
40 | const pfp = profile.pfp
41 |
42 | if (!pfp) {
43 | return res.status(404).json({ error: 'No such profile picture.' });
44 | } else if (pfp === "") {
45 | return res.status(200).json({ pfp: "" });
46 | }
47 |
48 | if (isLinkedInImage(pfp)) {
49 | return res.status(200).json({ pfp: pfp });
50 | }
51 |
52 | const getObjectParams = {
53 | Bucket: BUCKET_NAME,
54 | Key: pfp
55 | }
56 |
57 | const command = new GetObjectCommand(getObjectParams)
58 | const url = await getSignedUrl(s3, command, { expiresIn: 3600 })
59 |
60 | res.status(200).json({ pfp: url });
61 | }
62 |
63 | const updatePfp = async (req, res) => {
64 | const { id } = req.params
65 |
66 | let profile = await Profile.findOne({ _id: id });
67 |
68 | if (!profile) {
69 | return res.status(404).json({ error: 'No such Profile.' });
70 | }
71 |
72 | // if there is no file, then no changes will be made
73 | if (!req.file) {
74 | return res.status(200).json(profile);
75 | }
76 | let { buffer, mimetype } = req.file
77 |
78 | // resize image
79 | // const buffer = sharp(buffer).resize({
80 | // height: 320,
81 | // width: 320,
82 | // fit: "contain"
83 | // }).toBuffer()
84 |
85 | let imageName;
86 | if (profile.pfp === "") {
87 | imageName = randomImageName()
88 | } else {
89 | imageName = profile.pfp
90 | }
91 |
92 | const params = {
93 | Bucket: BUCKET_NAME,
94 | Key: imageName,
95 | Body: buffer,
96 | ContentType: mimetype
97 | }
98 |
99 | const command = new PutObjectCommand(params)
100 | await s3.send(command)
101 |
102 | // save image name (key) to mongodb
103 | const pfpData = { pfp: imageName }
104 | profile = await Profile.findOneAndUpdate({ _id: id }, pfpData, { new: true });
105 |
106 | if (!profile) {
107 | return res.status(404).json({ error: 'No such Profile.' });
108 | }
109 |
110 | res.status(200).json(profile);
111 | }
112 |
113 | module.exports = {
114 | getPfp,
115 | updatePfp
116 | }
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, sex characteristics, gender identity and expression,
9 | level of experience, education, socio-economic status, nationality, personal
10 | appearance, race, religion, or sexual identity and orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | - Using welcoming and inclusive language
18 | - Being respectful of differing viewpoints and experiences
19 | - Gracefully accepting constructive criticism
20 | - Focusing on what is best for the community
21 | - Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | - The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | - Trolling, insulting/derogatory comments, and personal or political attacks
28 | - Public or private harassment
29 | - Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | - Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at **support@pipelines.lol**. All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72 |
73 | [homepage]: https://www.contributor-covenant.org
74 |
75 | For answers to common questions about this code of conduct, see
76 | https://www.contributor-covenant.org/faq
77 |
--------------------------------------------------------------------------------
/client/src/components/QuerySearchInput.js:
--------------------------------------------------------------------------------
1 | import { useState } from 'react'
2 |
3 | import { HOST } from '../util/apiRoutes'
4 | import { fetchWithAuth } from '../util/fetchUtils'
5 |
6 | export const QuerySearchInput = ({ handleSearch }) => {
7 | const [query, setQuery] = useState('')
8 | const [results, setResults] = useState([])
9 | const hasResults = results.length > 0
10 |
11 | const handleInputChange = async (event) => {
12 | const inputValue = event.target.value
13 | setQuery(inputValue)
14 |
15 | // make sure theres an input before querying
16 | if (inputValue.length > 0) {
17 | try {
18 | const data = await fetchWithAuth({
19 | url: `${HOST}/api/company/get/companies/${inputValue.toLowerCase()}`,
20 | method: 'GET',
21 | })
22 |
23 | setResults(data)
24 | } catch (error) {
25 | console.error(error.message)
26 | }
27 | } else {
28 | setResults([])
29 | }
30 | }
31 |
32 | const handleCompanyButtonClick = async (company) => {
33 | // reset text input
34 | setQuery(company.displayName)
35 | setResults([])
36 |
37 | await handleSearch(company)
38 | }
39 |
40 | return (
41 | <>
42 |
82 | >
83 | )
84 | }
85 |
--------------------------------------------------------------------------------
/client/src/components/landing/CTA.js:
--------------------------------------------------------------------------------
1 | import { useNavigate } from 'react-router-dom'
2 | import { HOMEPAGE } from '../../util/apiRoutes'
3 | import { CLIENT_ID, SCOPE } from '../../util/linkedinUtils'
4 | import { useAuthContext } from '../../hooks/useAuthContext'
5 |
6 | export default function CTA() {
7 | const navigate = useNavigate()
8 | const { user } = useAuthContext()
9 | const linkedinRedirectUrl = `https://linkedin.com/oauth/v2/authorization?client_id=${CLIENT_ID}&response_type=code&scope=${SCOPE}&redirect_uri=${HOMEPAGE}`
10 |
11 | const handleNavigation = () => {
12 | if (user) {
13 | navigate('/edit')
14 | } else {
15 | window.location.href = linkedinRedirectUrl
16 | }
17 | }
18 |
19 | return (
20 | <>
21 |
76 | >
77 | )
78 | }
79 |
--------------------------------------------------------------------------------
/client/src/App.js:
--------------------------------------------------------------------------------
1 | // App.js
2 | import {
3 | Route,
4 | BrowserRouter as Router,
5 | Routes,
6 | useLocation,
7 | } from 'react-router-dom'
8 | import './App.css'
9 |
10 | // Components
11 | import Footer from './components/Footer'
12 | import Navbar from './components/Navbar'
13 |
14 | // Pages
15 | import Discover from './pages/Discover'
16 | import EditProfile from './pages/EditProfile'
17 | import Home from './pages/Home'
18 | import Login from './pages/Login'
19 | import Profile from './pages/Profile'
20 | import Search from './pages/Search'
21 | import Signup from './pages/Signup'
22 | import Suggestions from './pages/Suggestions'
23 | import Company from './pages/Company'
24 | import School from './pages/School'
25 | import Admin from './pages/(admin)/Admin'
26 |
27 | // Context
28 | import { useAuthContext } from './hooks/useAuthContext'
29 | import { useEarlyAccess } from './hooks/useEarlyAccess'
30 | import { error404 } from './components/Error404'
31 | import Newsletter from './pages/Newsletter'
32 | import Code from './pages/Code'
33 |
34 | // Navbar Component
35 | function AppNavbar() {
36 | return
37 | }
38 |
39 | // Footer Component
40 | function AppFooter() {
41 | return
42 | }
43 |
44 | // Routes Component
45 | function AppRoutes({ user }) {
46 | const routes = [
47 | { path: '/', element: },
48 | { path: '/search', element: },
49 | { path: '/login', element: },
50 | { path: '/signup', element: },
51 | { path: '/discover', element: },
52 | {
53 | path: '/edit',
54 | element: user && ,
55 | },
56 | { path: '/user/:id', element: },
57 | { path: '/company/:id', element: },
58 | { path: '/school/:id', element: },
59 | { path: '/suggestions', element: },
60 | { path: '/admin/*', element: },
61 | {
62 | path: '/*',
63 | element: error404("We couldn't find the page you are looking for."),
64 | },
65 | ]
66 |
67 | const { earlyAccess } = useEarlyAccess()
68 |
69 | return (
70 |
71 | {earlyAccess ? (
72 | routes.map(({ path, element }, index) => (
73 |
74 | ))
75 | ) : (
76 | <>
77 | } />
78 | {routes.map(({ path }, index) => (
79 | }
83 | />
84 | ))}
85 | >
86 | )}
87 |
88 | )
89 | }
90 |
91 | // Wrapper for Navbar and Footer
92 | const NavigationWrapper = ({ children }) => {
93 | const location = useLocation()
94 | const isAdminRoute = location.pathname.startsWith('/admin/')
95 |
96 | const { earlyAccess } = useEarlyAccess()
97 |
98 | return (
99 |
100 | {!isAdminRoute && earlyAccess &&
}
101 | {children}
102 | {!isAdminRoute && earlyAccess &&
}
103 |
104 | )
105 | }
106 |
107 | // Main App Component
108 | function App() {
109 | const { user } = useAuthContext()
110 |
111 | return (
112 |
113 |
118 |
119 | )
120 | }
121 |
122 | export default App
123 |
--------------------------------------------------------------------------------
/server/controllers/schoolController.js:
--------------------------------------------------------------------------------
1 | const fetch = require("node-fetch");
2 | const School = require("../models/schoolModel");
3 |
4 | const createSchool = async (req, res) => {
5 | if (!req.body.name) {
6 | return res.status(400).json({ error: "No company name given." });
7 | }
8 |
9 | try {
10 | const {
11 | name,
12 | domains,
13 | state_province,
14 | country,
15 | alpha_two_code,
16 | web_pages,
17 | } = req.body; //pull school values from the request body
18 |
19 | const newSchool = new School({
20 | name: name,
21 | domains: domains,
22 | state_province: state_province,
23 | country: country,
24 | alpha_two_code: alpha_two_code,
25 | web_pages: web_pages,
26 | companyTally: {},
27 | }); // Create New School object
28 |
29 | const savedSchool = await newSchool.save();
30 | console.log("New School Created: ", savedSchool.name);
31 | console.log(savedSchool);
32 | } catch (err) {
33 | console.error(err);
34 | res.status(500).json();
35 | }
36 | };
37 |
38 | const searchSchools = async (req, res) => {
39 | const { query } = req.params;
40 |
41 | try {
42 | // Create a regular expression to find documents that start with the query
43 | const regex = new RegExp("^" + query, "i"); // "i" for case-insensitive search
44 |
45 | // Find companies that match the regex
46 | const schools = await School.find({ name: regex });
47 |
48 | res.status(200).json(schools);
49 | } catch (err) {
50 | return res.status(400).json({ error: "Failed to retrieve schools" });
51 | }
52 | };
53 |
54 | const getSchool = async (req, res) => {
55 | const { id } = req.params;
56 | try {
57 | const school = await School.findOne({ _id: id });
58 | if (!school) res.status(404).json({ message: "School not found" });
59 | res.status(200).json(school);
60 | } catch (err) {
61 | return res.status(400).json({ error: "Failed to retrieve school " });
62 | }
63 | };
64 |
65 | const updateSchool = async (req, res) => {
66 | const { id } = req.params;
67 | const schoolArray = req.body;
68 | const newSchool = schoolArray[0];
69 | const oldSchool = schoolArray[1];
70 | try {
71 | const newUpdateData = {
72 | $inc: {},
73 | };
74 |
75 | const oldUpdateData = {
76 | $inc: {},
77 | };
78 |
79 | //update school tally
80 | if (id !== oldSchool) {
81 | //up
82 | for (let i = 0; i < newSchool.schoolTally.length; i++) {
83 | newUpdateData.$inc[`schoolTally.${newSchool.schoolTally[i]}`] = 1;
84 | oldUpdateData.$inc[`schoolTally.${newSchool.schoolTally[i]}`] = -1;
85 | }
86 | }
87 | //update new school
88 | const newResponse = await School.updateOne({ _id: id }, newUpdateData);
89 | if (!newResponse) res.status(404).json({ message: "School not found" });
90 |
91 | //update old school
92 | const oldResponse = await School.updateOne(
93 | { _id: oldSchool },
94 | oldUpdateData
95 | );
96 | if (!oldResponse) res.status(404).json({ message: "School not found" });
97 | console.log(`School updated ${newSchool.schoolId}`);
98 | res.status(200).json({ message: "School updated" });
99 | } catch (err) {
100 | console.error(err);
101 | return res.status(500).json({ error: "Failed to retrieve school" });
102 | }
103 | };
104 |
105 | const deleteSchool = async (req, res) => {
106 | const { id } = req.params;
107 | const result = await School.findOneAndDelete({
108 | _id: id,
109 | });
110 |
111 | if (!result) {
112 | return res.status(404).json({ error: "No such school." });
113 | }
114 |
115 | console.log("School Deleted: ", id);
116 | console.log(result);
117 |
118 | res.status(200).json(result);
119 | };
120 |
121 | module.exports = {
122 | searchSchools,
123 | getSchool,
124 | updateSchool,
125 | deleteSchool,
126 | createSchool,
127 | };
128 |
--------------------------------------------------------------------------------
/client/src/components/ExperienceQuerySearchInput.js:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from 'react'
2 |
3 | import { HOST } from '../util/apiRoutes'
4 | import { fetchWithAuth } from '../util/fetchUtils'
5 |
6 | export const ExperienceQuerySearchInput = ({ value, handleSearch }) => {
7 | const [query, setQuery] = useState('')
8 | const [results, setResults] = useState([])
9 | const hasResults = results.length > 0
10 |
11 | // initialize company if one exists
12 | useEffect(() => {
13 | // reset query before checking if theres a previous value
14 | setQuery('')
15 |
16 | // check if there was a previous value
17 | // if there was, set query to it
18 | if (value) {
19 | setQuery(value.displayName)
20 | }
21 | }, [value])
22 |
23 | const handleInputChange = async (event) => {
24 | const inputValue = event.target.value
25 | setQuery(inputValue.name)
26 |
27 | // make sure theres an input before querying
28 | if (inputValue.length > 0) {
29 | try {
30 | const data = await fetchWithAuth({
31 | url: `${HOST}/api/company/get/companies/${inputValue.toLowerCase()}`,
32 | method: 'GET',
33 | })
34 | setResults(data)
35 | } catch (error) {
36 | console.error(error.message)
37 | }
38 | } else {
39 | setResults([])
40 |
41 | await handleSearch('')
42 | }
43 | }
44 |
45 | const handleCompanyButtonClick = async (company) => {
46 | // reset text input
47 | setQuery(company.displayName)
48 | setResults([])
49 |
50 | await handleSearch(company)
51 | }
52 |
53 | return (
54 | <>
55 |
95 | >
96 | )
97 | }
98 |
--------------------------------------------------------------------------------
/client/src/components/landing/About.js:
--------------------------------------------------------------------------------
1 | import { motion, useInView } from 'framer-motion'
2 | import { useRef } from 'react'
3 | import Timeline from './Timeline'
4 |
5 | export default function About() {
6 | const ref = useRef(null)
7 | const ref2 = useRef(null)
8 | const inView = useInView(ref)
9 | const inView2 = useInView(ref2)
10 | const parent = {
11 | hidden: {
12 | opacity: 0,
13 | y: 50,
14 | },
15 | visible: {
16 | opacity: 1,
17 | y: 0,
18 | transition: {
19 | duration: 0.5,
20 | ease: 'easeInOut',
21 | },
22 | },
23 | }
24 | return (
25 | <>
26 |
27 |
28 |
29 | What is a pipeline?
30 |
31 |
32 |
39 | A pipeline is a collection of experiences that
40 | individuals embark on throughout their career.
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | Think of a pipeline as a roadmap of
49 | internships, jobs, and other
50 | opportunities that you can take to reach
51 | your career goals.
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
68 |
69 | With{' '}
70 |
71 | pipelines.lol
72 |
73 | , gain insights, draw inspiration, and chart your course
74 | by discovering the diverse destinations that await along
75 | your very own career pipeline.
76 |
77 |
78 |
79 |
80 |
85 |
86 |
87 | >
88 | )
89 | }
90 |
--------------------------------------------------------------------------------
/server/emails/welcome.js:
--------------------------------------------------------------------------------
1 | const { HOMEPAGE } = require("../utils/apiRoutes");
2 |
3 | const config = {
4 | welcome: `
5 |
6 |
7 | Welcome Onboard!
8 |
9 |
10 |
11 |
12 |
13 | Welcome to Pipelines!
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | Hello, and welcome!
22 |
23 |
24 |
25 |
26 | You've just taken the first step to streamline your career with our platform. Get ready to unlock all the features and benefits we offer. We're thrilled to have you on board.
27 |
28 |
29 |
30 |
31 | If you have the secret code for alpha testing, please enter it by clicking the button below.
32 |
33 |
34 |
35 |
36 | Secret...
37 |
38 |
39 |
40 |
41 | If you have any questions or need assistance getting started, our support team is here to help. Reach out to us anytime at support@pipelines.lol .
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 | You're receiving this email because you recently subscribed to our newsletter. If you didn't sign up for this newsletter, please ignore this email.
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 | © 2024 pipelines.lol. All rights reserved.
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 | `,
72 | };
73 |
74 | module.exports = config;
75 |
--------------------------------------------------------------------------------
/server/index.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 |
3 | const dotenv = require("dotenv");
4 | const mongoose = require("mongoose");
5 | const cors = require("cors");
6 | const bodyParser = require("body-parser");
7 |
8 | // middleware
9 | const { verifyToken } = require("./middleware/token");
10 | const { verifyProfile } = require("./middleware/profile");
11 | const { verifyAdmin } = require("./middleware/admin");
12 | const { verifyUser } = require("./middleware/user");
13 |
14 | // route imports
15 | const authRoutes = require("./routes/auth");
16 | const profileRoutes = require("./routes/profiles");
17 | const schoolRoutes = require("./routes/school");
18 | const companyRoutes = require("./routes/companies");
19 | const mongodbIdRoutes = require("./routes/mongodbId");
20 | const offerRoutes = require("./routes/offers");
21 | const pfpRoutes = require("./routes/pfps");
22 | const imageModerationRoutes = require("./routes/imageModeration");
23 | const adminRoutes = require("./routes/admin");
24 | const emailRoutes = require("./routes/emails");
25 | const earlyAccessRoutes = require("./routes/earlyAccess");
26 | const tokenRoutes = require("./routes/token");
27 |
28 | dotenv.config();
29 |
30 | const app = express();
31 | const PORT = process.env.PORT || 4000;
32 | const API_URL = process.env.API_URL;
33 |
34 | // cors
35 | const corsOptions = {
36 | origin: [
37 | "http://localhost:3000",
38 | API_URL,
39 | "https://pipelineslol.netlify.app",
40 | "https://pipelines.lol",
41 | "https://www.pipelines.lol",
42 | "https://linkedin.com",
43 | ],
44 | methods: ["POST", "PATCH", "DELETE", "GET"],
45 | credentials: true,
46 | };
47 | app.use(cors(corsOptions));
48 |
49 | // body parser
50 | app.use(
51 | bodyParser.urlencoded({
52 | extended: true,
53 | })
54 | );
55 |
56 | app.use(bodyParser.json());
57 |
58 | // database
59 | mongoose
60 | .connect(process.env.DB_CONNECT)
61 | .then(() => console.log("Successfully connected to database."))
62 | .catch((err) => console.log(err));
63 |
64 | app.use(express.json());
65 |
66 | // testing
67 | app.get("/", (req, res) => {
68 | res.json("Hello! This is the Pipelines API!");
69 | });
70 |
71 | // routes
72 | const routes = [
73 | { path: "/api/user", middleware: [verifyToken], handler: authRoutes },
74 | {
75 | path: "/api/profile",
76 | middleware: [verifyToken],
77 | handler: profileRoutes.read,
78 | },
79 | {
80 | path: "/api/profile",
81 | middleware: [verifyToken, verifyProfile],
82 | handler: profileRoutes.write,
83 | },
84 | {
85 | path: "/api/school/create",
86 | middleware: [verifyToken, verifyAdmin],
87 | handler: schoolRoutes.write,
88 | },
89 | {
90 | path: "/api/school/delete/:id",
91 | middleware: [verifyToken, verifyAdmin],
92 | handler: schoolRoutes.write,
93 | },
94 | {
95 | path: "/api/school",
96 | middleware: [verifyToken],
97 | handler: schoolRoutes.read,
98 | },
99 | {
100 | path: "/api/company",
101 | middleware: [verifyToken],
102 | handler: companyRoutes.read,
103 | },
104 | {
105 | path: "/api/company",
106 | middleware: [verifyToken, verifyAdmin],
107 | handler: companyRoutes.write,
108 | },
109 | {
110 | path: "/api/mongodbId",
111 | middleware: [verifyToken],
112 | handler: mongodbIdRoutes,
113 | },
114 | { path: "/api/pfp", middleware: [verifyToken], handler: pfpRoutes },
115 | {
116 | path: "/api/imageModeration",
117 | middleware: [verifyToken],
118 | handler: imageModerationRoutes,
119 | },
120 | { path: "/api/offer", middleware: [verifyToken], handler: offerRoutes },
121 | { path: "/api/email", middleware: [verifyToken], handler: emailRoutes.read },
122 | {
123 | path: "/api/email",
124 | middleware: [verifyToken, verifyAdmin],
125 | handler: emailRoutes.write,
126 | },
127 | {
128 | path: "/api/earlyAccess",
129 | middleware: [verifyToken],
130 | handler: earlyAccessRoutes,
131 | },
132 |
133 | // admin routes
134 | { path: "/api/admin", middleware: [verifyToken], handler: adminRoutes },
135 |
136 | { path: "/api/token", handler: tokenRoutes }, // no verification, this is needed for verification
137 | ];
138 |
139 | routes.forEach(({ path, middleware, handler }) => {
140 | if (middleware) app.use(path, middleware, handler);
141 | else app.use(path, handler);
142 | });
143 |
144 | const server = app.listen(PORT, () => console.log("Server is running."));
145 |
146 | module.exports = { app, server };
147 |
--------------------------------------------------------------------------------
/client/src/pages/Newsletter.js:
--------------------------------------------------------------------------------
1 | import { useState } from 'react'
2 | import { useNavigate } from 'react-router-dom'
3 |
4 | import { HOST } from '../util/apiRoutes'
5 | import { fetchWithAuth } from '../util/fetchUtils'
6 |
7 | // assets
8 | import { Check, Loader2 } from 'lucide-react'
9 |
10 | function Newsletter() {
11 | const [email, setEmail] = useState('')
12 |
13 | const [loading, setLoading] = useState(false)
14 | const [success, setSuccess] = useState(false)
15 | const [errorMessage, setErrorMessage] = useState('')
16 |
17 | const navigate = useNavigate()
18 |
19 | const handleSubmit = async (e) => {
20 | e.preventDefault()
21 |
22 | // Disable the submit button to prevent spamming
23 | e.target.disabled = true
24 |
25 | setLoading(true)
26 |
27 | // email logic
28 | try {
29 | await fetchWithAuth({
30 | url: `${HOST}/api/email/newsletter`,
31 | method: 'POST',
32 | data: { email },
33 | })
34 |
35 | // If fetchWithAuth doesn't throw, it means the response was ok
36 | setSuccess(true)
37 | } catch (error) {
38 | setErrorMessage(
39 | error.message || 'Email failed to subscribe. Please try again.'
40 | )
41 | } finally {
42 | setLoading(false)
43 |
44 | // Re-enable the submit button after a certain delay (e.g., 3 seconds)
45 | setTimeout(() => {
46 | e.target.disabled = false
47 | }, 3000) // 3 seconds delay before re-enabling the button
48 | }
49 | }
50 |
51 | return (
52 |
62 |
63 | {/* Hero */}
64 |
65 | Pipelines
66 |
67 | Coming Soon
68 |
69 |
70 |
71 |
72 | Signup for our newsletter to receive information on when we
73 | launch!
74 |
75 |
76 | {/* Input field for email */}
77 |
78 |
102 |
103 |
104 | {errorMessage &&
{errorMessage}
}
105 |
106 | {/* Grayed-out link for the secret code */}
107 |
navigate('/code')}>
108 |
109 | I have a secret code!
110 |
111 |
112 |
113 |
114 | )
115 | }
116 |
117 | export default Newsletter
118 |
--------------------------------------------------------------------------------
/client/src/components/PipelineDisplay.js:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from 'react'
2 |
3 | import { HOST } from '../util/apiRoutes'
4 | import { fetchWithAuth } from '../util/fetchUtils'
5 |
6 | // components
7 | import { ConditionalLink } from './ConditionalLink'
8 |
9 | export const PipelineDisplay = ({
10 | profileId,
11 | name,
12 | pfp,
13 | anonymous,
14 | pipeline,
15 | }) => {
16 | const [pfpUrl, setPfpUrl] = useState(null)
17 |
18 | const fetchPfp = async () => {
19 | if (!profileId || profileId === '') return
20 | if (!pfp || pfp === '') return
21 |
22 | try {
23 | const data = await fetchWithAuth({
24 | url: `${HOST}/api/pfp/${profileId}`,
25 | method: 'GET',
26 | })
27 |
28 | setPfpUrl(data.pfp)
29 | } catch (error) {
30 | console.error(error.message)
31 | setPfpUrl(null)
32 | }
33 | }
34 |
35 | useEffect(() => {
36 | const fetchInfo = async () => {
37 | await fetchPfp()
38 | }
39 |
40 | fetchInfo()
41 | }, [])
42 |
43 | return (
44 |
48 |
53 |
54 |
59 |
60 | {anonymous ? 'Anonymous' : name}
61 |
62 |
63 |
64 |
65 |
66 | {pipeline &&
67 | pipeline.map((experience) => (
68 |
72 |
73 |
74 | ))}
75 |
76 |
77 | )
78 | }
79 | import { useNavigate } from 'react-router-dom'
80 |
81 | export const ExperienceCard = ({ experience }) => {
82 | const current = new Date(experience.startDate) > new Date()
83 | const formatDateToMMYY = (dateString) => {
84 | // Converts 2023-01-01T00:00:00.000Z to January 2023
85 | const date = new Date(dateString)
86 |
87 | if (!(date instanceof Date) || isNaN(date.getTime())) {
88 | return 'Invalid Date'
89 | }
90 |
91 | const options = { year: 'numeric', month: 'long' }
92 | return date.toLocaleDateString(undefined, options)
93 | }
94 |
95 | const navigate = useNavigate()
96 |
97 | return (
98 |
102 |
{
105 | navigate(`/company/${experience.companyName}`)
106 | }}
107 | >
108 |
113 |
114 |
115 |
116 |
117 | {experience.displayName}
118 |
119 |
120 | {experience.title}
121 |
122 |
123 | {formatDateToMMYY(experience.startDate)} -{' '}
124 | {!experience.isIndefinite
125 | ? formatDateToMMYY(experience.endDate)
126 | : !current
127 | ? 'Present'
128 | : 'Indefinite'}
129 |
130 |
131 |
132 | )
133 | }
134 |
--------------------------------------------------------------------------------
/client/src/components/landing/People.js:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from 'react'
2 | import { useNavigate } from 'react-router-dom'
3 |
4 | import { HOST } from '../../util/apiRoutes'
5 | import { fetchWithAuth } from '../../util/fetchUtils'
6 |
7 | // components
8 | import Loading from '../../pages/Loading'
9 | import { PipelineCard } from '../PipelineCard'
10 |
11 | export default function People() {
12 | const [profiles, setProfiles] = useState([])
13 | const [loading, setLoading] = useState(false)
14 | const navigate = useNavigate()
15 |
16 | const generateProfiles = async (size = 5) => {
17 | setLoading(true)
18 |
19 | try {
20 | const data = await fetchWithAuth({
21 | url: `${HOST}/api/profile/random?amount=${size}`,
22 | method: 'GET',
23 | })
24 | setProfiles([...data])
25 | setLoading(false)
26 | } catch (error) {
27 | console.error(error.message)
28 | }
29 | }
30 |
31 | const handleNavigation = () => {
32 | navigate('/discover')
33 | }
34 |
35 | useEffect(() => {
36 | generateProfiles()
37 | }, [])
38 |
39 | if (loading) {
40 | return
41 | }
42 |
43 | return (
44 | <>
45 |
106 | >
107 | )
108 | }
109 |
--------------------------------------------------------------------------------