├── .nvmrc ├── Procfile ├── frontend ├── src │ ├── components │ │ ├── calendar │ │ │ └── calendarView.js │ │ ├── generic │ │ │ ├── List │ │ │ │ └── index.js │ │ │ ├── DescriptionItem │ │ │ │ └── DescriptionItem.module.scss │ │ │ ├── _Table │ │ │ │ ├── filterTypes.js │ │ │ │ ├── filterFunctions.js │ │ │ │ ├── filters │ │ │ │ │ └── ContainsSearch.js │ │ │ │ ├── sortFunctions.js │ │ │ │ ├── PageSelect.js │ │ │ │ ├── PageSizeSelect.js │ │ │ │ └── index.js │ │ │ ├── UserListItem │ │ │ │ ├── OrganiserListItem.js │ │ │ │ └── index.js │ │ │ ├── Divider │ │ │ │ └── index.js │ │ │ ├── LineDivider │ │ │ │ └── index.js │ │ │ ├── Tag │ │ │ │ ├── index.js │ │ │ │ └── Variants.js │ │ │ ├── GradientBox │ │ │ │ └── index.js │ │ │ ├── ErrorsBox │ │ │ │ └── index.js │ │ │ └── TimelineDot │ │ │ │ └── index.js │ │ ├── inputs │ │ │ ├── ImageUploadMultiple │ │ │ │ └── index.js │ │ │ ├── BlockExitIfDirty │ │ │ │ └── index.js │ │ │ ├── EventTagsSelect │ │ │ │ └── index.js │ │ │ └── RegistrationStatusSelect │ │ │ │ └── index.js │ │ ├── plots │ │ │ ├── TeamsCount.js │ │ │ ├── ApplicationsCount.js │ │ │ ├── ApplicationsLast24h.js │ │ │ ├── ReviewedPercent.js │ │ │ └── ReviewedAverage.js │ │ ├── events │ │ │ ├── EventPageScriptIFrame │ │ │ │ └── index.js │ │ │ └── EventPageScript │ │ │ │ └── index.js │ │ ├── animated │ │ │ ├── StaggeredListItem.js │ │ │ ├── FadeInWrapper.js │ │ │ └── StaggeredList.js │ │ ├── navbars │ │ │ └── BasicNavBar │ │ │ │ └── index.js │ │ ├── projects │ │ │ └── ScoreCriteria │ │ │ │ └── index.js │ │ ├── PricingMenu │ │ │ └── index.js │ │ ├── modals │ │ │ ├── QRCodeModal │ │ │ │ └── index.js │ │ │ └── ProjectReviewModal │ │ │ │ └── ReviewElement.js │ │ ├── hackerpack │ │ │ └── HackerpackDetail.js │ │ ├── Team │ │ │ └── TeamMembers │ │ │ │ └── index.js │ │ ├── layouts │ │ │ └── CookieConsentBar │ │ │ │ └── index.js │ │ ├── challenges │ │ │ └── ChallengeDetail.js │ │ ├── buttons │ │ │ └── StepButtons.js │ │ └── messaging │ │ │ └── alerts │ │ │ └── index.js │ ├── utils │ │ ├── experimental.js │ │ ├── debuggingTools.js │ │ ├── stylingHelpers.js │ │ ├── constants │ │ │ └── gradientList.js │ │ └── events.js │ ├── redux │ │ ├── account │ │ │ ├── actionTypes.js │ │ │ ├── selectors.js │ │ │ ├── reducer.js │ │ │ └── actions.js │ │ ├── snackbar │ │ │ ├── selectors.js │ │ │ ├── actionTypes.js │ │ │ └── reducer.js │ │ ├── auth │ │ │ ├── actionTypes.js │ │ │ └── reducer.js │ │ ├── admin │ │ │ ├── actionTypes.js │ │ │ └── selectors.js │ │ ├── user │ │ │ ├── actionTypes.js │ │ │ └── selectors.js │ │ ├── rootReducer.js │ │ ├── recruitment │ │ │ └── actionTypes.js │ │ └── dashboard │ │ │ └── actionTypes.js │ ├── assets │ │ ├── logos │ │ │ ├── flagCN.png │ │ │ ├── flagUK.png │ │ │ ├── emblem_black.png │ │ │ ├── emblem_white.png │ │ │ ├── JO_wordmark_black.png │ │ │ └── JO_wordmark_white.png │ │ └── images │ │ │ ├── laser_2016.jpg │ │ │ ├── visa_signature.jpg │ │ │ ├── dashboardDefault.jpg │ │ │ ├── default_thumbnail.png │ │ │ └── default_cover_image.png │ ├── pages │ │ ├── _dashboard │ │ │ └── renderDashboard │ │ │ │ ├── default │ │ │ │ ├── logout │ │ │ │ │ └── index.js │ │ │ │ ├── profile │ │ │ │ │ └── index.js │ │ │ │ └── index.js │ │ │ │ ├── organiser │ │ │ │ ├── edit │ │ │ │ │ ├── default │ │ │ │ │ │ └── const.js │ │ │ │ │ ├── submission │ │ │ │ │ │ └── components │ │ │ │ │ │ │ ├── inputs │ │ │ │ │ │ │ ├── BooleanInput.js │ │ │ │ │ │ │ └── UrlInput.js │ │ │ │ │ │ │ └── section │ │ │ │ │ │ │ ├── RemoveButton.js │ │ │ │ │ │ │ └── Dropdown.js │ │ │ │ │ └── timeline │ │ │ │ │ │ └── index.js │ │ │ │ ├── participants │ │ │ │ │ └── travel │ │ │ │ │ │ └── index.js │ │ │ │ ├── projects │ │ │ │ │ └── default │ │ │ │ │ │ └── index.js │ │ │ │ ├── router.js │ │ │ │ ├── travel-grants │ │ │ │ │ └── index.js │ │ │ │ └── default │ │ │ │ │ └── index.js │ │ │ │ ├── partner │ │ │ │ └── partnerrecruitment │ │ │ │ │ ├── default │ │ │ │ │ ├── Filters │ │ │ │ │ │ └── TextSearchFilter.js │ │ │ │ │ └── ToggleFavorites.js │ │ │ │ │ ├── index.js │ │ │ │ │ └── id │ │ │ │ │ └── DetailSection.js │ │ │ │ ├── generalPages │ │ │ │ └── default │ │ │ │ │ └── Blocks │ │ │ │ │ └── TimeLineBlock.js │ │ │ │ └── participant │ │ │ │ └── reviewing │ │ │ │ └── VoteTimer.js │ │ ├── _login │ │ │ ├── welcome │ │ │ │ ├── LightCheckbox.js │ │ │ │ └── LightTextField.js │ │ │ └── index.js │ │ ├── _logout │ │ │ └── index.js │ │ ├── _projects │ │ │ └── index.js │ │ ├── _events │ │ │ ├── index.js │ │ │ └── slug │ │ │ │ ├── tracking │ │ │ │ └── index.js │ │ │ │ └── default │ │ │ │ └── EventTimeline │ │ │ │ └── TimelineDot.js │ │ ├── _index │ │ │ └── index.js │ │ └── _admin │ │ │ └── index.js │ ├── services │ │ ├── newsletter.js │ │ ├── csvExporter.js │ │ ├── admin.js │ │ ├── api.js │ │ ├── winnerVote.js │ │ ├── axios.js │ │ ├── organization.js │ │ ├── banner.js │ │ ├── email.js │ │ └── hackerpack.js │ ├── graphql │ │ ├── queries │ │ │ ├── alert.js │ │ │ ├── messages.js │ │ │ ├── organization.js │ │ │ ├── registrations.js │ │ │ ├── userProfile.js │ │ │ └── hackerpack.js │ │ ├── mutations │ │ │ ├── alertOps.js │ │ │ ├── messageOps.js │ │ │ └── eventOps.js │ │ └── subscriptions │ │ │ ├── messages.js │ │ │ └── alert.js │ ├── hocs │ │ ├── EventStatusWrapper.js │ │ └── ShowIfPermission.js │ ├── styles │ │ └── index.css │ ├── constants │ │ └── events.js │ ├── hooks │ │ └── apiHooks.js │ └── i18n.js ├── public │ ├── favicon.ico │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── mstile-150x150.png │ ├── apple-touch-icon.png │ ├── android-chrome-192x192.png │ ├── android-chrome-512x512.png │ ├── site.webmanifest │ ├── browserconfig.xml │ └── manifest.json ├── postcss.config.js ├── config-overrides.js ├── jsconfig.json ├── .gitignore ├── .babelrc.js ├── .eslintrc └── tailwind.config.js ├── npm ├── shared ├── data │ ├── genders.json │ ├── roles-design.json │ ├── roles-dev.json │ ├── roles-other.json │ ├── roles-biz.json │ ├── themes.json │ ├── industries.json │ └── skills-programming-languages.json ├── constants │ ├── genders.js │ ├── project-statuses.js │ ├── themes.js │ ├── industries.js │ ├── currencies.js │ ├── reviewing-methods.js │ ├── project-default-fields.js │ ├── event-types.js │ ├── submission-default-fields.js │ ├── languages.js │ ├── filter-values.js │ ├── auth.js │ ├── overall-reviewing-methods.js │ ├── achievement-types.js │ ├── event-statuses.js │ ├── universities.js │ ├── gradient-list.js │ ├── countries.js │ ├── event-page-scripts.js │ └── registration-travel-grant-statuses.js ├── schemas │ ├── validation │ │ └── messageSchema.js │ ├── Candidate.js │ ├── UserDetailsConfigItem.js │ ├── ScoreCriteria.js │ ├── UserProfileFields.js │ ├── TeamOptions.js │ ├── CustomAnswer.js │ ├── LegalName.js │ ├── IBANAccount.js │ ├── Role.js │ ├── Skill.js │ ├── Answers.js │ ├── Education.js │ ├── PhoneNumber.js │ ├── TeamRole.js │ ├── RecruiterEvents.js │ ├── CloudinaryImage.js │ ├── RegistrationConfig.js │ ├── RegistrationQuestionSettings.js │ ├── Recruiter.js │ └── EventTag.js ├── helpers │ ├── utils.js │ └── registration-fields.js └── .eslintrc ├── backend ├── modules │ ├── auth │ │ └── routes.js │ ├── graphql-shared-types.js │ ├── sandbox │ │ ├── controller.js │ │ └── routes.js │ ├── email-task │ │ ├── types.js │ │ └── model.js │ ├── files │ │ ├── model.js │ │ └── routes.js │ ├── newsletter │ │ └── routes.js │ ├── alert │ │ └── model.js │ ├── cron │ │ ├── jobs │ │ │ └── generate-event-results.js │ │ └── index.js │ ├── reviewing │ │ └── gavel │ │ │ ├── settings.js │ │ │ └── Decision.js │ ├── winner-votes │ │ └── model.js │ ├── user-profile │ │ └── helpers.js │ ├── message │ │ └── model.js │ ├── voting-token │ │ └── model.js │ ├── meeting │ │ └── helpers.js │ ├── rankings │ │ └── model.js │ ├── registration │ │ └── checklists.js │ └── filter-group │ │ ├── controller.js │ │ └── model.js ├── nodemon.json ├── .gitignore ├── misc │ ├── logger.js │ └── gridfs.js ├── common │ ├── middleware │ │ ├── admin.js │ │ ├── webhook.js │ │ ├── token.js │ │ └── votingToken.js │ ├── services │ │ ├── google-calendar │ │ │ ├── token.json │ │ │ └── credentials.json │ │ ├── discord.js │ │ └── linkedin.js │ ├── plugins │ │ ├── publicFields.js │ │ ├── updateAllowed.js │ │ └── allowPublish.js │ ├── utils │ │ └── dateUtils.js │ └── schemas │ │ └── Achievement.js ├── migrations │ ├── 06-finals-active-to-event.js │ ├── 04-add-finalists-to-event.js │ ├── 15-add-meetingRooms-to-event.js │ ├── 09-add-challengesenabled-false │ ├── 13-set-eventLocation-null-where-not-exists.js │ ├── 17-add-specific-hackerpacks-to-event.js │ ├── 08-create-registration-objects-in-profiles.js │ ├── 18-add-event-newsletter-link-to-event.js │ ├── 28-add-gavel-login-to-registrations.js │ ├── 23-add-timeline-to-event.js │ ├── 27-add-experimental-flag-to-events.js │ ├── 22-rename-team-tagline-to-subtitle.js │ ├── 01-remove-project-unique-index.js │ ├── 12-fix-empty-senderEmail-in-event │ ├── 26-fix-empty-senderEmail-in-event.js │ ├── 10-add-banner-priority-and-approved-to-event.js │ ├── 03-rename-country_code-to-countryCode.js │ └── 02-rename-sigma_sq-to-sigmaSq.js ├── .eslintrc └── utils │ └── permissions.js ├── .github ├── ISSUE_TEMPLATE │ ├── config.yml │ └── --feature-request.md └── dependabot.yml ├── .gitignore ├── .prettierrc ├── .vscode ├── launch.json └── settings.json ├── docker-compose.yml ├── app.json └── auth0 ├── config.json └── rules └── Add data to idToken.js /.nvmrc: -------------------------------------------------------------------------------- 1 | 16.14.2 -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: npm start -------------------------------------------------------------------------------- /frontend/src/components/calendar/calendarView.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/components/generic/List/index.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /npm: -------------------------------------------------------------------------------- 1 | Enter the absolute path where the nvm-windows zip file is extracted/copied to: -------------------------------------------------------------------------------- /shared/data/genders.json: -------------------------------------------------------------------------------- 1 | ["Male", "Female", "Other", "None", "Prefer not to answer"] 2 | -------------------------------------------------------------------------------- /frontend/src/utils/experimental.js: -------------------------------------------------------------------------------- 1 | function experimental(params) { 2 | return {} 3 | } 4 | -------------------------------------------------------------------------------- /shared/constants/genders.js: -------------------------------------------------------------------------------- 1 | const genders = require('../data/genders.json') 2 | module.exports = genders 3 | -------------------------------------------------------------------------------- /frontend/src/redux/account/actionTypes.js: -------------------------------------------------------------------------------- 1 | export const UPDATE_REGISTRATIONS = 'account/UPDATE_REGISTRATIONS' 2 | -------------------------------------------------------------------------------- /frontend/src/redux/account/selectors.js: -------------------------------------------------------------------------------- 1 | export const registrations = state => state.account.registrations 2 | -------------------------------------------------------------------------------- /frontend/src/redux/snackbar/selectors.js: -------------------------------------------------------------------------------- 1 | export const notifications = state => state.snackbar.notifications 2 | -------------------------------------------------------------------------------- /frontend/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackjunction/JunctionApp/HEAD/frontend/public/favicon.ico -------------------------------------------------------------------------------- /frontend/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [require('tailwindcss'), require('autoprefixer')], 3 | } 4 | -------------------------------------------------------------------------------- /frontend/public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackjunction/JunctionApp/HEAD/frontend/public/favicon-16x16.png -------------------------------------------------------------------------------- /frontend/public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackjunction/JunctionApp/HEAD/frontend/public/favicon-32x32.png -------------------------------------------------------------------------------- /frontend/public/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackjunction/JunctionApp/HEAD/frontend/public/mstile-150x150.png -------------------------------------------------------------------------------- /shared/constants/project-statuses.js: -------------------------------------------------------------------------------- 1 | const ProjectStatuses = ['draft', 'final'] 2 | 3 | module.exports = ProjectStatuses 4 | -------------------------------------------------------------------------------- /frontend/public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackjunction/JunctionApp/HEAD/frontend/public/apple-touch-icon.png -------------------------------------------------------------------------------- /frontend/src/assets/logos/flagCN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackjunction/JunctionApp/HEAD/frontend/src/assets/logos/flagCN.png -------------------------------------------------------------------------------- /frontend/src/assets/logos/flagUK.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackjunction/JunctionApp/HEAD/frontend/src/assets/logos/flagUK.png -------------------------------------------------------------------------------- /backend/modules/auth/routes.js: -------------------------------------------------------------------------------- 1 | const express = require('express') 2 | 3 | const router = express.Router() 4 | 5 | module.exports = router 6 | -------------------------------------------------------------------------------- /backend/nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "events": { 3 | "restart": "kill-port 2222", 4 | "crash": "kill-port 2222" 5 | }, 6 | "delay": "1500" 7 | } -------------------------------------------------------------------------------- /frontend/config-overrides.js: -------------------------------------------------------------------------------- 1 | const { override, useBabelRc } = require('customize-cra') 2 | 3 | module.exports = override(useBabelRc()) 4 | -------------------------------------------------------------------------------- /frontend/src/assets/images/laser_2016.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackjunction/JunctionApp/HEAD/frontend/src/assets/images/laser_2016.jpg -------------------------------------------------------------------------------- /frontend/public/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackjunction/JunctionApp/HEAD/frontend/public/android-chrome-192x192.png -------------------------------------------------------------------------------- /frontend/public/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackjunction/JunctionApp/HEAD/frontend/public/android-chrome-512x512.png -------------------------------------------------------------------------------- /frontend/src/assets/logos/emblem_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackjunction/JunctionApp/HEAD/frontend/src/assets/logos/emblem_black.png -------------------------------------------------------------------------------- /frontend/src/assets/logos/emblem_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackjunction/JunctionApp/HEAD/frontend/src/assets/logos/emblem_white.png -------------------------------------------------------------------------------- /frontend/src/assets/images/visa_signature.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackjunction/JunctionApp/HEAD/frontend/src/assets/images/visa_signature.jpg -------------------------------------------------------------------------------- /frontend/src/assets/images/dashboardDefault.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackjunction/JunctionApp/HEAD/frontend/src/assets/images/dashboardDefault.jpg -------------------------------------------------------------------------------- /frontend/src/assets/images/default_thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackjunction/JunctionApp/HEAD/frontend/src/assets/images/default_thumbnail.png -------------------------------------------------------------------------------- /frontend/src/assets/logos/JO_wordmark_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackjunction/JunctionApp/HEAD/frontend/src/assets/logos/JO_wordmark_black.png -------------------------------------------------------------------------------- /frontend/src/assets/logos/JO_wordmark_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackjunction/JunctionApp/HEAD/frontend/src/assets/logos/JO_wordmark_white.png -------------------------------------------------------------------------------- /backend/.gitignore: -------------------------------------------------------------------------------- 1 | /shared 2 | /build 3 | .env 4 | .ignored 5 | /common/services/google-calendar/credentials.json 6 | /common/services/google-calendar/token.json -------------------------------------------------------------------------------- /frontend/src/assets/images/default_cover_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackjunction/JunctionApp/HEAD/frontend/src/assets/images/default_cover_image.png -------------------------------------------------------------------------------- /shared/constants/themes.js: -------------------------------------------------------------------------------- 1 | const themes = require('../data/themes.json') 2 | 3 | const Themes = {} 4 | 5 | Themes.themes = themes 6 | 7 | module.exports = Themes 8 | -------------------------------------------------------------------------------- /shared/constants/industries.js: -------------------------------------------------------------------------------- 1 | const industries = require('../data/industries.json') 2 | 3 | const Industries = {} 4 | 5 | Industries.industries = industries 6 | 7 | module.exports = Industries 8 | -------------------------------------------------------------------------------- /frontend/src/redux/snackbar/actionTypes.js: -------------------------------------------------------------------------------- 1 | export const ENQUEUE_SNACKBAR = 'snackbar/ENQUEUE_SNACKBAR' 2 | export const CLOSE_SNACKBAR = 'snackbar/CLOSE_SNACKBAR' 3 | export const REMOVE_SNACKBAR = 'snackbar/REMOVE_SNACKBAR' 4 | -------------------------------------------------------------------------------- /frontend/src/components/generic/DescriptionItem/DescriptionItem.module.scss: -------------------------------------------------------------------------------- 1 | .wrapper { 2 | display: flex; 3 | flex-direction: column; 4 | 5 | background: #f8f8f8; 6 | padding: 1rem; 7 | margin-bottom: 1rem; 8 | } 9 | -------------------------------------------------------------------------------- /shared/data/roles-design.json: -------------------------------------------------------------------------------- 1 | [ 2 | "Art Director", 3 | "Freelance Designer", 4 | "Graphic/Visual Designer", 5 | "Service Designer", 6 | "UI designer", 7 | "UX Designer", 8 | "Web Designer" 9 | ] 10 | -------------------------------------------------------------------------------- /frontend/src/pages/_dashboard/renderDashboard/default/logout/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export default () => { 4 | 5 | return ( 6 |
7 |

LOGOUT

8 |
9 | ) 10 | } -------------------------------------------------------------------------------- /frontend/src/pages/_dashboard/renderDashboard/default/profile/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export default () => { 4 | 5 | return ( 6 |
7 |

PROFILE

8 |
9 | ) 10 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: true 2 | contact_links: 3 | - name: Ask a question 4 | url: https://github.com/hackjunction/JunctionApp/discussions 5 | about: Ask questions and discuss with other community members 6 | -------------------------------------------------------------------------------- /frontend/src/redux/auth/actionTypes.js: -------------------------------------------------------------------------------- 1 | export const CLEAR_SESSION = 'auth/CLEAR_SESSION' 2 | export const SET_SESSION = 'auth/SET_SESSION' 3 | export const SET_NEXT_ROUTE = 'auth/SET_NEXT_ROUTE' 4 | export const RESET_NEXT_ROUTE = 'auth/RESET_NEXT_ROUTE' 5 | -------------------------------------------------------------------------------- /shared/schemas/validation/messageSchema.js: -------------------------------------------------------------------------------- 1 | import * as yup from 'yup' 2 | 3 | export default yup.object().shape({ 4 | content: yup 5 | .string() 6 | .required() 7 | .min(2, 'Message must be at least 2 characters long'), 8 | }) 9 | -------------------------------------------------------------------------------- /backend/modules/graphql-shared-types.js: -------------------------------------------------------------------------------- 1 | const { buildSchema } = require('graphql') 2 | const { SharedGraphQLTypes } = require('@hackjunction/shared/schemas') 3 | 4 | const SharedSchema = buildSchema(SharedGraphQLTypes) 5 | 6 | module.exports = SharedSchema._typeMap 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | scripts/ 4 | dump/ 5 | build/ 6 | docker-compose.yml 7 | .env 8 | *.env.example 9 | azure-pipelines-1.yml 10 | azure-pipelines.yml 11 | .env dev frontend 12 | .env dev backend 13 | .env stag frontend 14 | .env stag backend 15 | -------------------------------------------------------------------------------- /shared/constants/currencies.js: -------------------------------------------------------------------------------- 1 | const currencies = require('../data/currencies.json') 2 | 3 | const Currencies = {} 4 | 5 | Currencies.asArray = Object.keys(currencies).map(key => currencies[key]) 6 | Currencies.keys = Object.keys(currencies) 7 | 8 | module.exports = Currencies 9 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 80, 3 | "tabWidth": 4, 4 | "semi": false, 5 | "singleQuote": true, 6 | "trailingComma": "all", 7 | "bracketSpacing": true, 8 | "jsxBracketSameLine": false, 9 | "endOfLine":"lf", 10 | "arrowParens": "avoid" 11 | } 12 | -------------------------------------------------------------------------------- /frontend/public/site.webmanifest: -------------------------------------------------------------------------------- 1 | {"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} -------------------------------------------------------------------------------- /frontend/src/redux/admin/actionTypes.js: -------------------------------------------------------------------------------- 1 | export const LOAD_USERS = 'admin/LOAD_USERS' 2 | export const LOAD_ROLES = 'admin/LOAD_ROLES' 3 | 4 | export const SET_USERS_FILTERS_ROLES = 'admin/SET_USERS_FILTERS_ROLES' 5 | export const SET_USERS_FILTERS_SORT_BY = 'admin/SET_USERS_FILTERS_SORT_BY' 6 | -------------------------------------------------------------------------------- /frontend/src/services/newsletter.js: -------------------------------------------------------------------------------- 1 | import _axios from 'services/axios' 2 | 3 | const NewsletterService = {} 4 | 5 | NewsletterService.subscribe = (email, country) => { 6 | return _axios.post('/newsletter', { email, country }) 7 | } 8 | 9 | export default NewsletterService 10 | -------------------------------------------------------------------------------- /frontend/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es2016", 5 | "jsx": "preserve", 6 | "checkJs": true, 7 | "baseUrl": "./src" 8 | }, 9 | "exclude": ["node_modules", "**/node_modules/*"] 10 | } 11 | -------------------------------------------------------------------------------- /frontend/src/components/generic/_Table/filterTypes.js: -------------------------------------------------------------------------------- 1 | export const CONTAINS_SEARCH = 'contains-search' 2 | export const FUZZY_SEARCH = 'fuzzy-search' 3 | export const EXACT_SEARCH = 'exact-search' 4 | export const SINGLE_SELECT = 'single-select' 5 | export const MULTIPLE_SELECT = 'multiple-select' 6 | -------------------------------------------------------------------------------- /frontend/src/graphql/queries/alert.js: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | 3 | export const ALERTS_QUERY = gql` 4 | query alerts($eventId: String!) { 5 | alerts(eventId: $eventId) { 6 | content 7 | sender 8 | sentAt 9 | } 10 | } 11 | ` 12 | -------------------------------------------------------------------------------- /frontend/public/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #ffffff 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /frontend/src/redux/user/actionTypes.js: -------------------------------------------------------------------------------- 1 | export const UPDATE_PROFILE = 'user/UPDATE_PROFILE' 2 | export const SET_PROFILE = 'user/SET_PROFILE' 3 | export const SET_REGISTRATION = 'user/SET_REGISTRATION' 4 | export const SET_ACCESSRIGHT = 'user/SET_ACCESSRIGHT' 5 | export const ORGANIZER_EVENTS = 'user/ORGANIZER_EVENTS' 6 | 7 | -------------------------------------------------------------------------------- /shared/helpers/utils.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | isEmail: value => { 3 | const re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ 4 | return re.test(String(value).toLowerCase()) 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /frontend/src/graphql/queries/messages.js: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | 3 | export const MY_MESSAGES_QUERY = gql` 4 | query MyMessages { 5 | messages { 6 | recipients 7 | content 8 | sender 9 | sentAt 10 | readAt 11 | } 12 | } 13 | ` 14 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "type": "node", 6 | "request": "attach", 7 | "name": "Node: Nodemon", 8 | "processId": "${command:PickProcess}", 9 | "restart": true, 10 | "protocol": "inspector", 11 | }, 12 | ] 13 | } -------------------------------------------------------------------------------- /shared/constants/reviewing-methods.js: -------------------------------------------------------------------------------- 1 | const ReviewingMethods = { 2 | gavelPeerReview: { 3 | id: 'gavelPeerReview', 4 | label: 'Gavel, Peer-reviewing', 5 | }, 6 | manualReview: { 7 | id: 'manualReview', 8 | label: 'Manual review', 9 | }, 10 | } 11 | 12 | module.exports = ReviewingMethods 13 | -------------------------------------------------------------------------------- /frontend/src/graphql/mutations/alertOps.js: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | 3 | export const SEND_ALERT_MUTATION = gql` 4 | mutation SendAlert($input: AlertInput!) { 5 | sendAlert(alert: $input) { 6 | eventId 7 | content 8 | sender 9 | sentAt 10 | } 11 | } 12 | ` 13 | -------------------------------------------------------------------------------- /frontend/src/pages/_login/welcome/LightCheckbox.js: -------------------------------------------------------------------------------- 1 | import { withStyles } from '@material-ui/core/styles' 2 | import { Checkbox } from '@material-ui/core' 3 | 4 | export default withStyles(theme => ({ 5 | root: { 6 | '& .MuiSvgIcon-root': { 7 | color: theme.palette.primary.main, 8 | }, 9 | }, 10 | }))(Checkbox) 11 | -------------------------------------------------------------------------------- /frontend/src/components/inputs/ImageUploadMultiple/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const ImageUploadMultiple = ( 4 | value = [], 5 | onChange, 6 | uploadUrl, 7 | resizeMode = 'contain', 8 | enqueueSnackbar, 9 | idToken, 10 | ) => { 11 | return

Hello

12 | } 13 | 14 | export default ImageUploadMultiple 15 | -------------------------------------------------------------------------------- /frontend/src/graphql/subscriptions/messages.js: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | 3 | export const MY_MESSAGES_SUBSCRIPTION = gql` 4 | subscription MyMessages { 5 | newMessage { 6 | recipients 7 | content 8 | sender 9 | sentAt 10 | readAt 11 | } 12 | } 13 | ` 14 | -------------------------------------------------------------------------------- /frontend/src/hocs/EventStatusWrapper.js: -------------------------------------------------------------------------------- 1 | const EventStatusWrapper = ({ 2 | eventStatus, 3 | statuses = [], 4 | children, 5 | render, 6 | }) => { 7 | if (statuses.indexOf(eventStatus) !== -1) { 8 | return typeof render === 'function' ? render() : children 9 | } 10 | return null 11 | } 12 | 13 | export default EventStatusWrapper 14 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | services: 3 | mongodb: 4 | image: mongo 5 | container_name: mongodb_stag 6 | environment: 7 | - PUID=1000 8 | - PGID=1000 9 | ports: 10 | - 27012:27017 11 | volumes: 12 | - ../documents/databases/dump 13 | restart: unless-stopped 14 | -------------------------------------------------------------------------------- /shared/constants/project-default-fields.js: -------------------------------------------------------------------------------- 1 | const ProjectDefaultFields = [ 2 | 'images', 3 | 'punchline', 4 | 'description', 5 | 'track', 6 | 'challenges', 7 | 'technologies', 8 | 'video', 9 | 'demo', 10 | 'source', 11 | 'sourcePublic', 12 | 'location', 13 | 'privacy', 14 | ] 15 | 16 | module.exports = ProjectDefaultFields 17 | -------------------------------------------------------------------------------- /shared/constants/event-types.js: -------------------------------------------------------------------------------- 1 | const EventTypes = { 2 | physical: { 3 | id: 'physical', 4 | label: 'Physical event', 5 | }, 6 | online: { 7 | id: 'online', 8 | label: 'Online event', 9 | }, 10 | hybrid: { 11 | id: 'hybrid', 12 | label: 'Hybrid event', 13 | }, 14 | } 15 | 16 | module.exports = EventTypes 17 | -------------------------------------------------------------------------------- /backend/misc/logger.js: -------------------------------------------------------------------------------- 1 | const pino = require('pino') 2 | 3 | const prod = process.env.NODE_ENV === 'production' 4 | 5 | const opts = { 6 | prettyPrint: prod ? undefined : { colorize: true }, 7 | redact: ['res.headers', 'req.headers.authorization'], 8 | } 9 | 10 | const stream = pino.destination(1) 11 | const logger = pino(opts, stream) 12 | 13 | module.exports = logger 14 | -------------------------------------------------------------------------------- /frontend/src/graphql/mutations/messageOps.js: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | 3 | export const SEND_MESSAGE_MUTATION = gql` 4 | mutation SendMessage($input: MessageInput!) { 5 | sendMessage(message: $input) { 6 | recipients 7 | content 8 | sender 9 | sentAt 10 | readAt 11 | } 12 | } 13 | ` 14 | -------------------------------------------------------------------------------- /frontend/src/graphql/subscriptions/alert.js: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | 3 | export const NEW_ALERTS_SUBSCRIPTION = gql` 4 | subscription newAlert($eventId: String, $slug: String) { 5 | newAlert(eventId: $eventId, slug: $slug) { 6 | eventId 7 | content 8 | sender 9 | sentAt 10 | } 11 | } 12 | ` 13 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Junction App", 3 | "description": "Junction all-in-one hackathon platform", 4 | "buildpacks": [ 5 | { 6 | "url": "heroku/nodejs" 7 | } 8 | ], 9 | "env": { 10 | "SECRET_TOKEN": { 11 | "required": true, 12 | "description": "SECRET_TOKEN which is a must have" 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /frontend/src/components/plots/TeamsCount.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import Statistic from 'components/generic/Statistic' 4 | import { useSelector } from 'react-redux' 5 | import * as OrganiserSelectors from 'redux/organiser/selectors' 6 | 7 | export default () => { 8 | const value = useSelector(OrganiserSelectors.teamsCount) 9 | return 10 | } 11 | -------------------------------------------------------------------------------- /frontend/src/pages/_login/welcome/LightTextField.js: -------------------------------------------------------------------------------- 1 | import { withStyles } from '@material-ui/core/styles' 2 | import { TextField } from '@material-ui/core' 3 | 4 | export default withStyles(theme => ({ 5 | root: { 6 | '& label': { 7 | color: 'rgba(255,255,255,0.8)', 8 | }, 9 | '& input': { 10 | color: 'white', 11 | }, 12 | }, 13 | }))(TextField) 14 | -------------------------------------------------------------------------------- /frontend/src/components/generic/UserListItem/OrganiserListItem.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { useSelector } from 'react-redux' 3 | import * as OrganiserSelectors from 'redux/organiser/selectors' 4 | import UserListItem from './index' 5 | 6 | export default ({ userId }) => { 7 | const organisersMap = useSelector(OrganiserSelectors.organisersMap) 8 | return 9 | } 10 | -------------------------------------------------------------------------------- /frontend/src/components/plots/ApplicationsCount.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import Statistic from 'components/generic/Statistic' 4 | import { useSelector } from 'react-redux' 5 | import * as OrganiserSelectors from 'redux/organiser/selectors' 6 | 7 | export default () => { 8 | const value = useSelector(OrganiserSelectors.registrationsCount) 9 | return 10 | } 11 | -------------------------------------------------------------------------------- /shared/constants/submission-default-fields.js: -------------------------------------------------------------------------------- 1 | const SubmissionDefaultFields = { 2 | images: true, 3 | punchline: true, 4 | description: true, 5 | track: true, 6 | challenges: true, 7 | technologies: true, 8 | video: true, 9 | demo: true, 10 | source: true, 11 | sourcePublic: true, 12 | location: true, 13 | privacy: true, 14 | } 15 | 16 | module.exports = SubmissionDefaultFields 17 | -------------------------------------------------------------------------------- /frontend/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "Junction App", 3 | "name": "Junction App HackPlatform", 4 | "default_locale": "en", 5 | "icons": [ 6 | { 7 | "src": "favicon.ico", 8 | "sizes": "64x64 32x32 24x24 16x16", 9 | "type": "image/x-icon" 10 | } 11 | ], 12 | "start_url": ".", 13 | "display": "standalone", 14 | "theme_color": "#000000", 15 | "background_color": "#ffffff" 16 | } 17 | -------------------------------------------------------------------------------- /frontend/src/services/csvExporter.js: -------------------------------------------------------------------------------- 1 | import { ExportToCsv } from 'export-to-csv' 2 | 3 | const CsvExporterService = {} 4 | 5 | CsvExporterService.exportToCsv = (data, fileName) => { 6 | const options = { 7 | filename: fileName, 8 | useKeysAsHeaders: true, 9 | } 10 | 11 | const csvExporter = new ExportToCsv(options) 12 | csvExporter.generateCsv(data) 13 | } 14 | 15 | export default CsvExporterService 16 | -------------------------------------------------------------------------------- /shared/constants/languages.js: -------------------------------------------------------------------------------- 1 | const languages = require('../data/languages.json') 2 | 3 | const Languages = {} 4 | 5 | Languages.asArrayOfIds = Object.keys(languages) 6 | Languages.asArray = Languages.asArrayOfIds.reduce((result, languageId) => { 7 | result.push(languages[languageId]) 8 | return result 9 | }, []) 10 | Languages.asArrayOfNames = Languages.asArray.map(lang => lang.name) 11 | 12 | module.exports = Languages 13 | -------------------------------------------------------------------------------- /frontend/src/components/plots/ApplicationsLast24h.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import Statistic from 'components/generic/Statistic' 4 | import { useSelector } from 'react-redux' 5 | import * as OrganiserSelectors from 'redux/organiser/selectors' 6 | 7 | export default () => { 8 | const value = useSelector(OrganiserSelectors.registrationsLast24h) 9 | return 10 | } 11 | -------------------------------------------------------------------------------- /frontend/src/components/plots/ReviewedPercent.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import Statistic from 'components/generic/Statistic' 4 | import { useSelector } from 'react-redux' 5 | import * as OrganiserSelectors from 'redux/organiser/selectors' 6 | 7 | export default () => { 8 | const value = useSelector(OrganiserSelectors.percentReviewed) ?? 0 9 | return 10 | } 11 | -------------------------------------------------------------------------------- /shared/constants/filter-values.js: -------------------------------------------------------------------------------- 1 | const FilterValues = { 2 | STRING: 'STRING', 3 | BOOLEAN: 'BOOLEAN', 4 | NUMBER: 'NUMBER', 5 | RATING: 'RATING', 6 | DATE: 'DATE', 7 | GENDER: 'GENDER', 8 | NATIONALITY: 'NATIONALITY', 9 | COUNTRY: 'COUNTRY', 10 | LANGUAGE: 'LANGUAGE', 11 | STATUS: 'STATUS', 12 | TAG: 'TAG', 13 | CUSTOM_QUESTION: 'CUSTOM_QUESTION', 14 | } 15 | 16 | module.exports = FilterValues 17 | -------------------------------------------------------------------------------- /frontend/src/pages/_dashboard/renderDashboard/organiser/edit/default/const.js: -------------------------------------------------------------------------------- 1 | export const defaultEventStyles = { 2 | headerBackgroundColor: '#ffffff', 3 | headerTextColor: '#000000', 4 | bodyBackgroundColor: '#ffffff', 5 | detailsBackgroundColor: '#ffffff', 6 | detailsTextColor: '#000000', 7 | sidebarBackgroundColor: '#ffffff', 8 | sidebarTextColor: '#000000', 9 | accentColor: '#73f9ec', 10 | linkColor: '#52d7af', 11 | } 12 | -------------------------------------------------------------------------------- /frontend/src/components/generic/Divider/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { makeStyles } from '@material-ui/core/styles' 3 | 4 | const useStyles = makeStyles(theme => ({ 5 | root: ({ size }) => ({ 6 | width: theme.spacing(size), 7 | height: theme.spacing(size), 8 | }), 9 | })) 10 | 11 | export default ({ size = 1 }) => { 12 | const classes = useStyles({ size }) 13 | 14 | return
15 | } 16 | -------------------------------------------------------------------------------- /backend/common/middleware/admin.js: -------------------------------------------------------------------------------- 1 | const { NotFoundError } = require('../errors/errors') 2 | 3 | const AdminMiddleware = { 4 | hasAdminToken: (req, res, next) => { 5 | console.log('CHECKING ADMIN TOKEN', req.query.adminToken) 6 | if (req.query.adminToken === global.gConfig.ADMIN_TOKEN) { 7 | next() 8 | } else { 9 | next(new NotFoundError()) 10 | } 11 | }, 12 | } 13 | 14 | module.exports = AdminMiddleware 15 | -------------------------------------------------------------------------------- /shared/data/roles-dev.json: -------------------------------------------------------------------------------- 1 | [ 2 | "Backend Developer", 3 | "Data Scientist", 4 | "Database Specialist", 5 | "Desktop Developer", 6 | "DevOps Developer", 7 | "Freelance Developer", 8 | "Frontend Developer", 9 | "Fullstack Developer", 10 | "Hardware Developer", 11 | "ML/AI Developer", 12 | "Mobile Developer", 13 | "QA/Test Developer", 14 | "Cyber Security Engineer", 15 | "Software Architect", 16 | "Web Developer" 17 | ] 18 | -------------------------------------------------------------------------------- /frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | /server/build 14 | 15 | # misc 16 | .DS_Store 17 | .env 18 | .env.local 19 | .env.development.local 20 | .env.test.local 21 | .env.production.local 22 | 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | /shared 28 | 29 | -------------------------------------------------------------------------------- /frontend/src/pages/_dashboard/renderDashboard/organiser/edit/submission/components/inputs/BooleanInput.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Switch from '../../../../../../../../components/generic/Switch' 3 | 4 | const BooleanInput = ({ checked, onChange }) => { 5 | return ( 6 | 11 | ) 12 | } 13 | 14 | export default BooleanInput 15 | -------------------------------------------------------------------------------- /backend/modules/sandbox/controller.js: -------------------------------------------------------------------------------- 1 | const { AlreadyExistsError } = require("../../common/errors/errors") 2 | 3 | const controller = {} 4 | 5 | controller.updateMetadata = async (userId, updates) => { 6 | // const user = await auth0.getUser({ id: userId }) 7 | // const metadata = { ...user.user_metadata, ...updates } 8 | // const updatedUser = await auth0.updateUserMetadata({ id: userId }, metadata) 9 | return "updatedUser" 10 | } 11 | 12 | 13 | 14 | module.exports = controller -------------------------------------------------------------------------------- /frontend/src/pages/_dashboard/renderDashboard/partner/partnerrecruitment/default/Filters/TextSearchFilter.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import { Box } from '@material-ui/core' 4 | import TextInput from 'components/inputs/TextInput' 5 | 6 | const TextSearchFilter = () => { 7 | return ( 8 | 9 | 10 | 11 | ) 12 | } 13 | 14 | export default TextSearchFilter 15 | -------------------------------------------------------------------------------- /backend/common/middleware/webhook.js: -------------------------------------------------------------------------------- 1 | const { NotFoundError } = require('../errors/errors') 2 | 3 | const WebhookMiddleware = { 4 | hasWebhookToken: (req, res, next) => { 5 | console.log('CHECKING WEBHOOK API TOKEN', req.query.webhook_api_key) 6 | if (req.query.webhook_api_key === global.gConfig.WEBHOOK_API_KEY) { 7 | next() 8 | } else { 9 | next(new NotFoundError()) 10 | } 11 | }, 12 | } 13 | 14 | module.exports = WebhookMiddleware 15 | -------------------------------------------------------------------------------- /frontend/src/pages/_dashboard/renderDashboard/organiser/edit/submission/components/inputs/UrlInput.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const UrlInput = () => { 4 | return ( 5 | 10 | ) 11 | } 12 | 13 | export default UrlInput 14 | -------------------------------------------------------------------------------- /frontend/src/utils/debuggingTools.js: -------------------------------------------------------------------------------- 1 | export const debugGroup = ( 2 | groupName = 'Debug group', 3 | debugTarget = [], 4 | groupColor = 'yellow', 5 | ) => { 6 | console.group(`%c${groupName}`, `color: ${groupColor};font-size: 20px;`) 7 | Array.isArray(debugTarget) 8 | ? debugTarget.forEach((item, index) => { 9 | console.log(`%c${index}`, `color: green;font-size: 16px;`, item) 10 | }) 11 | : console.log(debugTarget) 12 | console.groupEnd() 13 | } 14 | -------------------------------------------------------------------------------- /frontend/src/components/events/EventPageScriptIFrame/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import EventUtils from 'utils/events' 3 | 4 | export default ({ pageId, slug, event }) => { 5 | return EventUtils.getApprovedEventPageScripts(event, pageId) ? ( 6 | 10 | ) : null 11 | } 12 | -------------------------------------------------------------------------------- /frontend/src/redux/account/reducer.js: -------------------------------------------------------------------------------- 1 | import * as ActionTypes from './actionTypes' 2 | 3 | const initialState = { 4 | registrations: [], 5 | } 6 | 7 | export default function reducer(state = initialState, action) { 8 | switch (action.type) { 9 | case ActionTypes.UPDATE_REGISTRATIONS: { 10 | return { 11 | ...state, 12 | registrations: action.payload, 13 | } 14 | } 15 | default: 16 | return state 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /frontend/src/components/animated/StaggeredListItem.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { motion } from 'framer-motion' 3 | 4 | const StaggeredListItem = props => { 5 | const variants = { 6 | visible: { 7 | opacity: 1, 8 | y: 0, 9 | }, 10 | hidden: { 11 | opacity: 0, 12 | y: props.staggerDistance || 50, 13 | }, 14 | } 15 | return 16 | } 17 | 18 | export default StaggeredListItem 19 | -------------------------------------------------------------------------------- /shared/constants/auth.js: -------------------------------------------------------------------------------- 1 | const Roles = { 2 | SUPER_ADMIN: 'SuperAdmin', 3 | ORGANISER: 'Organiser', 4 | ASSISTANT_ORGANISER: 'AssistantOrganiser', 5 | RECRUITER: 'Recruiter', 6 | } 7 | 8 | const Permissions = { 9 | CREATE_EVENT: 'create:event', 10 | MANAGE_EVENT: 'manage:event', 11 | DELETE_EVENT: 'delete:event', 12 | ACCESS_RECRUITMENT: 'access:recruitment', 13 | MANAGE_RECRUITMENT: 'manage:recruitment', 14 | } 15 | 16 | module.exports = { 17 | Roles, 18 | Permissions, 19 | } 20 | -------------------------------------------------------------------------------- /shared/schemas/Candidate.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose') 2 | const TeamRole = require('./TeamRole') 3 | 4 | const mongooseSchema = new mongoose.Schema({ 5 | userId: { 6 | type: String, 7 | required: true, 8 | }, 9 | roles: { 10 | type: [TeamRole.mongoose], 11 | required: true, 12 | default: [], 13 | }, 14 | motivation: { 15 | type: String, 16 | required: true, 17 | }, 18 | }) 19 | 20 | module.exports = { 21 | mongoose: mongooseSchema, 22 | } 23 | -------------------------------------------------------------------------------- /frontend/src/components/generic/LineDivider/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { makeStyles } from '@material-ui/core/styles' 3 | 4 | const useStyles = makeStyles(theme => ({ 5 | root: { 6 | height: '1px', 7 | background: '#f8f8f8', 8 | width: '100%', 9 | maxWidth: '640px', 10 | margin: '0 auto', 11 | }, 12 | })) 13 | 14 | const LineDivider = () => { 15 | const classes = useStyles() 16 | return
17 | } 18 | 19 | export default LineDivider 20 | -------------------------------------------------------------------------------- /shared/data/roles-other.json: -------------------------------------------------------------------------------- 1 | [ 2 | "Content Creator", 3 | "Entrepreneur", 4 | "Event Producer", 5 | "Founder", 6 | "Healthcare Professional", 7 | "Lawyer or Legal Professional", 8 | "Mathematician", 9 | "Physicist", 10 | "Psychologist", 11 | "Researcher", 12 | "Scientist", 13 | "Student", 14 | "Teacher or education specialist", 15 | "HR Specialist", 16 | "HR Director", 17 | "HR Generalist", 18 | "HR Manager", 19 | "HR Assistant", 20 | "HR Service Provider" 21 | ] 22 | -------------------------------------------------------------------------------- /shared/schemas/UserDetailsConfigItem.js: -------------------------------------------------------------------------------- 1 | const { GraphQLObjectType, GraphQLBoolean } = require('graphql') 2 | 3 | module.exports = { 4 | graphql: new GraphQLObjectType({ 5 | name: 'UserDetailsConfigItem', 6 | fields: { 7 | require: { 8 | type: GraphQLBoolean, 9 | }, 10 | enable: { 11 | type: GraphQLBoolean, 12 | }, 13 | editable: { 14 | type: GraphQLBoolean, 15 | }, 16 | }, 17 | }), 18 | } 19 | -------------------------------------------------------------------------------- /backend/common/services/google-calendar/token.json: -------------------------------------------------------------------------------- 1 | { 2 | "access_token": "ya29.a0AWY7Ckl7aCk5TvqSo3Lt-HSDwEWgolX718eVnoPFvEfdXcjLSByJ7HBK2tMxPnSgU8TItsluzhFTCCJZBjEYrff2ljdsvoKedx4UYpASxb-e8ZdTsBWWYF6_guNuJ0ivhJELS_v_I66k5UrgxsotP48gkVklaCgYKAWESARASFQG1tDrpDFQk2aE8PRheiSxruvE02Q0163", 3 | "refresh_token": "1//0cSsti3mKWoIrCgYIARAAGAwSNwF-L9IrVnM4q8qDiTfqQ0H69q1d9Y_t_4ua3SAHbZzYbi_07NKFBDQyKExuDpUAig2wNjz4kkE", 4 | "scope": "https://www.googleapis.com/auth/calendar", 5 | "token_type": "Bearer", 6 | "expiry_date": 1683801160546 7 | } 8 | -------------------------------------------------------------------------------- /shared/schemas/ScoreCriteria.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose') 2 | 3 | // TODO: The Project ref here might be an issue 4 | const ScoreCriteriaSchema = new mongoose.Schema({ 5 | criteria: { 6 | type: String, 7 | required: true, 8 | }, 9 | label: { 10 | type: String, 11 | required: true, 12 | }, 13 | score: { 14 | type: Number, 15 | // default: 0, 16 | required: true, 17 | }, 18 | }) 19 | 20 | module.exports = { 21 | mongoose: ScoreCriteriaSchema, 22 | } 23 | -------------------------------------------------------------------------------- /backend/modules/email-task/types.js: -------------------------------------------------------------------------------- 1 | const EmailTypes = { 2 | registrationAccepted: 'registration-accepted', 3 | registrationRejected: 'registration-rejected', 4 | registrationReceived: 'registration-received', 5 | travelGrantRejected: 'travelgrant-rejected', 6 | travelGrantAccepted: 'travelgrant-accepted', 7 | travelGrantDetailsRejected: 'travelgrant-details-rejected', 8 | travelGrantDetailsAccepted: 'travelgrant-details-accepted', 9 | recruiterMessage: 'recruiter-message', 10 | } 11 | 12 | module.exports = EmailTypes 13 | -------------------------------------------------------------------------------- /frontend/src/services/admin.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | const AdminService = {} 4 | 5 | function config(idToken) { 6 | return { 7 | headers: { 8 | Authorization: `Bearer ${idToken}`, 9 | }, 10 | } 11 | } 12 | 13 | AdminService.getRoles = idToken => { 14 | return axios.get('/admin/roles', config(idToken)).then(res => res.data) 15 | } 16 | 17 | AdminService.getUsers = idToken => { 18 | return axios.get('/admin/users', config(idToken)).then(res => res.data) 19 | } 20 | 21 | export default AdminService 22 | -------------------------------------------------------------------------------- /shared/constants/overall-reviewing-methods.js: -------------------------------------------------------------------------------- 1 | const OverallReviewingMethods = { 2 | finalsPublicVoting: { 3 | id: 'finalsPublicVoting', 4 | label: 'Finals, public voting', 5 | }, //TODO: test and fix, to remove create a migration 6 | finalsManualSelection: { 7 | id: 'finalsManualSelection', 8 | label: 'Finals, manual selection', 9 | }, 10 | noOverallWinner: { 11 | id: 'noOverallWinner', 12 | label: 'No overall winner', 13 | }, 14 | } 15 | 16 | module.exports = OverallReviewingMethods 17 | -------------------------------------------------------------------------------- /frontend/src/components/navbars/BasicNavBar/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import UserAvatar from 'components/UserAvatar' 3 | import LanguageMenu from 'components/LanguageMenu' 4 | 5 | const BasicNavBar = () => { 6 | return ( 7 |
8 |
9 | 10 | 11 |
12 |
13 | ) 14 | } 15 | 16 | export default BasicNavBar 17 | -------------------------------------------------------------------------------- /frontend/src/pages/_logout/index.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from 'react' 2 | 3 | import { useDispatch } from 'react-redux' 4 | import { push } from 'connected-react-router' 5 | import * as AuthActions from 'redux/auth/actions' 6 | 7 | import LoadingOverlay from 'components/loaders/LoadingOverlay' 8 | 9 | export default () => { 10 | const dispatch = useDispatch() 11 | 12 | useEffect(() => { 13 | dispatch(AuthActions.clearSession()) 14 | dispatch(push('/')) 15 | }, [dispatch]) 16 | 17 | return 18 | } 19 | -------------------------------------------------------------------------------- /backend/modules/files/model.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose') 2 | const Schema = mongoose.Schema 3 | 4 | const FileSchema = new Schema({ 5 | caption: { 6 | required: true, 7 | type: String, 8 | }, 9 | filename: { 10 | required: true, 11 | type: String, 12 | }, 13 | fileId: { 14 | required: true, 15 | type: String, 16 | }, 17 | createdAt: { 18 | default: Date.now(), 19 | type: Date, 20 | }, 21 | }) 22 | 23 | const File = mongoose.model('File', FileSchema) 24 | 25 | module.exports = File -------------------------------------------------------------------------------- /shared/data/roles-biz.json: -------------------------------------------------------------------------------- 1 | [ 2 | "Accountant", 3 | "Account Manager", 4 | "Analyst", 5 | "Business Angel", 6 | "Business Developer", 7 | "Communications Specialist", 8 | "Community Manager", 9 | "Copywriter", 10 | "Executive", 11 | "Growth Hacker", 12 | "HR Specialist", 13 | "Management Consultant", 14 | "Marketing", 15 | "Operations", 16 | "Product Manager", 17 | "Product Owner", 18 | "Public Relations", 19 | "Sales Associate", 20 | "Sales Engineer", 21 | "Strategist", 22 | "Venture Capitalist" 23 | ] 24 | -------------------------------------------------------------------------------- /backend/common/middleware/token.js: -------------------------------------------------------------------------------- 1 | const { UnauthorizedError } = require('../errors/errors') 2 | 3 | /** Token parsing logic has moved to misc/jwt.js and is run for every request. 4 | * The purpose of this middleware is to throw a 401 error if the JWT does not exist 5 | * or is invalid 6 | */ 7 | 8 | /* Verify JWT from client requests */ 9 | 10 | module.exports = { 11 | hasToken: (req, res, next) => { 12 | if (!req.user) { 13 | throw new UnauthorizedError('Authentication required') 14 | } else { 15 | next() 16 | } 17 | }, 18 | } 19 | -------------------------------------------------------------------------------- /backend/common/plugins/publicFields.js: -------------------------------------------------------------------------------- 1 | const _ = require('lodash') 2 | 3 | /** 4 | * Adds a new static method, getPublic, which returns only a subset of fields on the document 5 | */ 6 | 7 | function publicFieldsPlugin(schema, { fields = [] } = {}) { 8 | schema.statics.publicFields = function (docs) { 9 | if (Array.isArray(docs)) { 10 | return docs.map(doc => { 11 | return _.pick(doc.toJSON(), fields) 12 | }) 13 | } 14 | return _.pick(docs.toJSON(), fields) 15 | } 16 | } 17 | 18 | module.exports = publicFieldsPlugin 19 | -------------------------------------------------------------------------------- /frontend/src/components/plots/ReviewedAverage.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import Statistic from 'components/generic/Statistic' 4 | import StarIcon from '@material-ui/icons/Star' 5 | import { useSelector } from 'react-redux' 6 | import * as OrganiserSelectors from 'redux/organiser/selectors' 7 | 8 | export default () => { 9 | const value = useSelector(OrganiserSelectors.averageRating) 10 | return ( 11 | } 15 | /> 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /frontend/src/components/projects/ScoreCriteria/index.js: -------------------------------------------------------------------------------- 1 | const ScoreCriteriaBase = [ 2 | { 3 | criteria: 'creativity', 4 | label: 'Creativity', 5 | }, 6 | { 7 | criteria: 'innovation', 8 | label: 'Innovation', 9 | }, 10 | { 11 | criteria: 'problemSolving', 12 | label: 'Problem Solving', 13 | }, 14 | { 15 | criteria: 'companyFit', 16 | label: 'Company Fit', 17 | }, 18 | { 19 | criteria: 'teamwork', 20 | label: 'Teamwork', 21 | }, 22 | ] 23 | 24 | export default ScoreCriteriaBase 25 | -------------------------------------------------------------------------------- /frontend/src/pages/_dashboard/renderDashboard/organiser/participants/travel/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import { Box, Typography } from '@material-ui/core' 4 | 5 | export default () => { 6 | return ( 7 | 8 | 9 | This feature is currently unavailable 10 | 11 | 12 | This feature is currently unavailable, as it is undergoing some 13 | changes 14 | 15 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /backend/common/services/google-calendar/credentials.json: -------------------------------------------------------------------------------- 1 | { 2 | "installed": { 3 | "client_id": "752565208443-0g0ui7afokfi2b1t1von4qankq1vh62h.apps.googleusercontent.com", 4 | "project_id": "prod-calendar-386407", 5 | "auth_uri": "https://accounts.google.com/o/oauth2/auth", 6 | "token_uri": "https://oauth2.googleapis.com/token", 7 | "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", 8 | "client_secret": "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", 9 | "redirect_uris": [ 10 | "http://localhost" 11 | ] 12 | } 13 | } -------------------------------------------------------------------------------- /shared/data/themes.json: -------------------------------------------------------------------------------- 1 | [ 2 | "Artificial Intelligence", 3 | "Autonomous Vehicles", 4 | "Big Data", 5 | "Biohacking", 6 | "Blockchain", 7 | "Data Economics", 8 | "Data Visualization", 9 | "Digital Retail", 10 | "EdTech", 11 | "Entertainment", 12 | "FinTech", 13 | "Gaming", 14 | "HealthTech", 15 | "Intelligent Buildings", 16 | "Intelligent Infrastructure", 17 | "Internet of Things", 18 | "Machine learning", 19 | "Mobility", 20 | "Smart Cities", 21 | "Smart Cloud", 22 | "Space", 23 | "Virtual/Augmented/Mixed Reality" 24 | ] 25 | -------------------------------------------------------------------------------- /frontend/src/utils/stylingHelpers.js: -------------------------------------------------------------------------------- 1 | import gradientList from './constants/gradientList' 2 | 3 | export const gradientRandomizer = () => { 4 | return gradientList[Math.floor(Math.random() * gradientList.length)] 5 | } 6 | 7 | export const gradientSelector = (index = 0) => { 8 | if (index >= gradientList.length) { 9 | return gradientList[0] 10 | } 11 | return gradientList[index] 12 | } 13 | 14 | export const stringShortener = (str, length) => { 15 | if (str.length > length) { 16 | return `${str.substr(0, length)}...` 17 | } else { 18 | return str 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /backend/modules/newsletter/routes.js: -------------------------------------------------------------------------------- 1 | const express = require('express') 2 | 3 | const router = express.Router() 4 | const asyncHandler = require('express-async-handler') 5 | const SendgridService = require('../../common/services/sendgrid') 6 | 7 | const subscribeToNewsletter = asyncHandler(async (req, res) => { 8 | await SendgridService.subscribeToMailingList( 9 | req.body.email, 10 | req.body.country, 11 | global.gConfig.SENDGRID_MAILING_LIST_ID 12 | ) 13 | return res.sendStatus(200) 14 | }) 15 | 16 | router.route('/').post(subscribeToNewsletter) 17 | 18 | module.exports = router 19 | -------------------------------------------------------------------------------- /frontend/src/redux/account/actions.js: -------------------------------------------------------------------------------- 1 | import * as ActionTypes from './actionTypes' 2 | import * as AuthSelectors from '../auth/selectors' 3 | import RegistrationsService from 'services/registrations' 4 | 5 | export const updateRegistrations = () => async (dispatch, getState) => { 6 | const idToken = AuthSelectors.getIdToken(getState()) 7 | 8 | const registrations = await RegistrationsService.getUserRegistrations( 9 | idToken, 10 | ) 11 | 12 | dispatch({ 13 | type: ActionTypes.UPDATE_REGISTRATIONS, 14 | payload: registrations, 15 | }) 16 | 17 | return registrations 18 | } 19 | -------------------------------------------------------------------------------- /backend/common/services/discord.js: -------------------------------------------------------------------------------- 1 | const axios = require('axios') 2 | const Discord = require('discord.js') 3 | 4 | const client = new Discord.Client() 5 | const DiscordService = { 6 | initialize: () => { 7 | return new Promise((resolve, reject) => { 8 | client.once('ready', () => { 9 | console.log(client.users.map(user => user.email)) 10 | resolve(true) 11 | }) 12 | console.log(global.gConfig.DISCORD_BOT_TOKEN) 13 | client.login(global.gConfig.DISCORD_BOT_TOKEN) 14 | }) 15 | }, 16 | } 17 | module.exports = DiscordService 18 | -------------------------------------------------------------------------------- /frontend/src/styles/index.css: -------------------------------------------------------------------------------- 1 | @tailwind components; 2 | @tailwind utilities; 3 | /* CSS */ 4 | 5 | /* Create below composite classes, after you finish, from the /frontend directory, you must run the command 'npm run build:tailwind' to build tailwind css to see the changes on the development enviroment 6 | 7 | Any custom css, create it here and do not make any updates to the tailwind.css file, since it will be deleted every time tailwind build is executed*/ 8 | 9 | .tw-break-words-overflow { 10 | overflow-wrap: break-word; 11 | word-break: break-word; 12 | } 13 | .tw-rounded-02rem { 14 | border-radius: 0.2rem 15 | } 16 | -------------------------------------------------------------------------------- /shared/helpers/registration-fields.js: -------------------------------------------------------------------------------- 1 | const RegistrationFields = require('../constants/registration-fields') 2 | 3 | const RegistrationFieldsHelpers = { 4 | buildValidationSchema: (yup, fields) => { 5 | const schema = {} 6 | 7 | fields.forEach(({ fieldName, require }) => { 8 | const fieldParams = RegistrationFields.getField(fieldName) 9 | if (fieldParams) { 10 | schema[fieldName] = fieldParams.validationSchema(yup, require) 11 | } 12 | }) 13 | 14 | return schema 15 | }, 16 | } 17 | 18 | module.exports = RegistrationFieldsHelpers 19 | -------------------------------------------------------------------------------- /backend/migrations/06-finals-active-to-event.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose') 2 | const Promise = require('bluebird') 3 | 4 | module.exports = { 5 | index: 6, 6 | name: '06-finals-to-event', 7 | description: 'Add finals check to event', 8 | run: async () => { 9 | const res = await mongoose 10 | .model('Event') 11 | .updateMany( 12 | { finalsActive: { $exists: false } }, 13 | { $set: { finalsActive: false } }, 14 | ) 15 | 16 | console.log('Event', res.n, res.nModified) 17 | return Promise.resolve() 18 | }, 19 | } 20 | -------------------------------------------------------------------------------- /shared/constants/achievement-types.js: -------------------------------------------------------------------------------- 1 | /** The different types of achievements which can be given to projects */ 2 | 3 | const AchievementTypes = { 4 | trackPlacement: { 5 | id: 'trackPlacement', 6 | label: 'Track Placement', 7 | }, 8 | challengePlacement: { 9 | id: 'challengePlacement', 10 | label: 'Challenge Placement', 11 | }, 12 | overallPlacement: { 13 | id: 'overallPlacement', 14 | label: 'Overall Placement', 15 | }, 16 | finalist: { 17 | id: 'finalist', 18 | label: 'Finalist', 19 | }, 20 | } 21 | 22 | module.exports = AchievementTypes 23 | -------------------------------------------------------------------------------- /backend/migrations/04-add-finalists-to-event.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose') 2 | const Promise = require('bluebird') 3 | 4 | module.exports = { 5 | index: 4, 6 | name: '04-add-finalists-to-event', 7 | description: 'Add finalists in to event', 8 | run: async () => { 9 | const res = await mongoose 10 | .model('Event') 11 | .updateMany( 12 | { finalists: { $exists: false } }, 13 | { $set: { finalists: [] } }, 14 | ) 15 | console.log('Done with Events', res.n, res.nModified) 16 | 17 | return Promise.resolve() 18 | }, 19 | } 20 | -------------------------------------------------------------------------------- /frontend/src/components/inputs/BlockExitIfDirty/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const BlockExitIfDirty = props => { 4 | function unloadPage() { 5 | if (props.dirty) { 6 | return 'You have unsaved changes! Are you sure you want to leave this page?' 7 | } 8 | } 9 | 10 | React.useEffect(() => { 11 | window.onbeforeunload = unloadPage 12 | window.onpopstate = unloadPage 13 | 14 | return () => { 15 | window.onbeforeunload = null 16 | window.onpopstate = null 17 | } 18 | }) 19 | 20 | return null 21 | } 22 | 23 | export default BlockExitIfDirty 24 | -------------------------------------------------------------------------------- /frontend/src/pages/_dashboard/renderDashboard/organiser/projects/default/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { useSelector } from 'react-redux' 3 | import * as OrganiserSelectors from 'redux/organiser/selectors' 4 | import ProjectsTable from 'components/tables/ProjectsTable' 5 | import { filterProjectsWithTeam } from 'utils/dataModifiers' 6 | 7 | export default () => { 8 | const projects = useSelector(OrganiserSelectors.projects) 9 | const teams = useSelector(OrganiserSelectors.teams) 10 | 11 | const allProjectsWithTeam = filterProjectsWithTeam(projects, teams) 12 | return 13 | } 14 | -------------------------------------------------------------------------------- /frontend/src/components/inputs/EventTagsSelect/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import Select from 'components/inputs/Select' 4 | 5 | const EventTagsSelect = ({ 6 | value, 7 | onChange, 8 | tags = [], 9 | placeholder = 'Select tags', 10 | }) => { 11 | return ( 12 | ({ 19 | label: status.label, 20 | value: status.id, 21 | }))} 22 | /> 23 | ) 24 | } 25 | 26 | export default RegistrationStatusSelect 27 | -------------------------------------------------------------------------------- /backend/modules/reviewing/gavel/settings.js: -------------------------------------------------------------------------------- 1 | /** Gavel reviewing algorithm configuration options - don't change unless you really know what you're doing! */ 2 | 3 | const Settings = { 4 | /** Gavel algorithm math constants */ 5 | ALPHA_PRIOR: 10.0, 6 | BETA_PRIOR: 1.0, 7 | MU_PRIOR: 0.0, 8 | SIGMA_SQ_PRIOR: 1.0, 9 | GAMMA: 0.1, 10 | LAMBDA: 1.0, 11 | KAPPA: 0.0001, 12 | EPSILON: 0.25, 13 | /** How long must an annotator wait between votes? */ 14 | ANNOTATOR_WAIT_SECONDS: 45, 15 | /** How long after being assigned a project is an annotator considered inactive? */ 16 | ANNOTATOR_TIMEOUT_MINS: 5, 17 | /** How many views must a project have to no longer be automatically prioritised? */ 18 | ITEM_MIN_VIEWS: 5, 19 | } 20 | 21 | module.exports = Settings 22 | -------------------------------------------------------------------------------- /backend/modules/winner-votes/model.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose') 2 | 3 | const WinnerVoteSchema = new mongoose.Schema({ 4 | event: { 5 | type: mongoose.Schema.Types.ObjectId, 6 | ref: 'Event', 7 | required: true, 8 | }, 9 | user: { 10 | type: String, 11 | required: true, 12 | }, 13 | project: { 14 | type: mongoose.Schema.Types.ObjectId, 15 | ref: 'Project', 16 | required: true, 17 | }, 18 | }) 19 | 20 | WinnerVoteSchema.set('timestamps', true) 21 | WinnerVoteSchema.index( 22 | { 23 | user: 1, 24 | event: 1, 25 | }, 26 | { 27 | unique: true, 28 | }, 29 | ) 30 | 31 | const WinnerVote = mongoose.model('WinnerVote', WinnerVoteSchema) 32 | 33 | module.exports = WinnerVote 34 | -------------------------------------------------------------------------------- /backend/common/schemas/Achievement.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose') 2 | 3 | const TYPES = [ 4 | 'challenge-placement', 5 | 'track-placement', 6 | 'overall-placement', 7 | 'finalist', 8 | ] 9 | 10 | const AchievementSchema = new mongoose.Schema({ 11 | type: { 12 | type: String, 13 | required: true, 14 | validate: { 15 | validator(v) { 16 | return TYPES.indexOf(v) !== -1 17 | }, 18 | message: () => `Type should be one of ${TYPES.join(', ')}`, 19 | }, 20 | }, 21 | label: { 22 | type: String, 23 | }, 24 | value: { 25 | type: String, 26 | }, 27 | rank: { 28 | type: Number, 29 | min: 1, 30 | }, 31 | }) 32 | 33 | module.exports = AchievementSchema 34 | -------------------------------------------------------------------------------- /backend/modules/user-profile/helpers.js: -------------------------------------------------------------------------------- 1 | const { RegistrationFields } = require('@hackjunction/shared') 2 | const yup = require('yup') 3 | 4 | const UserProfileHelpers = { 5 | validate: data => { 6 | const validations = {} 7 | Object.keys(data).forEach(field => { 8 | const fieldConfig = RegistrationFields.getField(field) 9 | if (fieldConfig) { 10 | validations[field] = fieldConfig.validationSchema(false) 11 | } 12 | }) 13 | 14 | validations.avatar = yup 15 | .string() 16 | .url() 17 | .nullable() 18 | 19 | const schema = yup.object().shape(validations) 20 | return schema.validate(data, { stripUnknown: true }) 21 | }, 22 | } 23 | 24 | module.exports = UserProfileHelpers 25 | -------------------------------------------------------------------------------- /shared/constants/universities.js: -------------------------------------------------------------------------------- 1 | const universities = require('../data/universities.json') 2 | 3 | const Universities = {} 4 | 5 | const groupByAlpha2Code = () => { 6 | const grouped = {} 7 | 8 | universities.forEach(uni => { 9 | const alpha2 = uni.alpha_two_code 10 | if (grouped.hasOwnProperty(uni.alpha_two_code)) { 11 | grouped[alpha2].push(uni) 12 | } else { 13 | grouped[alpha2] = [uni] 14 | } 15 | }) 16 | 17 | return grouped 18 | } 19 | 20 | Universities.byAlpha2Code = groupByAlpha2Code() 21 | Universities.getByAlpha2Code = code => { 22 | if (code && Universities.byAlpha2Code.hasOwnProperty(code)) { 23 | return Universities.byAlpha2Code[code] 24 | } 25 | return [] 26 | } 27 | 28 | module.exports = Universities 29 | -------------------------------------------------------------------------------- /backend/migrations/18-add-event-newsletter-link-to-event.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose') 2 | const Promise = require('bluebird') 3 | 4 | module.exports = { 5 | index: 18, 6 | name: '18-add-event-newsletter-link-to-event', 7 | description: 'Add event newsletter link to event', 8 | run: async () => { 9 | // Update newsletter field 10 | const resNewsletter = await mongoose 11 | .model('Event') 12 | .updateMany( 13 | { newsletter: { $exists: false } }, 14 | { $set: { newsletter: '' } }, 15 | ) 16 | console.log( 17 | 'Done updating newsletter field', 18 | resNewsletter.n, 19 | resNewsletter.nModified, 20 | ) 21 | 22 | return Promise.resolve() 23 | }, 24 | } 25 | -------------------------------------------------------------------------------- /backend/modules/message/model.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose') 2 | 3 | const MessageSchema = new mongoose.Schema({ 4 | id: { 5 | type: String, 6 | required: true, 7 | unique: true, 8 | }, 9 | content: { 10 | type: String, 11 | required: true, 12 | }, 13 | recipients: { 14 | type: Array, 15 | required: true, 16 | default: [], 17 | }, 18 | sender: { 19 | type: String, 20 | required: true, 21 | }, 22 | sentAt: { 23 | type: Date, 24 | required: true, 25 | }, 26 | readAt: { 27 | type: Date, 28 | default: null, 29 | }, 30 | }) 31 | 32 | const Message = mongoose.model('Message', MessageSchema) 33 | 34 | module.exports = { 35 | Message, 36 | MessageSchema, 37 | } 38 | -------------------------------------------------------------------------------- /frontend/src/pages/_dashboard/renderDashboard/generalPages/default/Blocks/TimeLineBlock.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import { useSelector } from 'react-redux' 4 | import { Grid, Typography } from '@material-ui/core' 5 | 6 | import * as DashboardSelectors from 'redux/dashboard/selectors' 7 | 8 | 9 | import EventTimeline from 'pages/_events/slug/default/EventTimeline' 10 | 11 | export default () => { 12 | const event = useSelector(DashboardSelectors.event) 13 | return ( 14 | 15 | 16 | 21 | 22 | 23 | ) 24 | } 25 | // -------------------------------------------------------------------------------- /backend/migrations/28-add-gavel-login-to-registrations.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose') 2 | const Promise = require('bluebird') 3 | 4 | module.exports = { 5 | index: 28, 6 | name: '28-add-gavel-login-to-registrations', 7 | description: 'Add gavel login link to registrations', 8 | run: async () => { 9 | const addGavelLogin = await mongoose.model('Registration').updateMany( 10 | { gavelLogin: { $exists: false } }, 11 | { 12 | $set: { 13 | gavelLogin: '', 14 | }, 15 | }, 16 | ) 17 | 18 | console.log( 19 | 'Done adding gavel login link to registrations', 20 | addGavelLogin.n, 21 | addGavelLogin.nModified, 22 | ) 23 | 24 | return Promise.resolve() 25 | }, 26 | } 27 | -------------------------------------------------------------------------------- /frontend/src/constants/events.js: -------------------------------------------------------------------------------- 1 | const EventConstants = { 2 | STATUS: { 3 | Published: { 4 | id: 'Published', 5 | label: 'Published', 6 | index: 0, 7 | }, 8 | Registration: { 9 | id: 'Registration', 10 | label: 'Registration in progress', 11 | index: 1, 12 | }, 13 | Confirmation: { 14 | id: 'Confirmation', 15 | label: 'Confirm participation', 16 | index: 2, 17 | }, 18 | InProgress: { 19 | id: 'InProgress', 20 | label: 'InProgress', 21 | index: 3, 22 | }, 23 | Finished: { 24 | id: 'Finished', 25 | label: 'Finished', 26 | index: 4, 27 | }, 28 | }, 29 | } 30 | 31 | export default EventConstants 32 | -------------------------------------------------------------------------------- /backend/modules/voting-token/model.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose') 2 | 3 | const VotingTokenSchema = new mongoose.Schema({ 4 | name: { 5 | type: String, 6 | }, 7 | project: { 8 | type: mongoose.Schema.Types.ObjectId, 9 | ref: 'Project', 10 | }, 11 | event: { 12 | type: mongoose.Schema.Types.ObjectId, 13 | ref: 'Event', 14 | required: true, 15 | }, 16 | createdBy: { 17 | type: String, 18 | required: true, 19 | }, 20 | isRevoked: { 21 | type: Boolean, 22 | default: false, 23 | }, 24 | revokedAt: { 25 | type: Date, 26 | default: null, 27 | }, 28 | }) 29 | 30 | VotingTokenSchema.set('timestamps', true) 31 | 32 | const VotingToken = mongoose.model('VotingToken', VotingTokenSchema) 33 | 34 | module.exports = VotingToken 35 | -------------------------------------------------------------------------------- /frontend/src/components/generic/_Table/filterFunctions.js: -------------------------------------------------------------------------------- 1 | import * as FilterTypes from './filterTypes' 2 | 3 | export default { 4 | [FilterTypes.SINGLE_SELECT]: (rows, id, filterValue) => { 5 | if (!filterValue) return rows 6 | return rows.filter(row => row.values[id] === filterValue) 7 | }, 8 | [FilterTypes.MULTIPLE_SELECT]: (rows, id, filterValue) => { 9 | if (!Array.isArray(filterValue) || filterValue.length === 0) return rows 10 | return rows.filter(row => filterValue.indexOf(row.values[id]) !== -1) 11 | }, 12 | [FilterTypes.CONTAINS_SEARCH]: (rows, id, filterValue) => { 13 | return rows.filter(row => row.values[id]?.indexOf(filterValue) !== -1) 14 | }, 15 | [FilterTypes.EXACT_SEARCH]: (rows, id, filterValue) => { 16 | return rows.filter(row => row.values[id] === filterValue) 17 | }, 18 | } 19 | -------------------------------------------------------------------------------- /frontend/src/redux/user/selectors.js: -------------------------------------------------------------------------------- 1 | import { isEmpty } from 'lodash-es' 2 | 3 | export const hasProfile = state => !isEmpty(state.user.profile) 4 | export const userProfile = state => state.user.profile 5 | export const userProfileLoading = state => state.user.profileLoading 6 | export const userProfileError = state => state.user.profileError 7 | export const registrations = state => state.user.registrations 8 | export const registrationsLoading = state => state.user.registrationsLoading 9 | export const registrationsError = state => state.user.registrationsError 10 | export const userProfileRecruiterEvents = state => state.user.profile.recruiterEvents 11 | export const userProfileRegistrations = state => state.user.profile.registrations 12 | export const userAccessRight = state => state.user.accessRight 13 | export const organizerEvents = state => state.user.organizerEvents 14 | -------------------------------------------------------------------------------- /frontend/src/services/axios.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Custom axios service that: 3 | * - Checks that response format is application/json 4 | * - Returns the data field of the response 5 | * - Has the API url from config set as the baseURL, 6 | * 7 | * Use this with any calls you are making to the backend 8 | */ 9 | 10 | import axios from 'axios' 11 | 12 | const instance = axios.create({ 13 | baseURL: '/api', 14 | }) 15 | 16 | instance.interceptors.response.use( 17 | function (response) { 18 | if ( 19 | response.headers['content-type'].indexOf('application/json') !== -1 20 | ) { 21 | return response.data 22 | } 23 | return Promise.reject(new Error('Response was not application/json')) 24 | }, 25 | function (error) { 26 | return Promise.reject(error) 27 | }, 28 | ) 29 | 30 | export default instance 31 | -------------------------------------------------------------------------------- /backend/migrations/23-add-timeline-to-event.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose') 2 | const Promise = require('bluebird') 3 | 4 | module.exports = { 5 | index: 23, 6 | name: '23-add-timeline-to-event', 7 | description: 'add timeline event', 8 | run: async () => { 9 | const nres = await mongoose 10 | .model('Event') 11 | .updateMany( 12 | { eventTimeline: { $exists: false } }, 13 | { $set: { eventTimeline: { items: [] } } }, 14 | ) 15 | const bres = await mongoose 16 | .model('Event') 17 | .updateMany( 18 | { eventTimeline: null }, 19 | { $set: { eventTimeline: { items: [] } } }, 20 | ) 21 | console.info('Done with event timeline', nres.n, nres.nModified) 22 | return Promise.resolve() 23 | }, 24 | } 25 | -------------------------------------------------------------------------------- /backend/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["airbnb-base", "plugin:prettier/recommended"], 3 | "env": { 4 | "jest": true, 5 | "browser": true 6 | }, 7 | "rules": { 8 | "import/no-extraneous-dependencies": "off", 9 | "import/prefer-default-export": "off", 10 | "no-confusing-arrow": "off", 11 | "linebreak-style": "off", 12 | "arrow-parens": ["error", "as-needed"], 13 | "comma-dangle": [ 14 | "error", 15 | { 16 | "arrays": "always-multiline", 17 | "objects": "always-multiline", 18 | "imports": "always-multiline", 19 | "exports": "always-multiline", 20 | "functions": "ignore" 21 | } 22 | ], 23 | "no-plusplus": "off", 24 | "no-underscore-dangle": "off" 25 | }, 26 | "globals": { 27 | "browser": true, 28 | "$": true, 29 | "before": true, 30 | "document": true 31 | }, 32 | } 33 | -------------------------------------------------------------------------------- /shared/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["airbnb-base", "plugin:prettier/recommended"], 3 | "env": { 4 | "jest": true, 5 | "browser": true 6 | }, 7 | "rules": { 8 | "import/no-extraneous-dependencies": "off", 9 | "import/prefer-default-export": "off", 10 | "no-confusing-arrow": "off", 11 | "linebreak-style": "off", 12 | "arrow-parens": ["error", "as-needed"], 13 | "comma-dangle": [ 14 | "error", 15 | { 16 | "arrays": "always-multiline", 17 | "objects": "always-multiline", 18 | "imports": "always-multiline", 19 | "exports": "always-multiline", 20 | "functions": "ignore" 21 | } 22 | ], 23 | "no-plusplus": "off", 24 | "no-underscore-dangle": "off" 25 | }, 26 | "globals": { 27 | "browser": true, 28 | "$": true, 29 | "before": true, 30 | "document": true 31 | }, 32 | } 33 | -------------------------------------------------------------------------------- /backend/migrations/27-add-experimental-flag-to-events.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose') 2 | const Promise = require('bluebird') 3 | 4 | module.exports = { 5 | index: 27, 6 | name: '27-add-experimental-flag-to-events', 7 | description: 8 | 'Add new experimental flag to events, to allow events to use experimental features', 9 | run: async () => { 10 | const addExperimental = await mongoose.model('Event').updateMany( 11 | { experimental: { $exists: false } }, 12 | { 13 | $set: { 14 | experimental: false, 15 | }, 16 | }, 17 | ) 18 | 19 | console.log( 20 | 'Done adding experimental flag to events', 21 | addExperimental.n, 22 | addExperimental.nModified, 23 | ) 24 | 25 | return Promise.resolve() 26 | }, 27 | } 28 | -------------------------------------------------------------------------------- /frontend/src/pages/_events/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import { Route, Switch, Redirect } from 'react-router-dom' 4 | import { useRouteMatch } from 'react-router' 5 | 6 | import EventDetailRouter from './slug' 7 | import PastEvents from './past' 8 | import EventTracking from './slug/tracking' 9 | 10 | export default () => { 11 | const match = useRouteMatch() 12 | 13 | return ( 14 | 15 | 20 | 21 | {/** TODO: Consider adding a generic list of events at /events */} 22 | 23 | 24 | 25 | ) 26 | } 27 | -------------------------------------------------------------------------------- /shared/data/industries.json: -------------------------------------------------------------------------------- 1 | [ 2 | "Agriculture", 3 | "Audiovisual", 4 | "Banking & Finance", 5 | "Business, consulting & management", 6 | "Charity & voluntary work", 7 | "Creative arts & design", 8 | "Communications", 9 | "Energy & utilities", 10 | "Engineering & manufacturing", 11 | "Entertainment", 12 | "Environment & agriculture", 13 | "Food Industry", 14 | "Healthcare", 15 | "Hospitality & events management", 16 | "Law enforcement & security", 17 | "Law", 18 | "Leisure, sport & tourism", 19 | "Marketing, advertising & PR", 20 | "Media & internet", 21 | "Property & construction", 22 | "Public services & administration", 23 | "Recruitment & HR", 24 | "Retail", 25 | "Sales", 26 | "Science & pharmaceuticals", 27 | "Social care", 28 | "Teacher training & education", 29 | "Transport & logistics" 30 | ] 31 | -------------------------------------------------------------------------------- /backend/migrations/22-rename-team-tagline-to-subtitle.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose') 2 | const Promise = require('bluebird') 3 | const shortid = require('shortid') 4 | 5 | module.exports = { 6 | index: 22, 7 | name: '22-renamed-team-tagline-to-subtitle', 8 | description: 'Rename tagline to subtitle inside of the team model', 9 | run: async () => { 10 | const renameTaglineToSubtitle = await mongoose 11 | .model('Team') 12 | .updateMany( 13 | { tagline: { $exists: true } }, 14 | { $rename: { tagline: 'subtitle' } }, 15 | ) 16 | console.log( 17 | 'Done renaming tagline to subtitle', 18 | renameTaglineToSubtitle.n, 19 | renameTaglineToSubtitle.nModified, 20 | ) 21 | 22 | console.log('Done with migration 21') 23 | return Promise.resolve() 24 | }, 25 | } 26 | -------------------------------------------------------------------------------- /frontend/src/pages/_dashboard/renderDashboard/participant/reviewing/VoteTimer.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import moment from 'moment-timezone' 3 | import Countdown from 'react-countdown-now' 4 | import { Typography } from '@material-ui/core' 5 | 6 | export default ({ annotator, children }) => { 7 | return ( 8 | { 11 | if (!completed) { 12 | return ( 13 | 14 | You can submit a vote in {seconds} seconds. 15 | 16 | ) 17 | } else { 18 | return children 19 | } 20 | }} 21 | /> 22 | ) 23 | } 24 | -------------------------------------------------------------------------------- /backend/migrations/01-remove-project-unique-index.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose') 2 | const Promise = require('bluebird') 3 | const logger = require('../misc/logger') 4 | 5 | module.exports = { 6 | index: 1, 7 | name: '01-remove-project-unique-index', 8 | description: 'Remove unique team and event index from Project schema', 9 | run: async () => { 10 | const indexes = await mongoose.model('Project').listIndexes() 11 | const indexToDelete = indexes.find( 12 | index => index.name === 'event_1_team_1', 13 | ) 14 | if (indexToDelete) { 15 | await mongoose 16 | .model('Project') 17 | .collection.dropIndex(indexToDelete.name) 18 | logger.info(`Unique index dropped`) 19 | } else { 20 | logger.info(`-> No indexes to delete`) 21 | } 22 | return Promise.resolve() 23 | }, 24 | } 25 | -------------------------------------------------------------------------------- /backend/utils/permissions.js: -------------------------------------------------------------------------------- 1 | const PermissionsUtils = { 2 | userHasPermission: (user, requiredPermission) => { 3 | if (!user) return false 4 | return ( 5 | user && 6 | user.permissions && 7 | user.permissions.indexOf(requiredPermission) !== -1 8 | ) 9 | }, 10 | userHasPermissions: (user, requiredPermissions) => { 11 | if (!user) return false 12 | try { 13 | requiredPermissions.forEach(permission => { 14 | if (!PermissionsUtils.userHasPermission(user, permission)) { 15 | throw new Error( 16 | `User does not have a required permission: ${permission}`, 17 | ) 18 | } 19 | }) 20 | return true 21 | } catch (e) { 22 | return false 23 | } 24 | }, 25 | } 26 | 27 | module.exports = PermissionsUtils 28 | -------------------------------------------------------------------------------- /frontend/src/components/generic/_Table/filters/ContainsSearch.js: -------------------------------------------------------------------------------- 1 | import React, { useCallback } from 'react' 2 | import { TextField } from '@material-ui/core' 3 | 4 | import * as FilterTypes from '../filterTypes' 5 | 6 | const Component = ({ column }) => { 7 | const { filterValue, setFilter } = column 8 | const handleChange = useCallback( 9 | e => { 10 | setFilter(e.target.value) 11 | }, 12 | [setFilter], 13 | ) 14 | 15 | return ( 16 | 24 | ) 25 | } 26 | 27 | const ContainsSearchFilter = { 28 | Filter: Component, 29 | filter: FilterTypes.CONTAINS_SEARCH, 30 | } 31 | 32 | export default ContainsSearchFilter 33 | -------------------------------------------------------------------------------- /frontend/src/components/animated/FadeInWrapper.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { motion } from 'framer-motion' 3 | 4 | const FadeInWrapper = props => { 5 | const variants = { 6 | visible: { 7 | opacity: 1, 8 | y: 0, 9 | transition: { 10 | when: 'beforeChildren', 11 | duration: 0.2, 12 | delay: props.enterDelay || 0, 13 | }, 14 | }, 15 | hidden: { 16 | opacity: 0, 17 | y: props.verticalOffset || 0, 18 | transition: { 19 | duration: 0.2, 20 | }, 21 | }, 22 | } 23 | 24 | return ( 25 | 32 | ) 33 | } 34 | 35 | export default FadeInWrapper 36 | -------------------------------------------------------------------------------- /shared/schemas/CustomAnswer.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose') 2 | const { GraphQLObjectType, GraphQLString } = require('graphql') 3 | 4 | const mongooseSchema = new mongoose.Schema({ 5 | label: { 6 | type: String, 7 | }, 8 | section: { 9 | type: String, 10 | }, 11 | key: { 12 | type: String, 13 | }, 14 | value: { 15 | type: String, 16 | }, 17 | }) 18 | 19 | const graphqlSchema = new GraphQLObjectType({ 20 | name: 'CustomAnswer', 21 | fields: () => ({ 22 | label: { 23 | type: GraphQLString, 24 | }, 25 | section: { 26 | type: GraphQLString, 27 | }, 28 | key: { 29 | type: GraphQLString, 30 | }, 31 | value: { 32 | type: GraphQLString, 33 | }, 34 | }), 35 | }) 36 | 37 | module.exports = { 38 | mongoose: mongooseSchema, 39 | graphql: graphqlSchema, 40 | } 41 | -------------------------------------------------------------------------------- /frontend/src/hooks/apiHooks.js: -------------------------------------------------------------------------------- 1 | import { useState, useCallback } from 'react' 2 | 3 | export const usePromise = promise => { 4 | const [data, setData] = useState() 5 | const [loading, setLoading] = useState(true) 6 | const [error, setError] = useState(false) 7 | 8 | const handleDone = useCallback(data => { 9 | setData(data) 10 | setLoading(false) 11 | }, []) 12 | 13 | const handleErr = useCallback(err => { 14 | setLoading(false) 15 | setError(err) 16 | }, []) 17 | 18 | const fetch = useCallback( 19 | (...args) => { 20 | promise(...args) 21 | .then(data => { 22 | handleDone(data) 23 | }) 24 | .catch(err => { 25 | handleErr(err) 26 | }) 27 | }, 28 | [handleDone, handleErr, promise], 29 | ) 30 | 31 | return { data, loading, error, fetch } 32 | } 33 | -------------------------------------------------------------------------------- /frontend/src/pages/_dashboard/renderDashboard/partner/partnerrecruitment/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { useRouteMatch } from 'react-router' 3 | import { Switch, Route, Redirect } from 'react-router-dom' 4 | 5 | import SearchPage from './default' 6 | import DetailPage from './id' 7 | // TODO rework admin page to allow partners to manage their own teams 8 | // import AdminPage from './admin' 9 | 10 | export default () => { 11 | const match = useRouteMatch() 12 | return ( 13 | 14 | 15 | 20 | {/* */} 21 | 22 | 23 | ) 24 | } 25 | -------------------------------------------------------------------------------- /shared/schemas/LegalName.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose') 2 | const { GraphQLObjectType, GraphQLString, GraphQLNonNull } = require('graphql') 3 | 4 | const LegalNameSchema = new mongoose.Schema({ 5 | firstName: { 6 | required: true, 7 | type: String, 8 | }, 9 | middleName: { 10 | required: false, 11 | type: String, 12 | }, 13 | lastName: { 14 | required: true, 15 | type: String, 16 | }, 17 | }) 18 | 19 | const LegalNameType = new GraphQLObjectType({ 20 | name: 'LegalName', 21 | fields: { 22 | firstName: { 23 | type: GraphQLNonNull(GraphQLString), 24 | }, 25 | middleName: { 26 | type: GraphQLString, 27 | }, 28 | lastName: { 29 | type: GraphQLNonNull(GraphQLString), 30 | }, 31 | }, 32 | }) 33 | 34 | module.exports = { 35 | mongoose: LegalNameSchema, 36 | graphql: LegalNameType, 37 | } 38 | -------------------------------------------------------------------------------- /auth0/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "AUTH0_DOMAIN": ".eu.auth0.com", 3 | "AUTH0_CLIENT_ID": "", 4 | "AUTH0_CLIENT_SECRET": "", 5 | "AUTH0_KEYWORD_REPLACE_MAPPINGS": { 6 | "APP_CALLBACKS": [ 7 | "http://localhost:3000/callback", 8 | "http://localhost:3000" 9 | ], 10 | "APP_LOGOUT_URLS": [ 11 | "http://localhost:3000/logout", 12 | "http://localhost:3000" 13 | ], 14 | "AUDIENCE": "https://.eu.auth0.com/api/v2/", 15 | "APP_NAME_BACKEND": "Junction App Backend", 16 | "APP_NAME_FRONTEND": "Junction SSO", 17 | "AUTHZ_URL": "https://.webtask.io/adf6e2f2b84784b57522e3b19dfc9201", 18 | "URL": "https://localhost:3000" 19 | }, 20 | "EXCLUDED_PROPS": { 21 | "clients": ["client_secret"], 22 | "connections": ["options.client_secret"] 23 | }, 24 | "AUTH0_ALLOW_DELETE": true 25 | } 26 | -------------------------------------------------------------------------------- /backend/common/services/linkedin.js: -------------------------------------------------------------------------------- 1 | const axios = require('axios') 2 | 3 | const CLIENT_ID = '77gyr30dlraeob' 4 | const CLIENT_SECRET = 'jvMviXjTgjluzXN8' 5 | 6 | const LinkedInService = { 7 | getAccessToken: () => { 8 | return axios 9 | .post( 10 | `https://www.linkedin.com/oauth/v2/accessToken?grant_type=client_credentials&client_id=${CLIENT_ID}&client_secret=${CLIENT_SECRET}`, 11 | {}, 12 | { 13 | headers: { 14 | Host: 'www.linkedin.com', 15 | 'Content-Type': 'application/x-www-form-urlencoded', 16 | }, 17 | } 18 | ) 19 | .then(res => { 20 | console.log('getAccessToken', res) 21 | }) 22 | .catch(err => { 23 | console.log('getAccessToken err', err) 24 | }) 25 | }, 26 | } 27 | 28 | module.exports = LinkedInService 29 | -------------------------------------------------------------------------------- /backend/migrations/12-fix-empty-senderEmail-in-event: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose') 2 | const Promise = require('bluebird') 3 | 4 | module.exports = { 5 | index: 12, 6 | name: '12-fix-empty-senderEmail-in-event', 7 | description: 'Replace empty senderEmail with noreply@hackjunction.com', 8 | run: async () => { 9 | // Update emailConfig.senderEmail field for documents with an empty senderEmail 10 | const resSenderEmail = await mongoose 11 | .model('Event') 12 | .updateMany( 13 | { 'emailConfig.senderEmail': { $in: [null, ""] } }, 14 | { 15 | $set: { 16 | 'emailConfig.senderEmail': "noreply@hackjunction.com" 17 | } 18 | } 19 | ) 20 | 21 | console.log('Done updating empty senderEmail fields', resSenderEmail.n, resSenderEmail.nModified) 22 | 23 | return Promise.resolve() 24 | }, 25 | } -------------------------------------------------------------------------------- /frontend/src/pages/_events/slug/tracking/index.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react' 2 | 3 | import EventDetailContext, { EventDetailProvider } from '../context' 4 | import EventPageScript from 'components/events/EventPageScript' 5 | import { useParams } from 'react-router-dom' 6 | import { Helmet } from 'react-helmet' 7 | 8 | const EventTracking = () => { 9 | const { pageId } = useParams() 10 | const { event } = useContext(EventDetailContext) 11 | 12 | return ( 13 | <> 14 | {event && pageId && ( 15 | 16 | 17 | {event?.name} - Tracking - {pageId} 18 | 19 | 20 | )} 21 | 22 | 23 | 24 | ) 25 | } 26 | 27 | export default () => ( 28 | 29 | 30 | 31 | ) 32 | -------------------------------------------------------------------------------- /backend/migrations/26-fix-empty-senderEmail-in-event.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose') 2 | const Promise = require('bluebird') 3 | 4 | module.exports = { 5 | index: 26, 6 | name: '26-fix-empty-senderEmail-in-event', 7 | description: 'Replace empty senderEmail with noreply@hackjunction.com', 8 | run: async () => { 9 | // Update emailConfig.senderEmail field for documents with an empty senderEmail 10 | const resSenderEmail = await mongoose 11 | .model('Event') 12 | .updateMany( 13 | { 'emailConfig.senderEmail': { $in: [null, ""] } }, 14 | { 15 | $set: { 16 | 'emailConfig.senderEmail': "noreply@hackjunction.com" 17 | } 18 | } 19 | ) 20 | 21 | console.log('Done updating empty senderEmail fields', resSenderEmail.n, resSenderEmail.nModified) 22 | 23 | return Promise.resolve() 24 | }, 25 | } 26 | -------------------------------------------------------------------------------- /shared/schemas/IBANAccount.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose') 2 | const { GraphQLNonNull, GraphQLObjectType, GraphQLString } = require('graphql') 3 | 4 | const IBANAccountSchema = new mongoose.Schema({ 5 | accountNumber: { 6 | type: String, 7 | required: true, 8 | }, 9 | bankName: { 10 | type: String, 11 | required: true, 12 | }, 13 | swift: { 14 | type: String, 15 | required: true, 16 | }, 17 | }) 18 | 19 | const IBANAccountType = new GraphQLObjectType({ 20 | name: 'IBANAccount', 21 | fields: { 22 | accountNumber: { 23 | type: GraphQLNonNull(GraphQLString), 24 | }, 25 | bankName: { 26 | type: GraphQLNonNull(GraphQLString), 27 | }, 28 | swift: { 29 | type: GraphQLNonNull(GraphQLString), 30 | }, 31 | }, 32 | }) 33 | 34 | module.exports = { 35 | mongoose: IBANAccountSchema, 36 | graphql: IBANAccountType, 37 | } 38 | -------------------------------------------------------------------------------- /shared/schemas/Role.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose') 2 | const { GraphQLObjectType, GraphQLString, GraphQLInt } = require('graphql') 3 | const Roles = require('../constants/roles') 4 | 5 | const mongooseSchema = new mongoose.Schema({ 6 | role: { 7 | type: String, 8 | validate: { 9 | validator(v) { 10 | return Roles.items.indexOf(v) !== -1 11 | }, 12 | message: props => `${props.value} is not a valid role`, 13 | }, 14 | }, 15 | years: { 16 | type: Number, 17 | min: 1, 18 | max: 5, 19 | }, 20 | }) 21 | 22 | const graphqlSchema = new GraphQLObjectType({ 23 | name: 'Role', 24 | fields: () => ({ 25 | role: { 26 | type: GraphQLString, 27 | }, 28 | years: { 29 | type: GraphQLInt, 30 | }, 31 | }), 32 | }) 33 | 34 | module.exports = { 35 | mongoose: mongooseSchema, 36 | graphql: graphqlSchema, 37 | } 38 | -------------------------------------------------------------------------------- /backend/modules/email-task/model.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose') 2 | 3 | const EmailTaskSchema = new mongoose.Schema({ 4 | params: { 5 | type: mongoose.Schema.Types.Mixed, 6 | default: null, 7 | }, 8 | schedule: { 9 | type: Date, 10 | default: Date.now, 11 | }, 12 | deliveredAt: { 13 | type: Date, 14 | default: null, 15 | }, 16 | event: { 17 | type: String, 18 | required: true, 19 | }, 20 | user: { 21 | type: String, 22 | required: true, 23 | }, 24 | type: { 25 | type: String, 26 | required: true, 27 | }, 28 | }) 29 | 30 | EmailTaskSchema.set('timestamps', true) 31 | EmailTaskSchema.index( 32 | { 33 | event: 1, 34 | user: 1, 35 | type: 1, 36 | }, 37 | { 38 | unique: true, 39 | } 40 | ) 41 | 42 | const EmailTask = mongoose.model('EmailTask', EmailTaskSchema) 43 | 44 | module.exports = EmailTask 45 | -------------------------------------------------------------------------------- /frontend/src/redux/auth/reducer.js: -------------------------------------------------------------------------------- 1 | import * as ActionTypes from './actionTypes' 2 | 3 | const initialState = { 4 | session: {}, 5 | nextRoute: '/', 6 | } 7 | 8 | export default function reducer(state = initialState, action) { 9 | switch (action.type) { 10 | case ActionTypes.SET_SESSION: { 11 | return { 12 | ...state, 13 | session: action.payload, 14 | } 15 | } 16 | case ActionTypes.SET_NEXT_ROUTE: { 17 | return { 18 | ...state, 19 | nextRoute: action.payload, 20 | } 21 | } 22 | case ActionTypes.RESET_NEXT_ROUTE: { 23 | return { 24 | ...state, 25 | nextRoute: initialState.nextRoute, 26 | } 27 | } 28 | case ActionTypes.CLEAR_SESSION: { 29 | return initialState 30 | } 31 | 32 | default: 33 | return state 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /shared/constants/gradient-list.js: -------------------------------------------------------------------------------- 1 | const gradientList = [ 2 | 'tw-from-teal-400 tw-to-blue-500', 3 | 'tw-from-purple-400 tw-to-pink-500', 4 | 'tw-from-green-400 tw-to-blue-500', 5 | 'tw-from-yellow-400 tw-to-red-500', 6 | 'tw-from-red-400 tw-to-pink-500', 7 | 'tw-from-yellow-400 tw-to-orange-500', 8 | 'tw-from-green-400 tw-to-teal-500', 9 | 'tw-from-purple-400 tw-to-indigo-500', 10 | 'tw-from-blue-400 tw-to-purple-500', 11 | 'tw-from-red-400 tw-to-pink-500', 12 | 'tw-from-yellow-400 tw-to-orange-500', 13 | 'tw-from-green-400 tw-to-teal-500', 14 | 'tw-from-purple-400 tw-to-indigo-500', 15 | 'tw-from-blue-400 tw-to-purple-500', 16 | 'tw-from-red-400 tw-to-pink-500', 17 | 'tw-from-yellow-400 tw-to-orange-500', 18 | 'tw-from-green-400 tw-to-teal-500', 19 | 'tw-from-purple-400 tw-to-indigo-500', 20 | 'tw-from-blue-400 tw-to-purple-500', 21 | 'tw-from-red-400 tw-to-pink-500', 22 | ] 23 | 24 | module.exports = gradientList 25 | -------------------------------------------------------------------------------- /shared/schemas/Skill.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose') 2 | const { GraphQLObjectType, GraphQLString, GraphQLInt } = require('graphql') 3 | const Skills = require('../constants/skills') 4 | 5 | const mongooseSchema = new mongoose.Schema({ 6 | skill: { 7 | type: String, 8 | validate: { 9 | validator(v) { 10 | return Skills.items.indexOf(v) !== -1 11 | }, 12 | message: props => `${props.value} is not a valid skill`, 13 | }, 14 | }, 15 | level: { 16 | type: Number, 17 | min: 1, 18 | max: 5, 19 | }, 20 | }) 21 | 22 | const graphqlSchema = new GraphQLObjectType({ 23 | name: 'Skill', 24 | fields: () => ({ 25 | skill: { 26 | type: GraphQLString, 27 | }, 28 | level: { 29 | type: GraphQLInt, 30 | }, 31 | }), 32 | }) 33 | 34 | module.exports = { 35 | mongoose: mongooseSchema, 36 | graphql: graphqlSchema, 37 | } 38 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/--feature-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "✨ Feature request" 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 16 | 17 | **Is your feature request related to a problem? Please describe.** 18 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 19 | 20 | **Describe the solution you'd like** 21 | A clear and concise description of what you want to happen. 22 | 23 | **Describe alternatives you've considered** 24 | A clear and concise description of any alternative solutions or features you've considered. 25 | 26 | **Additional context** 27 | Add any other context or screenshots about the feature request here. 28 | -------------------------------------------------------------------------------- /backend/modules/reviewing/gavel/Decision.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose') 2 | 3 | const GavelDecisionSchema = new mongoose.Schema({ 4 | annotator: { 5 | type: mongoose.Schema.Types.ObjectId, 6 | ref: 'GavelAnnotator', 7 | required: true, 8 | }, 9 | event: { 10 | type: mongoose.Schema.Types.ObjectId, 11 | ref: 'Event', 12 | required: true, 13 | }, 14 | winner: { 15 | type: mongoose.Schema.Types.ObjectId, 16 | ref: 'GavelProject', 17 | required: true, 18 | }, 19 | loser: { 20 | type: mongoose.Schema.Types.ObjectId, 21 | ref: 'GavelProject', 22 | required: true, 23 | }, 24 | }) 25 | 26 | GavelDecisionSchema.set('timestamps', true) 27 | 28 | /** TODO: Is it necessary to index these? */ 29 | GavelDecisionSchema.index({ event: 1, annotator: 1 }) 30 | 31 | const GavelDecision = mongoose.model('GavelDecision', GavelDecisionSchema) 32 | 33 | module.exports = GavelDecision 34 | -------------------------------------------------------------------------------- /frontend/src/pages/_dashboard/renderDashboard/organiser/default/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import PageWrapper from 'components/layouts/PageWrapper' 4 | import GlobalNavBar from 'components/navbars/GlobalNavBar' 5 | import Footer from 'components/layouts/Footer' 6 | 7 | import Container from 'components/generic/Container' 8 | 9 | import NewEventForm from './NewEventForm' 10 | import EventsList from './EventsList' 11 | 12 | import { useMyEvents } from 'graphql/queries/events' 13 | 14 | export default () => { 15 | const [events, loading] = useMyEvents() 16 | 17 | return ( 18 | } 21 | footer={() =>