├── .github └── workflows │ ├── build-test.yml │ ├── build-workflow.yml │ ├── server_api_test.yml │ └── ssh-deploy.yml ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── SETUP.md ├── cache.md ├── new_client ├── .env ├── .gitignore ├── .npmrc ├── .prettierignore ├── .prettierrc ├── README.md ├── package.json ├── public │ ├── coc-icons │ │ ├── android-chrome-192x192.png │ │ ├── android-chrome-256x256.png │ │ ├── apple-touch-icon-114x114.png │ │ ├── apple-touch-icon-120x120.png │ │ ├── apple-touch-icon-144x144.png │ │ ├── apple-touch-icon-152x152.png │ │ ├── apple-touch-icon-180x180.png │ │ ├── apple-touch-icon-57x57.png │ │ ├── apple-touch-icon-60x60.png │ │ ├── apple-touch-icon-72x72.png │ │ ├── apple-touch-icon-76x76.png │ │ ├── apple-touch-icon.png │ │ ├── browserconfig.xml │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── favicon.ico │ │ ├── mstile-150x150.png │ │ └── safari-pinned-tab.svg │ ├── coc.jpeg │ ├── index.html │ ├── manifest.json │ ├── robots.txt │ ├── thumbnail.jpg │ └── thumbnail.png ├── src │ ├── App.js │ ├── ProtectedRoute.jsx │ ├── actions │ │ ├── authActions.js │ │ ├── errorActions.js │ │ └── types.js │ ├── components │ │ ├── 404 │ │ │ ├── NotFound.jsx │ │ │ └── SVG.jsx │ │ ├── Header.css │ │ ├── Header.js │ │ ├── Home │ │ │ ├── Home.jsx │ │ │ ├── Home.scss │ │ │ └── components │ │ │ │ ├── Achievements │ │ │ │ └── Achievements.jsx │ │ │ │ ├── Banner │ │ │ │ └── Banner.jsx │ │ │ │ ├── Description │ │ │ │ ├── Description.jsx │ │ │ │ └── Description.scss │ │ │ │ ├── Highlights │ │ │ │ ├── Highlight │ │ │ │ │ ├── Highlight.jsx │ │ │ │ │ └── Highlight.scss │ │ │ │ ├── Highlights.jsx │ │ │ │ └── Highlights.scss │ │ │ │ ├── Welcome │ │ │ │ ├── Welcome.jsx │ │ │ │ └── Welcome.scss │ │ │ │ └── assets │ │ │ │ └── banner.webp │ │ ├── Modal │ │ │ ├── Modal.css │ │ │ └── Modal.jsx │ │ ├── Utilities │ │ │ ├── Alert.jsx │ │ │ ├── BackButton.jsx │ │ │ ├── Backdrop.jsx │ │ │ ├── Banner.scss │ │ │ ├── COC.jsx │ │ │ ├── ScrollToTop.jsx │ │ │ ├── Title.jsx │ │ │ ├── overflowEllipsis.js │ │ │ └── useAuthenticatedAxios.js │ │ ├── about-us │ │ │ ├── AboutUs.css │ │ │ ├── AboutUs.jsx │ │ │ ├── Banner.jsx │ │ │ ├── GenericCard.jsx │ │ │ ├── GenericDetails.jsx │ │ │ ├── Image.jsx │ │ │ └── details.js │ │ ├── alumni │ │ │ ├── AlumniPage.jsx │ │ │ ├── AlumnusCard.jsx │ │ │ ├── Banner.jsx │ │ │ ├── MobileMenu.jsx │ │ │ └── SocialsArray.jsx │ │ ├── assets │ │ │ ├── COC.webp │ │ │ ├── COC_Full.webp │ │ │ ├── CP.webp │ │ │ ├── C_WS.webp │ │ │ ├── DEShaw.webp │ │ │ ├── Inheritance.webp │ │ │ ├── Tips-for-Making-Side-Projects.webp │ │ │ ├── about.webp │ │ │ ├── about_us.webp │ │ │ ├── alumni.jpeg │ │ │ ├── banner.webp │ │ │ ├── bg_signin.webp │ │ │ ├── bg_signup.webp │ │ │ ├── coc-gses.webp │ │ │ ├── coc-members.webp │ │ │ ├── coc_dark.webp │ │ │ ├── collaborate.webp │ │ │ ├── events.webp │ │ │ ├── experience.webp │ │ │ ├── learn.webp │ │ │ ├── magazines.webp │ │ │ ├── photo_11.webp │ │ │ ├── photo_12.webp │ │ │ └── projects.webp │ │ ├── auth │ │ │ ├── Error.css │ │ │ ├── NewPw.jsx │ │ │ ├── PasswordField.jsx │ │ │ ├── ResetPw.jsx │ │ │ ├── Signin.jsx │ │ │ ├── Signup.jsx │ │ │ └── VerifyEmail.jsx │ │ ├── blogs │ │ │ ├── AddBlog.jsx │ │ │ ├── Blog.jsx │ │ │ ├── Blogs.css │ │ │ ├── Editor.jsx │ │ │ ├── IndividualBlog.jsx │ │ │ └── SyntaxHighlighter.jsx │ │ ├── events │ │ │ ├── AddEvent.jsx │ │ │ ├── Banner.jsx │ │ │ ├── EventList.css │ │ │ ├── EventList.jsx │ │ │ ├── EventPage.css │ │ │ ├── EventPage.jsx │ │ │ ├── IndividualEvent.jsx │ │ │ ├── RegisterButton.jsx │ │ │ └── RegisterEvent.jsx │ │ ├── experiences │ │ │ ├── AddCompany.jsx │ │ │ ├── Banner.jsx │ │ │ ├── CompanyList.jsx │ │ │ ├── ExperienceList.jsx │ │ │ ├── ManageCompanies.jsx │ │ │ ├── ManageExperiences.jsx │ │ │ ├── MyExperiences.jsx │ │ │ ├── ReadExperience.jsx │ │ │ ├── VerifyExperience.jsx │ │ │ └── WriteExperience.jsx │ │ ├── footer │ │ │ ├── Footer.css │ │ │ ├── Footer.js │ │ │ └── footerStyle.js │ │ ├── glimpses │ │ │ ├── Glimpse.jsx │ │ │ ├── IndividualGlimpse.jsx │ │ │ └── IndividualImageGalllery.jsx │ │ ├── magazines │ │ │ ├── AddMagazine.jsx │ │ │ ├── Banner.jsx │ │ │ ├── IndividualMagazineCard.jsx │ │ │ ├── MagazineModal.jsx │ │ │ └── Magazines.jsx │ │ ├── projects │ │ │ ├── Banner.jsx │ │ │ ├── IndividualProjectCard.jsx │ │ │ ├── ProjectGroupCard.jsx │ │ │ ├── ProjectList.jsx │ │ │ ├── ProjectModal.jsx │ │ │ └── Projects.jsx │ │ ├── resources │ │ │ ├── Resource.jsx │ │ │ ├── ResourcePage.jsx │ │ │ └── Topic.jsx │ │ └── spinner │ │ │ ├── Spinner.css │ │ │ └── Spinner.jsx │ ├── index.css │ ├── index.js │ ├── logo.svg │ ├── reducers │ │ ├── authReducer.js │ │ ├── errorReducer.js │ │ └── index.js │ ├── serviceWorker.js │ ├── setupTests.js │ └── store │ │ └── configureStore.js └── yarn.lock ├── package.json ├── prod └── nginx.conf ├── server ├── .env.example ├── .eslintrc.json ├── .gitignore ├── .npmrc ├── package.json ├── src │ ├── app.js │ ├── config │ │ ├── dbconnect.js │ │ ├── index.js │ │ ├── redis.js │ │ └── sib.js │ ├── controllers │ │ ├── AchievementsController.js │ │ ├── AlumniController.js │ │ ├── AuthController.js │ │ ├── Blogs.js │ │ ├── CompanyController.js │ │ ├── DomainController.js │ │ ├── EthVJTIController.js │ │ ├── Events.js │ │ ├── GlimpseController.js │ │ ├── InterviewController.js │ │ ├── MagazineController.js │ │ ├── ProjectController.js │ │ ├── Register.js │ │ └── ResourcesController.js │ ├── middleware │ │ ├── auth.js │ │ ├── blog.js │ │ ├── cache.js │ │ ├── event.js │ │ ├── upload.js │ │ └── user.js │ ├── models │ │ ├── Achievement.js │ │ ├── Alumnus.js │ │ ├── Blog.js │ │ ├── Company.js │ │ ├── Domain.js │ │ ├── EthVJTIWallet.js │ │ ├── Event.js │ │ ├── FormElement.js │ │ ├── GLimpses.js │ │ ├── Interview.js │ │ ├── Magazine.js │ │ ├── Project.js │ │ ├── RegisterForm.js │ │ ├── Resources.js │ │ └── User.js │ ├── routes.js │ ├── utility │ │ ├── crypt.js │ │ ├── eventRescheduler.js │ │ ├── extractPhotos.js │ │ ├── getBaseURL.js │ │ ├── getEncPassword.js │ │ ├── getMailOptions.js │ │ ├── insert.js │ │ ├── replaceDriveURL.js │ │ ├── scheduler.js │ │ └── sendEmail.js │ └── views │ │ ├── emailVerification.ejs │ │ ├── eventReminder.ejs │ │ ├── eventRsvp.ejs │ │ ├── forgotPassword.ejs │ │ ├── partials │ │ ├── base.ejs │ │ ├── footer.ejs │ │ └── header.ejs │ │ └── view.js ├── test │ ├── api │ │ ├── blogs_test.js │ │ ├── events_test.js │ │ └── users_test.js │ └── test_helper.js └── uploads │ ├── 010005318b2fe0c83f26d482b261d97f │ ├── 2815bb07c5ee99459487475e32ff5a8f │ ├── 51ca0e888fab2e8396370a0ac8ff1231 │ ├── 7f91b0468cab55575d11fc94a31adf29 │ ├── 8b20dcb16dce18c83488e6d1d3688e8e │ ├── 97122fcf6b9f76fdb164348974712e80 │ ├── a3122a26109526aa384414dd4d7be8c6 │ ├── a5e90613a602fbf9f9a84ebaee1451f1 │ ├── a62563021f1a907365fec1a7393c28dd │ └── df08f0d1cf7bf29acc7aabcd1152af2e └── yarn.lock /.github/workflows/build-test.yml: -------------------------------------------------------------------------------- 1 | name: Build for Testing 2 | on: 3 | pull_request: 4 | types: [opened, synchronized] 5 | jobs: 6 | build: 7 | runs-on: ubuntu-18.04 8 | strategy: 9 | matrix: 10 | node-version: [16.x] 11 | 12 | steps: 13 | - uses: actions/checkout@v2 14 | - name: Use Node.js ${{ matrix.node-version }} 15 | uses: actions/setup-node@v1 16 | with: 17 | node-version: ${{ matrix.node-version }} 18 | - name: Creating react static build 19 | run: | 20 | yarn 21 | yarn workspace coc-client build 22 | env: 23 | CI: false 24 | -------------------------------------------------------------------------------- /.github/workflows/build-workflow.yml: -------------------------------------------------------------------------------- 1 | name: Build and Release 2 | on: 3 | push: 4 | branches: 5 | - prod 6 | jobs: 7 | build: 8 | runs-on: ubuntu-18.04 9 | strategy: 10 | matrix: 11 | node-version: [16.x] 12 | 13 | steps: 14 | - uses: actions/checkout@v2 15 | - name: Use Node.js ${{ matrix.node-version }} 16 | uses: actions/setup-node@v1 17 | with: 18 | node-version: ${{ matrix.node-version }} 19 | - name: Creating react static build 20 | run: | 21 | yarn 22 | yarn workspace coc-client build 23 | env: 24 | CI: false 25 | - name: Compressing server source code and frontend build folders 26 | run: | 27 | tar -zcf server.tar.gz ./server 28 | tar -zcf client.tar.gz ./new_client/build 29 | env: 30 | CI: false 31 | - name: Generate release tag 32 | id: tag 33 | run: | 34 | echo "::set-output name=release_tag::Release-$(date +"%Y.%m.%d-%H%M")" 35 | - name: Uploading assets to release 36 | uses: softprops/action-gh-release@v1 37 | with: 38 | tag_name: ${{ steps.tag.outputs.release_tag }} 39 | files: | 40 | server.tar.gz 41 | client.tar.gz 42 | -------------------------------------------------------------------------------- /.github/workflows/server_api_test.yml: -------------------------------------------------------------------------------- 1 | name: Server API Test 2 | on: 3 | push: 4 | branches: 5 | - master 6 | pull_request: 7 | branches: 8 | - master 9 | jobs: 10 | test: 11 | runs-on: ${{ matrix.os }} 12 | strategy: 13 | matrix: 14 | node-version: [10, 12] 15 | os: [ubuntu-latest] 16 | mongodb-version: [4.0] 17 | steps: 18 | - uses: actions/checkout@v1 19 | - name: Use Node.js ${{ matrix.node-version }} 20 | uses: actions/setup-node@v1 21 | with: 22 | node-version: ${{ matrix.node-version }} 23 | - name: Start MongoDB 24 | uses: supercharge/mongodb-github-action@1.3.0 25 | with: 26 | mongodb-version: ${{ matrix.mongodb-version }} 27 | - name: Installing dependencies and Running tests 28 | run: | 29 | cd server 30 | npm install 31 | npm test 32 | env: 33 | CI: true 34 | ENCPASSWORD: ${{ secrets.ENCPASSWORD }} 35 | CRYPTOKEY: ${{ secrets.CRYPTOKEY }} -------------------------------------------------------------------------------- /.github/workflows/ssh-deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy via SSH 2 | on: 3 | workflow_dispatch: 4 | inputs: 5 | logLevel: 6 | description: 'Log level' 7 | required: true 8 | default: 'debug' 9 | workflow_run: 10 | workflows: ["Build and Release"] 11 | types: 12 | - completed 13 | jobs: 14 | deploy: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Deploying 18 | uses: appleboy/ssh-action@v0.1.4 19 | with: 20 | host: ${{ secrets.HOST }} 21 | username: ${{ secrets.USERNAME }} 22 | key: ${{ secrets.PRIVKEY }} 23 | script: | 24 | pm2 stop all 25 | pm2 delete all 26 | bash cleanup.sh 27 | wget https://github.com/CommunityOfCoders/COCWebsite/releases/latest/download/server.tar.gz 28 | wget https://github.com/CommunityOfCoders/COCWebsite/releases/latest/download/client.tar.gz 29 | tar -xzf server.tar.gz 30 | tar -xzf client.tar.gz 31 | cp .env server/ 32 | cd server && yarn 33 | NODE_ENV=production pm2 start -n "coc-server" src/app.js 34 | -------------------------------------------------------------------------------- /.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 | /package-lock.json 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .vscode 16 | .DS_Store 17 | .env.local 18 | .env.development.local 19 | .env.test.local 20 | .env.production.local 21 | 22 | npm-debug.log* 23 | yarn-debug.log* 24 | yarn-error.log* -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to COCWebsite 2 | We love your input! We want to make contributing to this project as easy and transparent as possible, whether it's: 3 | 4 | - Reporting a bug 5 | - Discussing the current state of the code 6 | - Submitting a fix 7 | - Proposing new features 8 | 9 | ## We Develop with Github 10 | We use github to host code, to track issues and feature requests, as well as accept pull requests. 11 | 12 | ## All Code Changes Happen Through Pull Requests 13 | Pull requests are the best way to propose changes to the codebase (we use [Github Flow](https://guides.github.com/introduction/flow/index.html)). We actively welcome your pull requests: 14 | 15 | 1. Fork the repo and create your branch from `master`. 16 | 2. If you've added code that should be tested, add tests. 17 | 3. Make sure your code lints. 18 | 4. Issue that pull request! 19 | 20 | ## Any contributions you make will be under the GNU GPL 3.0 License 21 | In short, when you submit code changes, your submissions are understood to be under the same [GNU GPL 3.0 License](https://choosealicense.com/licenses/gpl-3.0/) that covers the project. Feel free to contact the maintainers if that's a concern. 22 | 23 | ## Report bugs using Github's [issues](https://github.com/CommunityOfCoders/COCWebsite/issues) 24 | We use GitHub issues to track public bugs. Report a bug by [opening a new issue](https://github.com/CommunityOfCoders/COCWebsite/issues/new); it's that easy! 25 | 26 | ## Use a Consistent Coding Style 27 | 28 | We have prettier in the client-side, and we prefer to have a consistent code format. 29 | 30 | * You can try running `npm run format` or have `husky` do that for you in a pre-commit git hook for style unification. 31 | 32 | ## License 33 | By contributing, you agree that your contributions will be licensed under its GNU GPL 3.0 License. 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![banner](https://res.cloudinary.com/coc-vjti/image/upload/v1614606865/logo_with_name_s2aduw.jpg) 2 | 3 | [![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-sucess.svg)](https://gitHub.com/CommunityOfCoders/COCWebsite/graphs/commit-activity) 4 | [![Issues Open](https://img.shields.io/github/issues/CommunityOfCoders/COCWebsite)](https://github.com/CommunityOfCoders/COCWebsite/issues) 5 | [![Forks](https://img.shields.io/github/forks/CommunityOfCoders/COCWebsite)](https://github.com/CommunityOfCoders/COCWebsite/network/members) 6 | [![Stars](https://img.shields.io/github/stars/CommunityOfCoders/COCWebsite)](https://github.com/CommunityOfCoders/COCWebsite/stargazers) 7 | [![GitHub contributors](https://img.shields.io/github/contributors/CommunityOfCoders/COCWebsite)](https://gitHub.com/CommunityOfCoders/COCWebsite/graphs/contributors/) 8 | [![PRs welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat)](https://github.com/dwyl/esta/issues) 9 | 10 | Welcome to the official website of the Community Of Coders! 11 | 12 | ## Setup 13 | 14 | Please read our [Setup Guide](https://github.com/CommunityOfCoders/COCWebsite/blob/master/SETUP.md) to get started with local development. 15 | 16 | ## Contributing 17 | 18 | Please read our [Contributing Guide](https://github.com/CommunityOfCoders/COCWebsite/blob/master/CONTRIBUTING.md) before submitting a Pull Request to the project. 19 | 20 | ## License 21 | 22 | See the [LICENSE](https://github.com/CommunityOfCoders/COCWebsite/blob/master/LICENSE) file for licensing information. 23 | -------------------------------------------------------------------------------- /SETUP.md: -------------------------------------------------------------------------------- 1 | # SETUP 2 | 3 | To setup a local development environment, follow the steps given below. 4 | 5 | 1. Ensure you have NodeJS, npm, yarn and redis installed in your system. 6 | 2. Fork and then clone the repository 7 | 8 | ```bash 9 | $ git clone https://github.com//COCWebsite.git 10 | ``` 11 | 12 | 3. Install dependencies in both folders. 13 | 14 | ```bash 15 | $ yarn 16 | ``` 17 | 18 | 4. Generate environment variables in `server` and fill in the values. 19 | 20 | ```bash 21 | $ cp server/.env.example .env 22 | ``` 23 | 24 | > Your `.env` is ignored by `git`, which you can see in `.gitignore`, and so, it's safe! 25 | 26 | 5. Start the development servers 27 | 28 | ```bash 29 | $ yarn dev 30 | ``` 31 | 32 | At the end of this, you should have 33 | 34 | - server running at `http://localhost:8000` 35 | - new_client running at `http://localhost:3000` 36 | - redis running at PORT `6379` 37 | 38 | ## Adding/ Removing packages 39 | 40 | The project is a monorepo, and dependencies are managed using Yarn Workspaces. To add a new package, follow the steps below. 41 | 42 | - For adding/ removing a dependency in server 43 | 44 | ```bash 45 | $ yarn workspace coc-server add/remove 46 | ``` 47 | 48 | - For adding a dependency in new_client 49 | 50 | ```bash 51 | $ yarn workspace coc-client add/remove 52 | ``` 53 | 54 | ## Folder structure 55 | 56 | Our folder structure 57 | 58 | ``` 59 | . 60 | ├── package.json # Maintains the dependencies using Yarn Workspaces 61 | ├── yarn.lock # Lock file 62 | ├── new_client 63 | │ ├── public # Stores public files like index.html 64 | │ └── src 65 | │ ├── actions # Redux actions and types 66 | │ ├── reducers # Redux reducers 67 | │ ├── store # Redux store 68 | │ └── components 69 | │ └── auth # A component directory 70 | └── server 71 | ├── src 72 | │ ├── config 73 | │ │ ├── dbconnect.js # Database connections. 74 | │ │ ├── index.js # Config object 75 | │ │ └── redis.js # Redis connection 76 | │ ├── controllers 77 | │ │ └── AuthController.js # Sample controller 78 | │ ├── middleware 79 | │ │ └── auth.js # Express middleware 80 | │ ├── models 81 | │ │ └── User.js # Mongoose model 82 | │ ├── utility # Standard utilities 83 | │ ├── views # .ejs files for mails 84 | │ ├── app.js # Main server file 85 | │ └── routes.js # Express routes 86 | └── test 87 | ├── api 88 | │ └── users_test.js # Sample test file using mocha, chai 89 | └── test_helper.js # Test config initializers 90 | ``` 91 | 92 | ## Bug/ Feature Request 93 | 94 | Now that the development environment is all set up, head over to [Contributing](./CONTRIBUTING.md) to learn how to contribute to COCWebsite. 95 | -------------------------------------------------------------------------------- /cache.md: -------------------------------------------------------------------------------- 1 | # Cache 2 | 3 | Since we have a lot of end points, we decided that it is better we introduce some sort of cache mechanisms in our systems. This will help us in responding to queries faster, and a smoother UI. 4 | 5 | ## What we decided to cache 6 | 7 | This is a curated list of points where we decided to cache our results. 8 | 9 | 1. `/api/domains` 10 | 2. `/api/projects` 11 | 3. `/api/alumni` 12 | 4. `/api/topics` 13 | 5. `/api/achievements` 14 | 6. `/api/events` 15 | 16 | ## Stuff required for cache 17 | 18 | 1. The npm module `redis`. Details [here](https://www.npmjs.com/package/redis). 19 | 2. Redis installed on the system. Details [here](https://redis.io/). 20 | 21 | ## How to cache 22 | 23 | Ideally, we would want everything... fast. We use a middleware that helps us in setting key-values in our Redis store. The decision for what route to have that middleware is wholly and solely on the basis of what we want and the frequency with which we want. 24 | 25 | GET requests can be easily cached and attended to, but we need to take care of whenever we perform a write operation. 26 | 27 | Ideally the flow should be: 28 | 29 | | Method | Route | Decision | 30 | |--------|------------|-------------------------------------------------------------------------| 31 | | GET | `/api/all` | Choose wisely | 32 | | GET | `/api/one` | If in cache, return from store. Else return from DB and store in cache. | 33 | | POST | `/api/one` | Update cache. | 34 | | PUT | `/api/one` | Update cache. | 35 | | DELETE | `/api/one` | Remove from cache. | 36 | -------------------------------------------------------------------------------- /new_client/.env: -------------------------------------------------------------------------------- 1 | REACT_APP_API=https://www.communityofcoders.in/server/api -------------------------------------------------------------------------------- /new_client/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .vscode 16 | .DS_Store 17 | .env.local 18 | .env.development.local 19 | .env.test.local 20 | .env.production.local 21 | 22 | npm-debug.log* 23 | yarn-debug.log* 24 | yarn-error.log* -------------------------------------------------------------------------------- /new_client/.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true -------------------------------------------------------------------------------- /new_client/.prettierignore: -------------------------------------------------------------------------------- 1 | .prettierrc 2 | .npmrc 3 | public 4 | package.json 5 | package-lock.json 6 | node_modules 7 | .gitignore 8 | .prettierignore 9 | *.webp 10 | *.ttf 11 | *.jpeg 12 | *.pdf 13 | yarn.lock -------------------------------------------------------------------------------- /new_client/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "always", 3 | "jsxBracketSameLine": false, 4 | "jsxSingleQuote": false, 5 | "singleQuote": false, 6 | "semi": true, 7 | "tabWidth": 2, 8 | "trailingComma": "es5", 9 | "useTabs": false 10 | } -------------------------------------------------------------------------------- /new_client/README.md: -------------------------------------------------------------------------------- 1 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 2 | 3 | ## Available Scripts 4 | 5 | In the project directory, you can run: 6 | 7 | ### `yarn start` 8 | 9 | Runs the app in the development mode.
10 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 11 | 12 | The page will reload if you make edits.
13 | You will also see any lint errors in the console. 14 | 15 | ### `yarn test` 16 | 17 | Launches the test runner in the interactive watch mode.
18 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 19 | 20 | ### `yarn build` 21 | 22 | Builds the app for production to the `build` folder.
23 | It correctly bundles React in production mode and optimizes the build for the best performance. 24 | 25 | The build is minified and the filenames include the hashes.
26 | Your app is ready to be deployed! 27 | 28 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 29 | 30 | ### `yarn eject` 31 | 32 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!** 33 | 34 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 35 | 36 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. 37 | 38 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. 39 | 40 | ## Learn More 41 | 42 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 43 | 44 | To learn React, check out the [React documentation](https://reactjs.org/). 45 | 46 | ### Code Splitting 47 | 48 | This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting 49 | 50 | ### Analyzing the Bundle Size 51 | 52 | This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size 53 | 54 | ### Making a Progressive Web App 55 | 56 | This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app 57 | 58 | ### Advanced Configuration 59 | 60 | This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration 61 | 62 | ### Deployment 63 | 64 | This section has moved here: https://facebook.github.io/create-react-app/docs/deployment 65 | 66 | ### `yarn build` fails to minify 67 | 68 | This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify 69 | -------------------------------------------------------------------------------- /new_client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "coc-client", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@date-io/date-fns": "1.3.13", 7 | "@editorjs/code": "^2.7.0", 8 | "@editorjs/editorjs": "^2.23.2", 9 | "@editorjs/header": "^2.6.2", 10 | "@editorjs/image": "^2.6.2", 11 | "@editorjs/link": "^2.4.0", 12 | "@editorjs/list": "^1.7.0", 13 | "@editorjs/raw": "^2.3.0", 14 | "@editorjs/table": "^2.0.1", 15 | "@material-ui/core": "^4.9.10", 16 | "@material-ui/icons": "^4.9.1", 17 | "@material-ui/lab": "^4.0.0-alpha.56", 18 | "@material-ui/pickers": "^3.2.10", 19 | "@mui-treasury/components": "^1.9.2", 20 | "@mui-treasury/styles": "^1.13.1", 21 | "@testing-library/jest-dom": "^4.2.4", 22 | "@testing-library/react": "^9.3.2", 23 | "@testing-library/user-event": "^7.1.2", 24 | "axios": "^0.21.2", 25 | "bootstrap": "^4.4.1", 26 | "clsx": "^1.1.1", 27 | "date-fns": "^2.15.0", 28 | "editorjs-style": "^3.0.2", 29 | "jwt-decode": "^3.1.2", 30 | "react": "^16.13.1", 31 | "react-bootstrap": "^1.0.1", 32 | "react-card-flip": "^1.0.11", 33 | "react-confirm-alert": "^2.6.1", 34 | "react-dom": "^16.13.1", 35 | "react-image-gallery": "^1.0.8", 36 | "react-markdown": "^4.3.1", 37 | "react-material-ui-carousel": "^2.1.2", 38 | "react-mde": "^10.1.0", 39 | "react-redux": "^7.2.0", 40 | "react-router-dom": "^5.1.2", 41 | "react-scripts": "^3.4.3", 42 | "react-syntax-highlighter": "^13.0.0", 43 | "react-typed": "^1.2.0", 44 | "redux": "^4.0.5", 45 | "redux-thunk": "^2.3.0", 46 | "showdown": "^1.9.1", 47 | "typewriter-effect": "^2.15.0" 48 | }, 49 | "engines": { 50 | "node": ">=16.0.0", 51 | "npm": ">=8.0.0" 52 | }, 53 | "scripts": { 54 | "start": "react-scripts start", 55 | "build": "react-scripts build", 56 | "test": "react-scripts test", 57 | "eject": "react-scripts eject", 58 | "lint": "prettier --check .", 59 | "format": "prettier --write ." 60 | }, 61 | "husky": { 62 | "hooks": { 63 | "pre-commit": "lint-staged" 64 | } 65 | }, 66 | "lint-staged": { 67 | "*": "prettier --write" 68 | }, 69 | "eslintConfig": { 70 | "extends": "react-app" 71 | }, 72 | "browserslist": { 73 | "production": [ 74 | ">0.2%", 75 | "not dead", 76 | "not op_mini all" 77 | ], 78 | "development": [ 79 | "last 1 chrome version", 80 | "last 1 firefox version", 81 | "last 1 safari version" 82 | ] 83 | }, 84 | "devDependencies": { 85 | "husky": "^4.3.8", 86 | "lint-staged": "^10.5.3", 87 | "prettier": "2.2.1", 88 | "sass": "^1.49.7" 89 | } 90 | } -------------------------------------------------------------------------------- /new_client/public/coc-icons/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/new_client/public/coc-icons/android-chrome-192x192.png -------------------------------------------------------------------------------- /new_client/public/coc-icons/android-chrome-256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/new_client/public/coc-icons/android-chrome-256x256.png -------------------------------------------------------------------------------- /new_client/public/coc-icons/apple-touch-icon-114x114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/new_client/public/coc-icons/apple-touch-icon-114x114.png -------------------------------------------------------------------------------- /new_client/public/coc-icons/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/new_client/public/coc-icons/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /new_client/public/coc-icons/apple-touch-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/new_client/public/coc-icons/apple-touch-icon-144x144.png -------------------------------------------------------------------------------- /new_client/public/coc-icons/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/new_client/public/coc-icons/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /new_client/public/coc-icons/apple-touch-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/new_client/public/coc-icons/apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /new_client/public/coc-icons/apple-touch-icon-57x57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/new_client/public/coc-icons/apple-touch-icon-57x57.png -------------------------------------------------------------------------------- /new_client/public/coc-icons/apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/new_client/public/coc-icons/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /new_client/public/coc-icons/apple-touch-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/new_client/public/coc-icons/apple-touch-icon-72x72.png -------------------------------------------------------------------------------- /new_client/public/coc-icons/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/new_client/public/coc-icons/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /new_client/public/coc-icons/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/new_client/public/coc-icons/apple-touch-icon.png -------------------------------------------------------------------------------- /new_client/public/coc-icons/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #000000 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /new_client/public/coc-icons/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/new_client/public/coc-icons/favicon-16x16.png -------------------------------------------------------------------------------- /new_client/public/coc-icons/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/new_client/public/coc-icons/favicon-32x32.png -------------------------------------------------------------------------------- /new_client/public/coc-icons/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/new_client/public/coc-icons/favicon.ico -------------------------------------------------------------------------------- /new_client/public/coc-icons/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/new_client/public/coc-icons/mstile-150x150.png -------------------------------------------------------------------------------- /new_client/public/coc-icons/safari-pinned-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.11, written by Peter Selinger 2001-2013 9 | 10 | 12 | 17 | 23 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /new_client/public/coc.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/new_client/public/coc.jpeg -------------------------------------------------------------------------------- /new_client/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 16 | 22 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 39 | 40 | 41 | 42 | 43 | 44 | 48 | 49 | 58 | Community Of Coders 59 | 60 | 61 | 62 |
63 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /new_client/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "CoC VJTI", 3 | "name": "Community Of Coders, VJTI", 4 | "icons": [ 5 | { 6 | "src": "coc-icons/favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "coc-icons/android-chrome-192x192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "coc-icons/android-chrome-256x256.png", 17 | "type": "image/png", 18 | "sizes": "256x256" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /new_client/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /new_client/public/thumbnail.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/new_client/public/thumbnail.jpg -------------------------------------------------------------------------------- /new_client/public/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/new_client/public/thumbnail.png -------------------------------------------------------------------------------- /new_client/src/ProtectedRoute.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { connect } from "react-redux"; 3 | import { Redirect } from "react-router-dom"; 4 | 5 | const ProtectedRoute = (props) => { 6 | const Component = props.component; 7 | const isAuthenticated = props.isAuthenticated; 8 | 9 | return isAuthenticated ? ( 10 | 11 | ) : ( 12 | 13 | ); 14 | }; 15 | 16 | const mapStateToProps = (state) => ({ 17 | isAuthenticated: state.auth.isAuthenticated, 18 | }); 19 | 20 | export default connect(mapStateToProps)(ProtectedRoute); 21 | -------------------------------------------------------------------------------- /new_client/src/actions/authActions.js: -------------------------------------------------------------------------------- 1 | import { 2 | USER_LOADED, 3 | USER_LOADING, 4 | AUTH_ERROR, 5 | LOGIN_SUCCESS, 6 | LOGIN_FAIL, 7 | REGISTER_SUCCESS, 8 | REGISTER_FAIL, 9 | LOGOUT_SUCCESS, 10 | NEW_PASSWORD_SUCCESS, 11 | NEW_PASSWORD_FAIL, 12 | REFRESH_TOKENS, 13 | } from "./types"; 14 | import axios from "axios"; 15 | import { returnErrors } from "./errorActions"; 16 | 17 | export const loadUser = () => (dispatch, getState) => { 18 | dispatch({ type: USER_LOADING }); 19 | 20 | axios 21 | .get(process.env.REACT_APP_API + "/user", tokenConfig(getState)) 22 | .then((res) => res.json()) 23 | .then((res) => 24 | dispatch({ 25 | type: USER_LOADED, 26 | payload: res.data, 27 | }) 28 | ) 29 | .catch((err) => { 30 | dispatch(returnErrors(err.response.data, err.response.status)); 31 | dispatch({ 32 | type: AUTH_ERROR, 33 | }); 34 | }); 35 | }; 36 | 37 | export const register = ({ username, email, password, graduationYear }) => ( 38 | dispatch 39 | ) => { 40 | const config = { 41 | headers: { 42 | "Content-Type": "application/json", 43 | }, 44 | }; 45 | const body = JSON.stringify({ username, email, password, graduationYear }); 46 | axios 47 | .post(process.env.REACT_APP_API + "/register", body, config) 48 | .then((res) => { 49 | dispatch(returnErrors(res.data, res.status, REGISTER_SUCCESS)); 50 | }) 51 | .catch((err) => { 52 | dispatch( 53 | returnErrors(err.response.data, err.response.status, REGISTER_FAIL) 54 | ); 55 | dispatch({ 56 | type: REGISTER_FAIL, 57 | }); 58 | }); 59 | }; 60 | 61 | export const login = ({ username, password, rememberme }) => (dispatch) => { 62 | const config = { 63 | headers: { 64 | "Content-Type": "application/json", 65 | }, 66 | }; 67 | const body = JSON.stringify({ username, password, rememberme }); 68 | 69 | axios 70 | .post(process.env.REACT_APP_API + "/login", body, config) 71 | .then((res) => 72 | dispatch({ 73 | type: LOGIN_SUCCESS, 74 | payload: res.data, 75 | }) 76 | ) 77 | .catch((err) => { 78 | console.log(err); 79 | dispatch( 80 | returnErrors(err.response.data, err.response.status, LOGIN_FAIL) 81 | ); 82 | dispatch({ 83 | type: LOGIN_FAIL, 84 | }); 85 | }); 86 | }; 87 | 88 | export const newPassword = ({ newPassword, token }) => (dispatch) => { 89 | const config = { 90 | headers: { 91 | "Content-Type": "application/json", 92 | }, 93 | }; 94 | const body = JSON.stringify({ newPassword, token }); 95 | axios 96 | .post(process.env.REACT_APP_API + "/new-password", body, config) 97 | .then((res) => { 98 | dispatch({ 99 | type: NEW_PASSWORD_SUCCESS, 100 | payload: res.data, 101 | }); 102 | }) 103 | .catch((err) => { 104 | console.log(err); 105 | dispatch( 106 | returnErrors(err.response.data, err.response.status, NEW_PASSWORD_FAIL) 107 | ); 108 | dispatch({ 109 | type: NEW_PASSWORD_FAIL, 110 | }); 111 | }); 112 | }; 113 | 114 | export const logout = () => (dispatch) => { 115 | localStorage.removeItem("token"); 116 | dispatch({ 117 | type: LOGOUT_SUCCESS, 118 | }); 119 | }; 120 | 121 | export const tokenConfig = (getState) => { 122 | const token = getState().auth.token; 123 | const config = { 124 | headers: { 125 | "Content-type": "application/json", 126 | }, 127 | }; 128 | 129 | // If token, add to headers 130 | if (token) { 131 | config.headers["x-auth-token"] = token; 132 | } 133 | 134 | return config; 135 | }; 136 | -------------------------------------------------------------------------------- /new_client/src/actions/errorActions.js: -------------------------------------------------------------------------------- 1 | import { GET_ERRORS, CLEAR_ERRORS } from "./types"; 2 | 3 | export const returnErrors = (msg, status, id = null) => { 4 | return { 5 | type: GET_ERRORS, 6 | payload: { msg, status, id }, 7 | }; 8 | }; 9 | 10 | export const clearErrors = () => { 11 | return { 12 | type: CLEAR_ERRORS, 13 | }; 14 | }; 15 | -------------------------------------------------------------------------------- /new_client/src/actions/types.js: -------------------------------------------------------------------------------- 1 | export const REGISTER_USER = "REGISTER_USER"; 2 | export const LOGIN_USER = "LOGIN_USER"; 3 | export const USER_LOADING = "USER_LOADING"; 4 | export const USER_LOADED = "USER_LOADED"; 5 | export const AUTH_ERROR = "AUTH_ERROR"; 6 | export const LOGIN_SUCCESS = "LOGIN_SUCCESS"; 7 | export const LOGIN_FAIL = "LOGIN_FAIL"; 8 | export const REGISTER_SUCCESS = "REGISTER_SUCCESS"; 9 | export const REGISTER_FAIL = "REGISTER_FAIL"; 10 | export const REFRESH_TOKENS = "REFRESH_TOKENS"; 11 | export const GET_ERRORS = "GET_ERRORS"; 12 | export const CLEAR_ERRORS = "CLEAR_ERRORS"; 13 | export const LOGOUT_SUCCESS = "LOGOUT_SUCCESS"; 14 | export const NEW_PASSWORD_SUCCESS = "NEW_PASSWORD_SUCCESS"; 15 | export const NEW_PASSWORD_FAIL = "NEW_PASSWORD_FAIL"; 16 | -------------------------------------------------------------------------------- /new_client/src/components/404/NotFound.jsx: -------------------------------------------------------------------------------- 1 | import { Button, Container, Grid } from "@material-ui/core"; 2 | import React from "react"; 3 | import SVG from "./SVG"; 4 | 5 | export default function NotFound({ history }) { 6 | return ( 7 | 8 | 9 | 10 | 11 | 12 | 13 |

404

14 |

UH OH! You're lost.

15 |

16 | The page you are looking for does not exist. How you got here is a 17 | mystery. But you can click the button below to go back to the 18 | homepage. 19 |

20 | 27 |
28 | If you think there should be a page here, please create an issue at{" "} 29 | 30 | the website repository 31 | 32 | . 33 |
34 |
35 |
36 |
37 | ); 38 | } 39 | -------------------------------------------------------------------------------- /new_client/src/components/Home/Home.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useRef, useState } from "react"; 2 | import Banner from "./components/Banner/Banner"; 3 | import Welcome from "./components/Welcome/Welcome"; 4 | import Description from "./components/Description/Description"; 5 | import Highlights from "./components/Highlights/Highlights"; 6 | import Achievements from "./components/Achievements/Achievements"; 7 | import "./Home.scss"; 8 | 9 | const Home = () => { 10 | const [width, setWidth] = useState(window.innerWidth); 11 | 12 | useEffect(() => { 13 | window.addEventListener("resize", handleResize); 14 | 15 | return () => { 16 | window.removeEventListener("resize", handleResize); 17 | }; 18 | }, []); 19 | 20 | const handleResize = () => { 21 | setWidth(window.innerWidth); 22 | }; 23 | 24 | const scrollToRef = useRef(null); 25 | 26 | return ( 27 |
28 |
29 | 30 | 31 | 32 | 33 | 34 |
35 |
36 | ); 37 | }; 38 | 39 | export default Home; 40 | -------------------------------------------------------------------------------- /new_client/src/components/Home/Home.scss: -------------------------------------------------------------------------------- 1 | .Home { 2 | scroll-behavior: smooth; 3 | } 4 | -------------------------------------------------------------------------------- /new_client/src/components/Home/components/Achievements/Achievements.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import Carousel from "react-material-ui-carousel"; 3 | import axios from "axios"; 4 | import Card from "@material-ui/core/Card"; 5 | import { makeStyles } from "@material-ui/core/styles"; 6 | 7 | import "../Description/Description.scss"; 8 | import CardActions from "@material-ui/core/CardActions"; 9 | import CardContent from "@material-ui/core/CardContent"; 10 | import CardMedia from "@material-ui/core/CardMedia"; 11 | import Button from "@material-ui/core/Button"; 12 | import Typography from "@material-ui/core/Typography"; 13 | 14 | const useStyles = makeStyles({ 15 | carousel: { 16 | maxWidth: 700, 17 | }, 18 | root: { 19 | maxWidth: 500, 20 | }, 21 | media: { 22 | height: 250, 23 | }, 24 | actions: { 25 | alignItems: "center", 26 | display: "flex", 27 | }, 28 | }); 29 | 30 | const Achievements = (props) => { 31 | const [achievements, setAchievements] = useState([]); 32 | 33 | useEffect(() => { 34 | axios.get(process.env.REACT_APP_API + "/achievements").then((res) => { 35 | setAchievements(res.data); 36 | }); 37 | }, []); 38 | 39 | const classes = useStyles(); 40 | 41 | return ( 42 |
43 |
44 |
45 |

Our Achievements

46 |

47 | Our community helps our members build their skills and achieve their 48 | dreams.
49 | CoC is also where we celebrate those achievements. 50 |

51 |
52 | 57 | {achievements.map((item, i) => ( 58 | 59 | ))} 60 | 61 |
62 |
63 |
64 | ); 65 | }; 66 | 67 | const Item = (props) => { 68 | const classes = useStyles(); 69 | 70 | return ( 71 | 72 | 73 | 74 | 75 | {props.item.title} 76 | 77 | 78 | {props.item.description} 79 | 80 |
81 | 82 | By:
83 | {props.item.owner.fullName} 84 |
85 |
86 | 87 | 88 | 93 | 96 | 97 | {props.item.projectUrl ? ( 98 | 103 | Learn more 104 | 105 | ) : null} 106 | 107 |
108 | ); 109 | }; 110 | 111 | export default Achievements; 112 | -------------------------------------------------------------------------------- /new_client/src/components/Home/components/Banner/Banner.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import "../../../Utilities/Banner.scss"; 3 | import COC from "../../../assets/COC.webp"; 4 | 5 | const Banner = () => { 6 | return ( 7 |
8 |
9 |
10 | COC Logo PNG{" "} 11 | Community of Coders 12 |
13 |
14 |   IMAGINE   |   BELIEVE   |   ACHIEVE   15 |
16 |
17 | ); 18 | }; 19 | 20 | export default Banner; 21 | -------------------------------------------------------------------------------- /new_client/src/components/Home/components/Description/Description.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import "./Description.scss"; 3 | // import image from 'assets/home/linkedin.jpg'; 4 | 5 | const Description = (props) => { 6 | return ( 7 |
8 | {/*
*/} 9 |
10 |
11 |

Our Mission

12 | 13 |
14 |
15 | {/*
*/} 16 |
17 | ); 18 | }; 19 | 20 | const MissionContent = ({ width }) => { 21 | // The line doesn't evenly break until ~716px so we need to up it from 700px 22 | if (width < 720) { 23 | return ( 24 |

25 | To help students interested in the field of development and programming 26 | to meet other like‑minded students and to help them advance their 27 | careers. 28 |

29 | ); 30 | } else { 31 | return ( 32 | // eslint-disable-next-line 33 |

34 | To help students interested in the field of development and programming 35 | to meet other 36 |
37 | like‑minded students and to help them advance their careers. 38 |

39 | ); 40 | } 41 | }; 42 | 43 | export default Description; 44 | -------------------------------------------------------------------------------- /new_client/src/components/Home/components/Highlights/Highlight/Highlight.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Link } from "react-router-dom"; 3 | import "./Highlight.scss"; 4 | 5 | const Highlight = (props) => { 6 | return ( 7 |
11 |
12 |
13 |

{props.title}

14 |

{props.description}

15 | {props.linkText} → 16 |
17 | {props.imageAlt} 22 |
23 |
24 | ); 25 | }; 26 | 27 | export default Highlight; 28 | -------------------------------------------------------------------------------- /new_client/src/components/Home/components/Highlights/Highlight/Highlight.scss: -------------------------------------------------------------------------------- 1 | // Highlight component. 2 | 3 | .Highlight { 4 | // Mobile styles 5 | 6 | margin: 4rem 0 0 0; 7 | padding: 3rem 0; 8 | 9 | .highlight-container { 10 | margin: 0 auto; 11 | padding: 0 6.25vw; 12 | display: flex; 13 | flex-direction: column; 14 | 15 | .highlight-content { 16 | padding-left: 1.75vw; 17 | padding-right: 1.75vw; 18 | 19 | h2 { 20 | font-family: "Raleway", sans-serif; 21 | font-size: 2.5rem; 22 | font-weight: bold; 23 | } 24 | 25 | p { 26 | font-family: "Nunito", sans-serif; 27 | font-size: 1.25rem; 28 | } 29 | 30 | a { 31 | font-family: "Nunito", sans-serif; 32 | font-size: 1.5rem; 33 | color: #4d5eff; 34 | } 35 | } 36 | 37 | .highlight-image { 38 | margin: 2rem auto 0; 39 | height: auto; 40 | width: 100%; 41 | box-shadow: 0 0 25px rgba(0, 0, 0, 0.3); 42 | border-radius: 10px; 43 | } 44 | } 45 | 46 | // Tablet and Desktop styles 47 | 48 | // 700px (vertical tablets and horizontal phones) 49 | // Landscape and tablet optimized layout 50 | @media screen and (min-width: 43.75rem) { 51 | padding: 4rem 0; 52 | 53 | .highlight-container { 54 | padding: 0 5vw; 55 | 56 | // Padding for landscape iPhones with notch 57 | // @supports (padding: max(0px)) { 58 | // @media screen and (orientation: landscape) { 59 | // padding-left: max(5vw, calc(env(safe-area-inset-left) + 1rem)); 60 | // padding-right: max(5vw, calc(env(safe-area-inset-right) + 1rem)); 61 | // } 62 | // } 63 | 64 | align-items: center; 65 | justify-content: space-between; 66 | 67 | .highlight-content { 68 | padding-left: 0; 69 | padding-right: 0; 70 | width: 47.5%; 71 | 72 | h2 { 73 | font-size: 2.5rem; 74 | } 75 | 76 | a { 77 | font-size: 1.5rem; 78 | } 79 | } 80 | 81 | .highlight-image { 82 | margin: 0; 83 | width: 47.5%; 84 | border-radius: 20px; 85 | } 86 | } 87 | 88 | // Row format for highlights 89 | .highlight-container.highlight-learn, 90 | .highlight-container.highlight-network { 91 | flex-direction: row-reverse; 92 | } 93 | 94 | .highlight-container.highlight-collaborate { 95 | flex-direction: row; 96 | } 97 | } 98 | 99 | // 1024px (horizontal tablets) 100 | // Use full size layout and font size 101 | @media screen and (min-width: 64rem) { 102 | .highlight-container { 103 | .highlight-content { 104 | width: 44%; 105 | 106 | h2 { 107 | font-size: 3rem; 108 | } 109 | 110 | p { 111 | font-size: 1.25rem; 112 | } 113 | } 114 | 115 | .highlight-image { 116 | width: 50%; 117 | } 118 | } 119 | } 120 | 121 | // 1366px (medium laptops and above) 122 | // Use max-width over padding for larger screens 123 | @media screen and (min-width: 85.375rem) { 124 | .highlight-container { 125 | padding: 0; 126 | max-width: 76.875rem; // 1230px 127 | } 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /new_client/src/components/Home/components/Highlights/Highlights.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Highlight from "./Highlight/Highlight"; 3 | import "./Highlights.scss"; 4 | 5 | import learn from "../../../assets/learn.webp"; 6 | import collaborate from "../../../assets/collaborate.webp"; 7 | // import network from 'assets/home/highlights/network.jpg'; 8 | 9 | const descriptions = [ 10 | // Learn 11 | `Whether you’ve never even seen a line of code before or you’ve written 12 | full-stack applications that scale, we’ve got you covered. With workshops, competitive coding challenges, and more, there’s plenty of ways to gain 13 | new skills and level up your career. Our exciting events, ranging from 14 | beginner to advanced, will get you up and running with your first 15 | website or how to deploy your application on the cloud.`, 16 | 17 | // Collaborate 18 | `Teamwork makes the dream work! Find team members to work on a project 19 | with, form your winning hackathon team, or practice mock interviewing 20 | with others and score your dream job. Do you love making websites/ apps? We've got you covered. 21 | Do you wish to explore the path of Competitive Programming? 22 | We've got mentors that can help you get on track, ready to achieve your dreams.`, 23 | 24 | // Network 25 | ]; 26 | 27 | const Highlights = () => { 28 | return ( 29 |
30 | {/* Learn */} 31 | 41 | 42 | {/* Collaborate */} 43 | 53 | 54 | {/* Network */} 55 | {/* */} 65 |
66 | ); 67 | }; 68 | 69 | export default Highlights; 70 | -------------------------------------------------------------------------------- /new_client/src/components/Home/components/Highlights/Highlights.scss: -------------------------------------------------------------------------------- 1 | // Highlights section of the homepage. 2 | 3 | .Highlights { 4 | margin: 5rem auto 0; 5 | } 6 | -------------------------------------------------------------------------------- /new_client/src/components/Home/components/assets/banner.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/new_client/src/components/Home/components/assets/banner.webp -------------------------------------------------------------------------------- /new_client/src/components/Modal/Modal.css: -------------------------------------------------------------------------------- 1 | .modal-backdrop { 2 | width: 100%; 3 | height: 100%; 4 | position: fixed; 5 | z-index: 100; 6 | left: 0; 7 | top: 0; 8 | background-color: rgba(0, 0, 0, 0.5); 9 | } 10 | -------------------------------------------------------------------------------- /new_client/src/components/Modal/Modal.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Modal, Button } from "react-bootstrap"; 3 | import "./Modal.css"; 4 | 5 | const ModalComp = (props) => { 6 | return ( 7 | 16 | 17 | {props.header} 18 | 19 | {props.children} 20 | 21 | 24 | {props.hasBtn ? ( 25 | 28 | ) : null} 29 | 30 | 31 | ); 32 | }; 33 | 34 | export default ModalComp; 35 | -------------------------------------------------------------------------------- /new_client/src/components/Utilities/Alert.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { makeStyles, Snackbar } from "@material-ui/core"; 3 | import MuiAlert from "@material-ui/lab/Alert"; 4 | import Backdrop from "./Backdrop"; 5 | 6 | const useStyles = makeStyles((theme) => ({ 7 | alert: { 8 | width: "100%", 9 | zIndex: "500", 10 | "& > * + *": { 11 | marginTop: theme.spacing(2), 12 | }, 13 | }, 14 | })); 15 | 16 | // const AlertUtility = props => { 17 | // return ; 18 | // }; 19 | 20 | const Alert = (props) => { 21 | const classes = useStyles(); 22 | return ( 23 | 24 | 25 |
26 | 31 | 37 | {props.message} 38 | 39 | 40 |
41 |
42 | ); 43 | }; 44 | 45 | export default Alert; 46 | -------------------------------------------------------------------------------- /new_client/src/components/Utilities/BackButton.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ArrowBackIcon from "@material-ui/icons/ArrowBack"; 3 | import { Link } from "react-router-dom"; 4 | 5 | export default function BackButton({ link }) { 6 | return ( 7 |
8 | 9 | 10 | Go Back 11 | 12 | 13 |
14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /new_client/src/components/Utilities/Backdrop.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { makeStyles } from "@material-ui/core"; 3 | 4 | const useStyles = makeStyles((theme) => ({ 5 | backdrop: { 6 | width: "100%", 7 | height: "100%", 8 | position: "fixed", 9 | zIndex: "100", 10 | left: "0", 11 | top: "0", 12 | backgroundColor: "rgba(0, 0, 0, 0.5)", 13 | }, 14 | })); 15 | 16 | const Backdrop = (props) => { 17 | const classes = useStyles(); 18 | return props.show ? ( 19 |
20 | ) : null; 21 | }; 22 | 23 | export default Backdrop; 24 | -------------------------------------------------------------------------------- /new_client/src/components/Utilities/Banner.scss: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: "Recharge Bold"; 3 | src: url("https://res.cloudinary.com/coc-vjti/raw/upload/v1613468201/recharge.bold_ck77rq.ttf") 4 | format("truetype"), 5 | local("Recharge Bold"); 6 | font-display: swap; 7 | } 8 | 9 | @mixin Banner($page) { 10 | position: relative; 11 | text-align: center; 12 | margin-top: 0%; 13 | 14 | .parallax { 15 | /* Create the parallax scrolling effect */ 16 | background-attachment: fixed; 17 | background-position: center; 18 | background-repeat: no-repeat; 19 | background-size: cover; 20 | @media only screen and (max-width: 1080px) { 21 | background-attachment: scroll; 22 | } 23 | @if $page == "Home" { 24 | /* The image used */ 25 | background-image: url("../Home/components/assets/banner.webp"); 26 | 27 | /* Set a specific height */ 28 | min-height: 100vh; 29 | } @else if $page == "Event" { 30 | /* The image used */ 31 | background-image: linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), 32 | url("../assets/events.webp"); 33 | 34 | /* Set a specific height */ 35 | min-height: 100vh; 36 | } @else if $page == "Alumni" { 37 | background-image: url("../assets/alumni.jpeg"); 38 | @media only screen and (min-width: 992px) { 39 | min-height: 100vh; 40 | background-size: cover; 41 | } 42 | @media only screen and (max-width: 992px) { 43 | // 1.63 is the aspect of alumni.jpeg 44 | min-height: calc(100vw / 1.63); 45 | background-size: contain; 46 | background-position: unset; 47 | } 48 | } @else if $page == "AboutUs" { 49 | background-image: linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), 50 | url("../assets/about_us.webp"); 51 | min-height: 100vh; 52 | } @else if $page == "Projects" { 53 | background-image: linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), 54 | url("../assets/projects.webp"); 55 | min-height: 100vh; 56 | } @else if $page == "Magazines" { 57 | background-image: linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), 58 | url("../assets/magazines.webp"); 59 | min-height: 100vh; 60 | } @else if $page == "Experience" { 61 | background-image: linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), 62 | url("../assets/experience.webp"); 63 | min-height: 100vh; 64 | } 65 | } 66 | 67 | .banner-center { 68 | font-family: "Recharge Bold", -apple-system, BlinkMacSystemFont, "Segoe UI", 69 | Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", 70 | sans-serif; 71 | font-weight: bold; 72 | color: white; 73 | font-size: 6vh; 74 | position: absolute; 75 | top: 50%; 76 | left: 50%; 77 | transform: translate(-50%, -50%); 78 | } 79 | .banner-text { 80 | margin-top: 4vh; 81 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, 82 | Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif; 83 | font-weight: regular; 84 | font-size: 4vh; 85 | color: white; 86 | position: absolute; 87 | top: 70%; 88 | left: 50%; 89 | transform: translate(-50%, -50%); 90 | display: flex; 91 | } 92 | 93 | @media only screen and (max-width: 600px) { 94 | .banner-center { 95 | font-size: 5vh; 96 | } 97 | 98 | .banner-text { 99 | font-size: 2.5vh; 100 | } 101 | } 102 | } 103 | section.homeBanner { 104 | @include Banner("Home"); 105 | } 106 | section.eventBanner { 107 | @include Banner("Event"); 108 | } 109 | section.alumniBanner { 110 | @include Banner("Alumni"); 111 | } 112 | section.aboutUsBanner { 113 | @include Banner("AboutUs"); 114 | } 115 | section.projectsBanner { 116 | @include Banner("Projects"); 117 | } 118 | section.magazinesBanner { 119 | @include Banner("Magazines"); 120 | } 121 | section.experienceBanner { 122 | @include Banner("Experience"); 123 | } 124 | -------------------------------------------------------------------------------- /new_client/src/components/Utilities/COC.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | export default function COC() { 4 | return ( 5 | <> 6 | Co 7 | C 8 | 9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /new_client/src/components/Utilities/ScrollToTop.jsx: -------------------------------------------------------------------------------- 1 | import { useEffect } from "react"; 2 | import { useLocation } from "react-router-dom"; 3 | 4 | export default function ScrollToTop() { 5 | const { pathname } = useLocation(); 6 | 7 | useEffect(() => { 8 | window.scrollTo(0, 0); 9 | }, [pathname]); 10 | 11 | return null; 12 | } 13 | -------------------------------------------------------------------------------- /new_client/src/components/Utilities/Title.jsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import PropTypes from "prop-types"; 3 | import Typography from "@material-ui/core/Typography"; 4 | 5 | function Title(props) { 6 | return ( 7 |
8 | 9 | {props.children} 10 | 11 |
12 | ); 13 | } 14 | 15 | Title.propTypes = { 16 | children: PropTypes.node, 17 | }; 18 | 19 | export default Title; 20 | -------------------------------------------------------------------------------- /new_client/src/components/Utilities/overflowEllipsis.js: -------------------------------------------------------------------------------- 1 | export const overflowEllipsis = (givenString) => { 2 | const numberOfChars = 150; 3 | let isOverflow = false; 4 | let returnString = givenString; 5 | 6 | if (givenString.length > numberOfChars) { 7 | returnString = givenString.substring(0, numberOfChars - 3) + "..."; 8 | isOverflow = true; 9 | } 10 | 11 | return { display: returnString, isOverflow: isOverflow }; 12 | }; 13 | -------------------------------------------------------------------------------- /new_client/src/components/Utilities/useAuthenticatedAxios.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import jwt_decode from "jwt-decode"; 3 | import { useSelector, useDispatch } from "react-redux"; 4 | import { useHistory } from "react-router-dom"; 5 | import { REFRESH_TOKENS, LOGOUT_SUCCESS } from "../../actions/types"; 6 | 7 | const useAuthenticatedAxios = () => { 8 | const token = useSelector((state) => state.auth.token); 9 | const refreshToken = useSelector((state) => state.auth.refreshToken); 10 | const userID = useSelector((state) => state.auth.userID); 11 | const dispatch = useDispatch(); 12 | const history = useHistory(); 13 | 14 | // Custom Axios Instace 15 | const axiosInstance = axios.create({ 16 | baseURL: "", 17 | headers: { Authorization: `Bearer ${token}` }, 18 | }); 19 | 20 | axiosInstance.interceptors.request.use(async (req) => { 21 | // Check if Access Token is expired 22 | const user = jwt_decode(token); 23 | const expiryDateAccessToken = new Date(user.exp * 1000); 24 | const isExpired = new Date() > expiryDateAccessToken; 25 | if (!isExpired) return req; 26 | 27 | // Check if Refresh Token is expired 28 | const refreshDecode = jwt_decode(refreshToken); 29 | const expiryDateRefreshToken = new Date(refreshDecode.exp * 1000); 30 | const isRefreshExpired = new Date() > expiryDateRefreshToken; 31 | if (isRefreshExpired) { 32 | dispatch({ 33 | type: LOGOUT_SUCCESS, 34 | }); 35 | history.push("/signin"); 36 | return Promise.reject(); 37 | } 38 | 39 | // Update Refresh Tokens 40 | const response = await axios.post( 41 | `${process.env.REACT_APP_API}/refresh-tokens`, 42 | { 43 | refreshToken: refreshToken, 44 | uid: userID, 45 | } 46 | ); 47 | 48 | // Dispatch to Refresh the new tokens in state and localStorage 49 | dispatch({ 50 | type: REFRESH_TOKENS, 51 | payload: { 52 | token: response.data.token, 53 | refreshToken: response.data.refreshToken, 54 | }, 55 | }); 56 | 57 | req.headers.Authorization = `Bearer ${response.data.token}`; 58 | 59 | return req; 60 | }); 61 | 62 | return axiosInstance; 63 | }; 64 | 65 | export default useAuthenticatedAxios; 66 | -------------------------------------------------------------------------------- /new_client/src/components/about-us/AboutUs.css: -------------------------------------------------------------------------------- 1 | .root { 2 | background-color: #eee; 3 | padding: 2rem; 4 | } 5 | 6 | .paragraph { 7 | width: 60%; 8 | margin-left: auto; 9 | margin-right: auto; 10 | } 11 | 12 | .secretaries-image { 13 | width: 50vw; 14 | } 15 | 16 | .image-card { 17 | width: 30vw; 18 | height: 50vh; 19 | border-top-left-radius: 1rem; 20 | border-top-right-radius: 1rem; 21 | display: flex; 22 | justify-content: center; 23 | align-items: center; 24 | overflow: hidden; 25 | } 26 | 27 | .shadow-1 { 28 | box-shadow: 2px 2px rgba(0, 0, 0, 0.3); 29 | } 30 | 31 | .com-mem { 32 | display: flex; 33 | flex-direction: row; 34 | margin: 20px 0px; 35 | justify-content: space-evenly; 36 | align-items: center; 37 | } 38 | 39 | .gene-sec-cont { 40 | display: flex; 41 | flex-direction: row; 42 | align-items: center; 43 | justify-content: center; 44 | } 45 | 46 | .image-cont { 47 | margin: 3rem; 48 | align-content: center; 49 | } 50 | 51 | .image-name { 52 | border-bottom-left-radius: 1rem; 53 | border-bottom-right-radius: 1rem; 54 | font-size: 1.3rem; 55 | padding-top: 5px; 56 | padding-bottom: 5px; 57 | } 58 | 59 | .position { 60 | color: rgb(67, 200, 62); 61 | } 62 | 63 | .team-image { 64 | width: 80vw; 65 | } 66 | 67 | .member { 68 | width: 25vw; 69 | height: 35vh; 70 | } 71 | 72 | @media only screen and (max-width: 768px) { 73 | .paragraph { 74 | width: fit-content; 75 | margin: 0 0.5rem; 76 | } 77 | .secretaries-image { 78 | width: 80vw; 79 | } 80 | 81 | .gene-sec-cont { 82 | flex-direction: column; 83 | } 84 | 85 | .image-card { 86 | width: 70vw; 87 | } 88 | 89 | .image-cont { 90 | margin: 12px 0px; 91 | } 92 | 93 | .member { 94 | width: 40vw; 95 | height: 35vh; 96 | } 97 | } 98 | 99 | @media only screen and (min-width: 768px) { 100 | .paragraph, 101 | .paragraph-side { 102 | font-size: 1.5rem; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /new_client/src/components/about-us/Banner.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import "../Utilities/Banner.scss"; 3 | 4 | function Banner() { 5 | return ( 6 |
7 |
8 |
About Us
9 |
10 | ); 11 | } 12 | 13 | export default Banner; 14 | -------------------------------------------------------------------------------- /new_client/src/components/about-us/GenericCard.jsx: -------------------------------------------------------------------------------- 1 | import { makeStyles, Tooltip } from "@material-ui/core"; 2 | import React from "react"; 3 | 4 | const useStyles = makeStyles((theme) => ({ 5 | root: { 6 | margin: "0 auto 1.25rem", 7 | height: "auto", 8 | width: "90%", 9 | boxShadow: "0 0 25px rgba(0,0,0,.3)", 10 | borderRadius: "10px", 11 | }, 12 | })); 13 | 14 | export default function GenericCard({ imgSrc, title }) { 15 | const classes = useStyles(); 16 | 17 | return ( 18 | 19 | {title} 20 | 21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /new_client/src/components/about-us/GenericDetails.jsx: -------------------------------------------------------------------------------- 1 | import { 2 | Card, 3 | CardContent, 4 | CardMedia, 5 | makeStyles, 6 | Typography, 7 | } from "@material-ui/core"; 8 | import React from "react"; 9 | 10 | const useStyles = makeStyles((theme) => ({ 11 | root: { 12 | maxWidth: 345, 13 | }, 14 | media: { 15 | height: 260, 16 | }, 17 | })); 18 | 19 | export default function GenericDetails({ imgSrc, title }) { 20 | const classes = useStyles(); 21 | 22 | return ( 23 | 24 | 25 | 26 | 27 | {title} 28 | 29 | 30 | 31 | ); 32 | } 33 | -------------------------------------------------------------------------------- /new_client/src/components/about-us/Image.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Image = (props) => { 4 | return ( 5 |
6 |
10 | {`${props.name}`} 16 |
17 |
18 | {props.name} 19 |
20 | {props.position && ( 21 | {props.position} 22 | )} 23 |
24 |
25 | ); 26 | }; 27 | export default Image; 28 | -------------------------------------------------------------------------------- /new_client/src/components/about-us/details.js: -------------------------------------------------------------------------------- 1 | export default [ 2 | { 3 | name: "Devansh Joshi", 4 | img: 5 | "https://res.cloudinary.com/coc-vjti/image/upload/v1667131931/core22/Devansh_Joshi_umjpjq.jpg", 6 | }, 7 | { 8 | name: "Ritika Chandwani", 9 | img: 10 | "https://res.cloudinary.com/coc-vjti/image/upload/v1667131930/core22/Ritika_Chandwani_h9rmqv.jpg", 11 | }, 12 | { 13 | name: "Nishant Patil", 14 | img: 15 | "https://res.cloudinary.com/coc-vjti/image/upload/v1667131930/core22/Nishant_Patil_melje7.jpg", 16 | }, 17 | { 18 | name: "Ketaki Deshmukh", 19 | img: 20 | "https://res.cloudinary.com/coc-vjti/image/upload/v1667131929/core22/Ketaki_Deshmukh_pr93zm.jpg", 21 | }, 22 | { 23 | name: "Parth Shirole", 24 | img: 25 | "https://res.cloudinary.com/coc-vjti/image/upload/v1667131929/core22/Parth_Shirole_ofovps.jpg", 26 | }, 27 | { 28 | name: "Mridul Sharma", 29 | img: 30 | "https://res.cloudinary.com/coc-vjti/image/upload/v1667131929/core22/Mridul_sharma_wfnjyo.jpg", 31 | }, 32 | { 33 | name: "Nirbhay Nikam", 34 | img: 35 | "https://res.cloudinary.com/coc-vjti/image/upload/v1667131929/core22/Nirbhay_Nikam_mrl2ac.jpg", 36 | }, 37 | { 38 | name: "Bhavik Bharambe", 39 | img: 40 | "https://res.cloudinary.com/coc-vjti/image/upload/v1667131929/core22/Bhavik_Bharambe_bkc8ls.jpg", 41 | }, 42 | { 43 | name: "Vaibhav Patel", 44 | img: 45 | "https://res.cloudinary.com/coc-vjti/image/upload/v1667131928/core22/Vaibhav_patel_pe5cxb.jpg", 46 | }, 47 | { 48 | name: "Dhriti Mabian", 49 | img: 50 | "https://res.cloudinary.com/coc-vjti/image/upload/v1667131928/core22/dhriti_img_ax3iqm.jpg", 51 | }, 52 | { 53 | name: "Harshil Shah", 54 | img: 55 | "https://res.cloudinary.com/coc-vjti/image/upload/v1667131928/core22/Harshil_Shah_jqdjum.jpg", 56 | }, 57 | { 58 | name: "Dhrumil Raigagla", 59 | img: 60 | "https://res.cloudinary.com/coc-vjti/image/upload/v1667131928/core22/Dhrumil_Raigagla_ebsjjp.jpg", 61 | }, 62 | { 63 | name: "Chaitya Vora", 64 | img: 65 | "https://res.cloudinary.com/coc-vjti/image/upload/v1667131928/core22/Chaitya_Vora_y4ibno.jpg", 66 | }, 67 | { 68 | name: "Amey Bhatuse", 69 | img: 70 | "https://res.cloudinary.com/coc-vjti/image/upload/v1667131928/core22/Amey_Bhatuse_gf3odc.jpg", 71 | }, 72 | { 73 | name: "Akash Sable", 74 | img: 75 | "https://res.cloudinary.com/coc-vjti/image/upload/v1667131928/core22/Akash_sable_mzejv3.jpg", 76 | }, 77 | { 78 | name: "Arnav Zutshi", 79 | img: 80 | "https://res.cloudinary.com/coc-vjti/image/upload/v1667131927/core22/Arnav_Zutshi_zeuuq4.jpg", 81 | }, 82 | { 83 | name: "Shubham Mahakal", 84 | img: 85 | "https://res.cloudinary.com/coc-vjti/image/upload/v1667131927/core22/Shubham_Mahakal_iniial.jpg", 86 | }, 87 | { 88 | name: "Tushar Shirbhate", 89 | img: 90 | "https://res.cloudinary.com/coc-vjti/image/upload/v1667131926/core22/Tushar_Shirbhate_mzx9ad.jpg", 91 | }, 92 | { 93 | name: "Soumitra Kand", 94 | img: 95 | "https://res.cloudinary.com/coc-vjti/image/upload/v1667131926/core22/Soumitra_Kand_jfxftx.jpg", 96 | }, 97 | { 98 | name: "Tejas Thorat", 99 | img: 100 | "https://res.cloudinary.com/coc-vjti/image/upload/v1667131926/core22/Tejas_Thorat_pvgx81.jpg", 101 | }, 102 | { 103 | name: "Sayali Panch", 104 | img: 105 | "https://res.cloudinary.com/coc-vjti/image/upload/v1667131930/core22/Sayali_Panch_rtb78v.jpg", 106 | }, 107 | ]; 108 | -------------------------------------------------------------------------------- /new_client/src/components/alumni/AlumnusCard.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import { Card, Typography, makeStyles } from "@material-ui/core"; 3 | import ReactCardFlip from "react-card-flip"; 4 | import PropTypes from "prop-types"; 5 | 6 | import SocialsArray from "./SocialsArray"; 7 | /* 8 | alumnus: { 9 | fullName, 10 | professionalTitle, 11 | company, 12 | imageUrl, 13 | socialUrls, 14 | graduationYear 15 | } 16 | */ 17 | 18 | const useStyles = makeStyles((theme) => ({ 19 | card: { 20 | display: "flex", 21 | flexDirection: "column", 22 | justifyContent: "center", 23 | textDecoration: "none", 24 | height: "27rem", 25 | width: "20rem", 26 | cursor: "pointer", 27 | }, 28 | frontCard: { 29 | backgroundColor: theme.palette.background.paper, 30 | padding: "1rem 0rem 1rem 0rem", 31 | }, 32 | backCard: { 33 | padding: 0, 34 | backgroundSize: "cover", 35 | backgroundPosition: "center", 36 | }, 37 | backCardContent: { 38 | backgroundColor: "rgba(81, 176, 7, 0.75)", 39 | height: "100%", 40 | color: "#fff", 41 | display: "flex", 42 | alignItems: "center", 43 | flexDirection: "column", 44 | justifyContent: "flex-end", 45 | }, 46 | img: { 47 | width: "100%", 48 | height: "80%", 49 | objectFit: "cover", 50 | margin: "0 1rem 1rem 1rem", 51 | alignSelf: "center", 52 | textAlign: "center", 53 | lineHeight: "25rem", 54 | }, 55 | })); 56 | 57 | function AlumnusCardFront({ mask, alumnus }) { 58 | const classes = useStyles(); 59 | return ( 60 | 61 | Alumnus 69 | 70 | {alumnus.fullName} 71 | 72 | 78 | {alumnus.professionalTitle} at {alumnus.company} 79 | 80 | 81 | ); 82 | } 83 | 84 | function AlumnusCardBack({ alumnus }) { 85 | const classes = useStyles(); 86 | return ( 87 | 94 |
95 | 96 | {alumnus.fullName} 97 | 98 | 99 | {alumnus.professionalTitle} at {alumnus.company} 100 | 101 | {!!alumnus.socialUrls && ( 102 | 103 | )} 104 |
105 |
106 | ); 107 | } 108 | 109 | function AlumnusCard({ mask, alumnus }) { 110 | const [isFlipped, setIsFlipped] = useState(false); 111 | 112 | return ( 113 | 119 |
setIsFlipped((prev) => !prev)} 123 | > 124 | 125 |
126 |
setIsFlipped((prev) => !prev)} 130 | > 131 | 132 |
133 |
134 | ); 135 | } 136 | 137 | AlumnusCard.propTypes = { 138 | alumnus: PropTypes.object.isRequired, 139 | }; 140 | 141 | export default AlumnusCard; 142 | -------------------------------------------------------------------------------- /new_client/src/components/alumni/Banner.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import "../Utilities/Banner.scss"; 3 | 4 | function Banner() { 5 | return ( 6 |
7 |
8 |
9 | ); 10 | } 11 | 12 | export default Banner; 13 | -------------------------------------------------------------------------------- /new_client/src/components/alumni/MobileMenu.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { 3 | Grid, 4 | List, 5 | ListItem, 6 | ListItemText, 7 | makeStyles, 8 | Menu, 9 | MenuItem, 10 | } from "@material-ui/core"; 11 | import ExpandMoreIcon from "@material-ui/icons/ExpandMore"; 12 | import PropTypes from "prop-types"; 13 | 14 | const useStyles = makeStyles((theme) => ({ 15 | menuItem: { 16 | width: "90vw", 17 | justifyContent: "center", 18 | "&:hover": { 19 | color: "#3B377C", 20 | opacity: 1, 21 | }, 22 | "&$selected": { 23 | fontWeight: theme.typography.fontWeightMedium, 24 | color: "#3B377C", 25 | }, 26 | "&:focus": { 27 | color: "#3B377C", 28 | }, 29 | }, 30 | listItem: { 31 | textAlign: "center", 32 | }, 33 | listNav: { 34 | marginTop: "1rem", 35 | backgroundColor: theme.palette.grey[200], 36 | borderRadius: theme.shape.borderRadius, 37 | }, 38 | })); 39 | 40 | function MobileMenu({ value, setValue, options, label }) { 41 | const classes = useStyles(); 42 | const [anchorEl, setAnchorEl] = React.useState(null); 43 | const handleClickListItem = (event) => { 44 | setAnchorEl(event.currentTarget); 45 | }; 46 | 47 | const handleMenuItemClick = (event, newValue) => { 48 | setValue(newValue); 49 | setAnchorEl(null); 50 | }; 51 | 52 | const handleMenuClose = () => { 53 | setAnchorEl(null); 54 | }; 55 | 56 | return ( 57 | 58 | 63 | 71 | 74 | {options[value]} {" "} 75 | 76 | } 77 | primaryTypographyProps={{ 78 | variant: "h5", 79 | }} 80 | secondary={label} 81 | className={classes.listItem} 82 | > 83 | 84 | 85 | 92 | {options.map((option, index) => ( 93 | handleMenuItemClick(event, index)} 97 | className={classes.menuItem} 98 | > 99 | {option} 100 | 101 | ))} 102 | 103 | 104 | ); 105 | } 106 | 107 | MobileMenu.propTypes = { 108 | value: PropTypes.number.isRequired, 109 | setValue: PropTypes.func.isRequired, 110 | options: PropTypes.array.isRequired, 111 | label: PropTypes.string, 112 | }; 113 | 114 | export default MobileMenu; 115 | -------------------------------------------------------------------------------- /new_client/src/components/alumni/SocialsArray.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { makeStyles } from "@material-ui/core"; 3 | import PersonIcon from "@material-ui/icons/Person"; 4 | import GitHubIcon from "@material-ui/icons/GitHub"; 5 | import FacebookIcon from "@material-ui/icons/Facebook"; 6 | import TwitterIcon from "@material-ui/icons/Twitter"; 7 | import InstagramIcon from "@material-ui/icons/Instagram"; 8 | import LinkedInIcon from "@material-ui/icons/LinkedIn"; 9 | import { IconButton } from "@material-ui/core"; 10 | 11 | const useStyles = makeStyles(() => ({ 12 | iconButton: { 13 | color: "#ffffff", 14 | }, 15 | array: { 16 | display: "flex", 17 | flexWrap: "wrap", 18 | flexDirection: "row", 19 | justifyContent: "center", 20 | }, 21 | })); 22 | 23 | const socialIcons = { 24 | personal: , 25 | facebook: , 26 | github: , 27 | instagram: , 28 | linkedin: , 29 | twitter: , 30 | }; 31 | 32 | function SocialsArray({ socialUrls }) { 33 | const classes = useStyles(); 34 | 35 | return ( 36 |
37 | {Object.keys(socialUrls) 38 | .filter((key) => socialUrls[key] !== "") 39 | .map((key) => ( 40 | 46 | 47 | {socialIcons[key]} 48 | 49 | 50 | ))} 51 |
52 | ); 53 | } 54 | 55 | export default SocialsArray; 56 | -------------------------------------------------------------------------------- /new_client/src/components/assets/COC.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/new_client/src/components/assets/COC.webp -------------------------------------------------------------------------------- /new_client/src/components/assets/COC_Full.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/new_client/src/components/assets/COC_Full.webp -------------------------------------------------------------------------------- /new_client/src/components/assets/CP.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/new_client/src/components/assets/CP.webp -------------------------------------------------------------------------------- /new_client/src/components/assets/C_WS.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/new_client/src/components/assets/C_WS.webp -------------------------------------------------------------------------------- /new_client/src/components/assets/DEShaw.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/new_client/src/components/assets/DEShaw.webp -------------------------------------------------------------------------------- /new_client/src/components/assets/Inheritance.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/new_client/src/components/assets/Inheritance.webp -------------------------------------------------------------------------------- /new_client/src/components/assets/Tips-for-Making-Side-Projects.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/new_client/src/components/assets/Tips-for-Making-Side-Projects.webp -------------------------------------------------------------------------------- /new_client/src/components/assets/about.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/new_client/src/components/assets/about.webp -------------------------------------------------------------------------------- /new_client/src/components/assets/about_us.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/new_client/src/components/assets/about_us.webp -------------------------------------------------------------------------------- /new_client/src/components/assets/alumni.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/new_client/src/components/assets/alumni.jpeg -------------------------------------------------------------------------------- /new_client/src/components/assets/banner.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/new_client/src/components/assets/banner.webp -------------------------------------------------------------------------------- /new_client/src/components/assets/bg_signin.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/new_client/src/components/assets/bg_signin.webp -------------------------------------------------------------------------------- /new_client/src/components/assets/bg_signup.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/new_client/src/components/assets/bg_signup.webp -------------------------------------------------------------------------------- /new_client/src/components/assets/coc-gses.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/new_client/src/components/assets/coc-gses.webp -------------------------------------------------------------------------------- /new_client/src/components/assets/coc-members.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/new_client/src/components/assets/coc-members.webp -------------------------------------------------------------------------------- /new_client/src/components/assets/coc_dark.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/new_client/src/components/assets/coc_dark.webp -------------------------------------------------------------------------------- /new_client/src/components/assets/collaborate.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/new_client/src/components/assets/collaborate.webp -------------------------------------------------------------------------------- /new_client/src/components/assets/events.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/new_client/src/components/assets/events.webp -------------------------------------------------------------------------------- /new_client/src/components/assets/experience.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/new_client/src/components/assets/experience.webp -------------------------------------------------------------------------------- /new_client/src/components/assets/learn.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/new_client/src/components/assets/learn.webp -------------------------------------------------------------------------------- /new_client/src/components/assets/magazines.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/new_client/src/components/assets/magazines.webp -------------------------------------------------------------------------------- /new_client/src/components/assets/photo_11.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/new_client/src/components/assets/photo_11.webp -------------------------------------------------------------------------------- /new_client/src/components/assets/photo_12.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/new_client/src/components/assets/photo_12.webp -------------------------------------------------------------------------------- /new_client/src/components/assets/projects.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/new_client/src/components/assets/projects.webp -------------------------------------------------------------------------------- /new_client/src/components/auth/Error.css: -------------------------------------------------------------------------------- 1 | .errorMsg { 2 | color: #cc0000; 3 | margin-bottom: 10px; 4 | } 5 | -------------------------------------------------------------------------------- /new_client/src/components/auth/PasswordField.jsx: -------------------------------------------------------------------------------- 1 | import { IconButton, InputAdornment, TextField } from "@material-ui/core"; 2 | import React, { useState } from "react"; 3 | import VpnKeyIcon from "@material-ui/icons/VpnKey"; 4 | import Visibility from "@material-ui/icons/Visibility"; 5 | import VisibilityOff from "@material-ui/icons/VisibilityOff"; 6 | 7 | export default function PasswordField({ 8 | handlePassword, 9 | name = "password", 10 | isNew = false, 11 | }) { 12 | const [isPasswordVisible, toggleIsPasswordVisible] = useState(false); 13 | 14 | const handleClickShowPassword = () => { 15 | toggleIsPasswordVisible(!isPasswordVisible); 16 | }; 17 | 18 | const handleMouseDownPassword = (event) => { 19 | event.preventDefault(); 20 | }; 21 | 22 | const capitalize = (s) => { 23 | if (typeof s !== "string") return ""; 24 | return s.charAt(0).toUpperCase() + s.slice(1); 25 | }; 26 | 27 | return ( 28 | 40 | 41 | 42 | ), 43 | endAdornment: ( 44 | 45 | 50 | {isPasswordVisible ? : } 51 | 52 | 53 | ), 54 | }} 55 | onChange={handlePassword} 56 | /> 57 | ); 58 | } 59 | -------------------------------------------------------------------------------- /new_client/src/components/auth/VerifyEmail.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import Button from "@material-ui/core/Button"; 3 | import Typography from "@material-ui/core/Typography"; 4 | import { makeStyles, ThemeProvider } from "@material-ui/core/styles"; 5 | import Container from "@material-ui/core/Container"; 6 | import { Paper } from "@material-ui/core"; 7 | import coc from "../assets/COC_Full.webp"; 8 | import { createMuiTheme } from "@material-ui/core/styles"; 9 | import { useHistory, useParams } from "react-router-dom"; 10 | import axios from "axios"; 11 | import { useDispatch } from "react-redux"; 12 | 13 | import "./Error.css"; 14 | import AlertUtility from "../Utilities/Alert"; 15 | 16 | const useStyles = makeStyles((theme) => ({ 17 | paper: { 18 | marginTop: theme.spacing(8), 19 | display: "flex", 20 | flexDirection: "column", 21 | alignItems: "center", 22 | backgroundColor: "#000", 23 | }, 24 | form: { 25 | width: "100%", 26 | marginTop: theme.spacing(1), 27 | justifyContent: "center", 28 | backgroundColor: "#f8f8f8", 29 | }, 30 | formInner: { 31 | padding: "30px", 32 | }, 33 | submit: { 34 | margin: theme.spacing(3, 0, 2), 35 | color: "white", 36 | }, 37 | })); 38 | 39 | const theme1 = createMuiTheme({ 40 | palette: { 41 | primary: { 42 | main: "#52b107", 43 | }, 44 | }, 45 | }); 46 | 47 | function VerifyEmail(props) { 48 | const token = useParams().token; 49 | const history = useHistory(); 50 | const dispatch = useDispatch(); 51 | 52 | const [msg, setMsg] = useState(""); 53 | const [isSubmitted, setIsSubmitted] = useState(false); 54 | const [isError, setIsError] = useState(false); 55 | 56 | function handleClose(e) { 57 | setIsSubmitted(false); 58 | history.push("/signin"); 59 | } 60 | 61 | function handleClick(event) { 62 | event.preventDefault(); 63 | axios 64 | .post(process.env.REACT_APP_API + "/verify-email", { token }) 65 | .then((res) => { 66 | if (res.status === 200) { 67 | setMsg(res.data.message); 68 | setIsSubmitted(true); 69 | } else { 70 | setMsg("Unknown Error"); 71 | setIsError(true); 72 | } 73 | }) 74 | .catch((err) => { 75 | setMsg(err.response.data.error); 76 | setIsError(true); 77 | }); 78 | } 79 | 80 | const classes = useStyles(); 81 | return ( 82 | 83 | 84 | 85 | COC Logo 90 | 91 | 92 | Verify Email 93 | 94 |
95 |
96 | 107 |
108 |
109 |
110 |
111 | 118 | setIsError(false)} 122 | severity="error" 123 | message={`Error: ${msg}. Please try again`} 124 | /> 125 |
126 | ); 127 | } 128 | 129 | export default VerifyEmail; 130 | -------------------------------------------------------------------------------- /new_client/src/components/blogs/Blogs.css: -------------------------------------------------------------------------------- 1 | .tag { 2 | padding: 0.4em 0.5em; 3 | margin: 2px 2px 2px 0; 4 | cursor: pointer; 5 | color: #39739d; 6 | background-color: #e1ecf4; 7 | border-color: #00000000; 8 | line-height: 1; 9 | white-space: nowrap; 10 | text-decoration: none; 11 | text-align: center; 12 | border-width: 1px; 13 | border-style: solid; 14 | border-radius: 3px; 15 | font-size: 12px; 16 | } 17 | 18 | .tag:hover { 19 | background-color: #bfe3fd; 20 | } 21 | -------------------------------------------------------------------------------- /new_client/src/components/blogs/Editor.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import ReactMde from "react-mde"; 3 | import * as Showdown from "showdown"; 4 | import "react-mde/lib/styles/css/react-mde-all.css"; 5 | 6 | const converter = new Showdown.Converter({ 7 | tables: true, 8 | simplifiedAutoLink: true, 9 | strikethrough: true, 10 | tasklists: true, 11 | }); 12 | 13 | export default function Editor(props) { 14 | const { content, setContent } = props; 15 | const [selectedTab, setSelectedTab] = useState("write"); 16 | return ( 17 | 23 | Promise.resolve(converter.makeHtml(markdown)) 24 | } 25 | /> 26 | ); 27 | } 28 | -------------------------------------------------------------------------------- /new_client/src/components/blogs/IndividualBlog.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from "react"; 2 | import { useParams } from "react-router-dom"; 3 | import axios from "axios"; 4 | import ReactMarkdown from "react-markdown"; 5 | import { Container } from "@material-ui/core"; 6 | import CodeBlock from "./SyntaxHighlighter"; 7 | 8 | function IndividualBlog() { 9 | const id = useParams().id; 10 | const [blog, setBlog] = useState({}); 11 | 12 | useEffect(() => { 13 | axios 14 | .get(process.env.REACT_APP_API + `/blogs/${id}`) 15 | .then((res) => { 16 | setBlog(res.data); 17 | }) 18 | .catch((err) => console.log(err.toString())); 19 | }, [id]); 20 | 21 | return ( 22 | 23 | 27 | 28 | ); 29 | } 30 | 31 | export default IndividualBlog; 32 | -------------------------------------------------------------------------------- /new_client/src/components/blogs/SyntaxHighlighter.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"; 3 | import { coy } from "react-syntax-highlighter/dist/esm/styles/prism"; 4 | 5 | const CodeBlock = ({ language, value }) => { 6 | return ( 7 | 8 | {value} 9 | 10 | ); 11 | }; 12 | 13 | export default CodeBlock; 14 | -------------------------------------------------------------------------------- /new_client/src/components/events/Banner.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import "../Utilities/Banner.scss"; 3 | import { Button } from "@material-ui/core"; 4 | 5 | function Banner({ isMember, setShowModal }) { 6 | return ( 7 |
8 |
9 |
Events
10 | {isMember && ( 11 |
12 | 15 |
16 | )} 17 |
18 | ); 19 | } 20 | 21 | export default Banner; 22 | -------------------------------------------------------------------------------- /new_client/src/components/events/EventList.css: -------------------------------------------------------------------------------- 1 | .nav-mob-close { 2 | transform: translateX(-355%); 3 | } 4 | -------------------------------------------------------------------------------- /new_client/src/components/events/EventPage.css: -------------------------------------------------------------------------------- 1 | .nav-mob-open { 2 | transform: translateX(1%); 3 | } 4 | .onlyEventPage { 5 | left: auto; 6 | right: 5px; 7 | } 8 | #onlyEventPageSideBar { 9 | left: auto; 10 | right: 5px; 11 | } 12 | -------------------------------------------------------------------------------- /new_client/src/components/events/RegisterButton.jsx: -------------------------------------------------------------------------------- 1 | import { Button, Tooltip } from "@material-ui/core"; 2 | import React from "react"; 3 | import { connect } from "react-redux"; 4 | import { Link } from "react-router-dom"; 5 | 6 | const RegisterButton = ({ 7 | isAuthenticated, 8 | isUserRegistered, 9 | handleRSVP, 10 | eventID, 11 | }) => { 12 | if (!isAuthenticated) { 13 | return ( 14 | 15 | 16 | 19 | 20 | 21 | ); 22 | } 23 | return ( 24 | 33 | ); 34 | }; 35 | 36 | const mapStateToProps = (state) => ({ 37 | isAuthenticated: state.auth.isAuthenticated, 38 | }); 39 | 40 | export default connect(mapStateToProps)(RegisterButton); 41 | -------------------------------------------------------------------------------- /new_client/src/components/events/RegisterEvent.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from "react"; 2 | import { useParams, withRouter } from "react-router-dom"; 3 | import Alert from "../Utilities/Alert"; 4 | 5 | const RegisterEvent = (props) => { 6 | const uid = useParams().uid; 7 | const eid = useParams().eid; 8 | const [alert, setAlert] = useState(""); 9 | 10 | useEffect(() => { 11 | (async () => { 12 | const requestOptions = { 13 | method: "POST", 14 | headers: { 15 | Authorization: "Bearer " + props.token, 16 | }, 17 | }; 18 | const url = 19 | process.env.REACT_APP_API + `/events/register?eid=${eid}&uid=${uid}`; 20 | const response = await fetch(url, requestOptions); 21 | if (response.status === 200) { 22 | setAlert("success"); 23 | } else { 24 | setAlert("error"); 25 | } 26 | })(); 27 | }, [eid, uid, props.token]); 28 | 29 | let alertComp = null; 30 | if (alert !== "") { 31 | alertComp = ( 32 | 43 | ); 44 | } 45 | 46 | return ( 47 | 48 |

You have been registered for the event

49 |
50 | ); 51 | }; 52 | 53 | export default withRouter(RegisterEvent); 54 | -------------------------------------------------------------------------------- /new_client/src/components/experiences/Banner.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import "../Utilities/Banner.scss"; 3 | import { Button, Box } from "@material-ui/core"; 4 | import { useHistory } from "react-router-dom"; 5 | 6 | function Banner({ isMember }) { 7 | const history = useHistory(); 8 | return ( 9 |
10 |
11 |
Experiences
12 | {isMember && ( 13 |
14 | 15 | 23 | 24 | 25 | 33 | 34 |
35 | )} 36 |
37 | ); 38 | } 39 | 40 | export default Banner; 41 | -------------------------------------------------------------------------------- /new_client/src/components/footer/Footer.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: "Recharge Bold"; 3 | src: local("Recharge Bold"), 4 | url("https://res.cloudinary.com/coc-vjti/raw/upload/v1613468201/recharge.bold_ck77rq.ttf") 5 | format("truetype"); 6 | font-display: swap; 7 | } 8 | -------------------------------------------------------------------------------- /new_client/src/components/footer/Footer.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { 3 | Typography, 4 | createMuiTheme, 5 | responsiveFontSizes, 6 | ThemeProvider, 7 | } from "@material-ui/core"; 8 | import { 9 | Facebook, 10 | GitHub, 11 | Instagram, 12 | LinkedIn, 13 | YouTube, 14 | } from "@material-ui/icons"; 15 | 16 | import COC from "../assets/coc_dark.webp"; 17 | import "./Footer.css"; 18 | import footerStyle from "./footerStyle"; 19 | 20 | const responsiveFonts = responsiveFontSizes(createMuiTheme()); 21 | 22 | export default function Footer() { 23 | const classes = footerStyle(); 24 | return ( 25 | 26 |
27 | COC Logo 28 | 29 | Community{" "} 30 | of{" "} 31 | Coders 32 | 33 | 34 | Imagine 35 | Believe 36 | Achieve 37 | 38 | 75 |
76 |
77 |
78 |
79 |
80 | 81 | © Community of Coders, VJTI 82 | 83 |
84 |
85 | ); 86 | } 87 | -------------------------------------------------------------------------------- /new_client/src/components/footer/footerStyle.js: -------------------------------------------------------------------------------- 1 | import { makeStyles } from "@material-ui/core"; 2 | 3 | const GREEN_COLOR = "#31D16D"; 4 | const BLACK_PRIMARY_COLOR = "#0A150A"; 5 | const BLACK_SECONDARY_COLOR = "#2F2F2F"; 6 | const WHITE_PRIMARY_COLOR = "#CDCDCD"; 7 | const RECHARGE_FONT = "Recharge Bold"; 8 | 9 | export default makeStyles((theme) => ({ 10 | footerContent: { 11 | padding: "1rem", 12 | backgroundColor: BLACK_PRIMARY_COLOR, 13 | display: "flex", 14 | flexDirection: "column", 15 | alignItems: "center", 16 | }, 17 | name: { 18 | color: WHITE_PRIMARY_COLOR, 19 | fontFamily: RECHARGE_FONT, 20 | marginTop: "1rem", 21 | [theme.breakpoints.down("xs")]: { 22 | fontSize: "1.5rem", 23 | }, 24 | }, 25 | socials: { 26 | margin: "1rem 0 1rem 0", 27 | display: "flex", 28 | flexWrap: "nowrap", 29 | alignItems: "center", 30 | justifyContent: "space-between", 31 | }, 32 | socialIcon: { 33 | marginLeft: "1rem", 34 | marginRight: "1rem", 35 | color: WHITE_PRIMARY_COLOR, 36 | cursor: "pointer", 37 | transition: "all 0.2s ease", 38 | "&:hover, &:focus": { 39 | color: GREEN_COLOR, 40 | transform: "scale(1.2)", 41 | }, 42 | }, 43 | tagline: { 44 | color: WHITE_PRIMARY_COLOR, 45 | display: "flex", 46 | justifyContent: "center", 47 | flexWrap: "wrap", 48 | alignItems: "center", 49 | minWidth: "100%", 50 | textTransform: "uppercase", 51 | fontFamily: RECHARGE_FONT, 52 | fontSize: "1.1rem", 53 | [theme.breakpoints.down("sm")]: { 54 | fontSize: "1rem", 55 | }, 56 | [theme.breakpoints.down("xs")]: { 57 | fontSize: "0.8rem", 58 | }, 59 | }, 60 | bulletSeperator: { 61 | fontSize: "2rem", 62 | padding: "0 0.8rem 0 0.8rem", 63 | }, 64 | footerSeperator: { 65 | backgroundColor: BLACK_PRIMARY_COLOR, 66 | display: "flex", 67 | justifyContent: "center", 68 | }, 69 | greenThread: { 70 | width: "2rem", 71 | backgroundColor: GREEN_COLOR, 72 | height: "0.3rem", 73 | borderRadius: "1rem", 74 | }, 75 | footerBottom: { 76 | backgroundColor: BLACK_SECONDARY_COLOR, 77 | color: WHITE_PRIMARY_COLOR, 78 | display: "flex", 79 | alignItems: "center", 80 | justifyContent: "center", 81 | padding: "1.2rem", 82 | }, 83 | cocGreen: { 84 | color: GREEN_COLOR, 85 | }, 86 | })); 87 | -------------------------------------------------------------------------------- /new_client/src/components/glimpses/Glimpse.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import axios from "axios"; 3 | import { Container, Grid } from "@material-ui/core"; 4 | import IndividualGlimpse from "./IndividualGlimpse"; 5 | import Spinner from "../spinner/Spinner"; 6 | 7 | const Glimpse = () => { 8 | const [glimpses, setGlimpses] = useState([]); 9 | const [isLoading, setIsLoading] = useState(true); 10 | 11 | useEffect(() => { 12 | let shouldCancel = false; 13 | const call = async () => { 14 | try { 15 | const response = await axios.get( 16 | process.env.REACT_APP_API + "/glimpses" 17 | ); 18 | if (!shouldCancel && response.data && response.data.data.length > 0) { 19 | setGlimpses(response.data.data); 20 | } 21 | } catch (e) { 22 | setGlimpses([]); 23 | } 24 | setIsLoading(false); 25 | }; 26 | call(); 27 | return () => (shouldCancel = true); 28 | }, []); 29 | 30 | return ( 31 | 32 | 33 | {isLoading ? : null} 34 | {glimpses.map((glimpse) => ( 35 | 36 | 41 | 42 | ))} 43 | 44 | 45 | ); 46 | }; 47 | 48 | export default Glimpse; 49 | -------------------------------------------------------------------------------- /new_client/src/components/glimpses/IndividualGlimpse.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { makeStyles } from "@material-ui/core/styles"; 3 | import Card from "@material-ui/core/Card"; 4 | import CardActions from "@material-ui/core/CardActions"; 5 | import CardContent from "@material-ui/core/CardContent"; 6 | import CardMedia from "@material-ui/core/CardMedia"; 7 | import Button from "@material-ui/core/Button"; 8 | import Typography from "@material-ui/core/Typography"; 9 | import cx from "clsx"; 10 | import { useFourThreeCardMediaStyles } from "@mui-treasury/styles/cardMedia/fourThree"; 11 | import { useOverShadowStyles } from "@mui-treasury/styles/shadow/over"; 12 | import { Link } from "react-router-dom"; 13 | 14 | const useStyles = makeStyles(() => ({ 15 | root: { 16 | maxWidth: 343, 17 | margin: "auto", 18 | borderRadius: 12, 19 | padding: 12, 20 | }, 21 | media: { 22 | borderRadius: 6, 23 | }, 24 | })); 25 | 26 | export default function IndividualGlimpse({ imgSrc, title, albumPath }) { 27 | const styles = useStyles(); 28 | const mediaStyles = useFourThreeCardMediaStyles(); 29 | const shadowStyles = useOverShadowStyles({ inactive: true }); 30 | 31 | return ( 32 | 33 | 37 | 38 | 39 | {title} 40 | 41 | 42 | 43 | 49 | {" "} 50 | 53 | 54 | 55 | 56 | ); 57 | } 58 | -------------------------------------------------------------------------------- /new_client/src/components/glimpses/IndividualImageGalllery.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from "react"; 2 | import "react-image-gallery/styles/css/image-gallery.css"; 3 | import ImageGallery from "react-image-gallery"; 4 | import axios from "axios"; 5 | import Spinner from "../spinner/Spinner"; 6 | 7 | export default function IndividualImageGalllery(props) { 8 | const [images, setImages] = useState([]); 9 | const [isLoading, setIsLoading] = useState(true); 10 | 11 | const { 12 | location: { 13 | state: { albumPath }, 14 | }, 15 | } = props; 16 | 17 | useEffect(() => { 18 | let shouldCancel = false; 19 | const call = async () => { 20 | try { 21 | const response = await axios.post( 22 | process.env.REACT_APP_API + "/glimpses", 23 | { gPhotosUrl: albumPath } 24 | ); 25 | if (!shouldCancel && response.data) { 26 | setImages( 27 | response.data.map((url) => ({ 28 | original: `${url}=w512`, 29 | thumbnail: `${url}=w100`, 30 | })) 31 | ); 32 | setIsLoading(false); 33 | } 34 | } catch (e) { 35 | setImages([]); 36 | setIsLoading(false); 37 | } 38 | }; 39 | call(); 40 | return () => (shouldCancel = true); 41 | }); 42 | 43 | return ( 44 | 45 | {isLoading ? : } 46 | 47 | ); 48 | } 49 | -------------------------------------------------------------------------------- /new_client/src/components/magazines/Banner.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import "../Utilities/Banner.scss"; 3 | 4 | function Banner() { 5 | return ( 6 |
7 |
8 |
Magazines
9 |
10 | ); 11 | } 12 | 13 | export default Banner; 14 | -------------------------------------------------------------------------------- /new_client/src/components/magazines/MagazineModal.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { makeStyles } from "@material-ui/core/styles"; 3 | import Typography from "@material-ui/core/Typography"; 4 | import Button from "@material-ui/core/Button"; 5 | import Modal from "@material-ui/core/Modal"; 6 | 7 | const useStyles = makeStyles((theme) => ({ 8 | paper: { 9 | position: "absolute", 10 | display: "flex", 11 | flexDirection: "column", 12 | alignItems: "center", 13 | backgroundColor: "#FFF", 14 | border: "2px solid #000", 15 | boxShadow: theme.shadows[5], 16 | padding: theme.spacing(2, 4, 3), 17 | overflow: "auto", 18 | maxHeight: "80%", 19 | [theme.breakpoints.down("sm")]: { 20 | width: "85%", 21 | }, 22 | [theme.breakpoints.up("md")]: { 23 | width: "60%", 24 | }, 25 | }, 26 | downloadBtn: { 27 | margin: "5% 0", 28 | }, 29 | pdfviewer: { 30 | width: "100%", 31 | display: "flex", 32 | justifyContent: "center", 33 | marginTop: "8px", 34 | }, 35 | })); 36 | 37 | const getModalStyle = () => { 38 | const top = 45; 39 | const left = 50; 40 | 41 | return { 42 | top: `${top}%`, 43 | left: `${left}%`, 44 | transform: `translate(-${top}%, -${left}%)`, 45 | }; 46 | }; 47 | 48 | const MagazineModal = ({ open, modalHide, magazineData }) => { 49 | const classes = useStyles(); 50 | const [modalStyle] = React.useState(getModalStyle); 51 | 52 | return ( 53 | 54 |
55 | 56 | {magazineData.title} 57 | 58 |
59 | 60 | {magazineData.desc} 61 | 62 | 72 | 73 | Preview: 74 | 75 |
76 | {magazineData.pdfUrl && ( 77 | 83 | )} 84 |
85 |
86 |
87 | ); 88 | }; 89 | 90 | export default MagazineModal; 91 | -------------------------------------------------------------------------------- /new_client/src/components/projects/Banner.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import "../Utilities/Banner.scss"; 3 | 4 | function Banner() { 5 | return ( 6 |
7 |
8 |
Projects
9 |
10 | ); 11 | } 12 | 13 | export default Banner; 14 | -------------------------------------------------------------------------------- /new_client/src/components/projects/ProjectGroupCard.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { makeStyles } from "@material-ui/core/styles"; 3 | import Card from "@material-ui/core/Card"; 4 | import CardActions from "@material-ui/core/CardActions"; 5 | import CardContent from "@material-ui/core/CardContent"; 6 | import CardMedia from "@material-ui/core/CardMedia"; 7 | import Button from "@material-ui/core/Button"; 8 | import Typography from "@material-ui/core/Typography"; 9 | import { Link } from "react-router-dom"; 10 | import { Divider } from "@material-ui/core"; 11 | 12 | const useStyles = makeStyles((theme) => ({ 13 | card: { 14 | margin: "20px 100px", 15 | backgroundColor: "white", 16 | position: "relative", 17 | height: "100%", 18 | }, 19 | media: { 20 | height: "auto", 21 | paddingTop: "100%", //"56.25%", // 16:9 22 | }, 23 | section1: { 24 | margin: theme.spacing(1, 2), 25 | }, 26 | section2: { 27 | margin: theme.spacing(2, 2), 28 | }, 29 | actions: { 30 | margin: theme.spacing(1, 2), 31 | display: "flex", 32 | justifyContent: "space-between", 33 | }, 34 | })); 35 | 36 | export default function ProjectGroup({ id, imageURL, title, description }) { 37 | const classes = useStyles(); 38 | return ( 39 | 40 | {imageURL && ( 41 | 42 | )} 43 | 44 | 51 | {title} 52 | 53 | 54 | 60 | {description} 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | ); 71 | } 72 | -------------------------------------------------------------------------------- /new_client/src/components/projects/ProjectList.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import axios from "axios"; 3 | import { Container, Grid, Typography, Box } from "@material-ui/core"; 4 | import IndividualProjectCard from "./IndividualProjectCard"; 5 | import { useParams } from "react-router-dom"; 6 | import Spinner from "../spinner/Spinner"; 7 | import BackButton from "../Utilities/BackButton"; 8 | 9 | const ProjectList = () => { 10 | const [isLoading, setIsLoading] = useState(true); 11 | const [projects, setProjects] = useState([]); 12 | const [domain, setDomain] = useState([]); 13 | const id = useParams().id; 14 | 15 | useEffect(() => { 16 | axios 17 | .get(process.env.REACT_APP_API + `/projects/filter/${id}`) 18 | .then((res) => { 19 | if (res.status === 200) { 20 | const projectsList = res.data.projects; 21 | setProjects(projectsList); 22 | } 23 | setIsLoading(false); 24 | }) 25 | .catch((err) => { 26 | console.log(err); 27 | setIsLoading(false); 28 | }); 29 | }, [id]); 30 | 31 | useEffect(() => { 32 | setIsLoading(true); 33 | axios 34 | .get(process.env.REACT_APP_API + `/domains/${id}`) 35 | .then((res) => { 36 | if (res.status === 200) { 37 | setDomain(res.data.domainName); 38 | } 39 | setIsLoading(false); 40 | }) 41 | .catch((err) => { 42 | console.error(err); 43 | setIsLoading(false); 44 | }); 45 | }, [id]); 46 | 47 | const DisplayProjects = () => { 48 | return projects.length ? ( 49 | 50 | 51 | 52 | 53 | {`${domain} projects`} 54 | 55 | 56 | {projects.map((project) => ( 57 | 58 | 66 | 67 | ))} 68 | 69 | 70 | ) : ( 71 | 72 | Sorry, projects in this category are not yet available. 73 | 74 | ); 75 | }; 76 | 77 | return ( 78 | 79 | {isLoading ? ( 80 | 81 | ) : ( 82 | <> 83 | 84 | 85 | 86 | )} 87 | 88 | ); 89 | }; 90 | 91 | export default ProjectList; 92 | -------------------------------------------------------------------------------- /new_client/src/components/projects/ProjectModal.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { makeStyles } from "@material-ui/core/styles"; 3 | import CardMedia from "@material-ui/core/CardMedia"; 4 | import Typography from "@material-ui/core/Typography"; 5 | import Modal from "@material-ui/core/Modal"; 6 | 7 | const useStyles = makeStyles((theme) => ({ 8 | paper: { 9 | position: "absolute", 10 | backgroundColor: "#FFF", 11 | border: "2px solid #000", 12 | boxShadow: theme.shadows[5], 13 | padding: theme.spacing(2, 4, 3), 14 | overflow: "auto", 15 | maxHeight: "80%", 16 | [theme.breakpoints.down("sm")]: { 17 | width: "85%", 18 | }, 19 | [theme.breakpoints.up("md")]: { 20 | width: "40%", 21 | }, 22 | }, 23 | modalMedia: { 24 | maxHeight: "50%", 25 | maxWidth: "auto", 26 | paddingTop: "56.25%", // 16: 27 | borderRadius: 4, 28 | backgroundSize: "contain", 29 | }, 30 | projectOwner: { 31 | marginTop: "10px", 32 | marginLeft: "auto", 33 | maxWidth: "50%", 34 | textAlign: "right", 35 | }, 36 | })); 37 | 38 | const getModalStyle = () => { 39 | const top = 45; 40 | const left = 50; 41 | 42 | return { 43 | top: `${top}%`, 44 | left: `${left}%`, 45 | transform: `translate(-${top}%, -${left}%)`, 46 | }; 47 | }; 48 | 49 | const ProjectModal = ({ open, modalHide, projectData }) => { 50 | const classes = useStyles(); 51 | const [modalStyle] = React.useState(getModalStyle); 52 | 53 | return ( 54 | 55 |
56 | 57 | {projectData.title} 58 | 59 |
60 |
61 | 66 |
67 |
68 | 69 | {projectData.desc} 70 | 71 | 72 | By{" "} 73 | {typeof projectData.owner == "object" 74 | ? projectData.owner.name 75 | : projectData.owner} 76 | 77 |
78 |
79 | ); 80 | }; 81 | 82 | export default ProjectModal; 83 | -------------------------------------------------------------------------------- /new_client/src/components/projects/Projects.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import axios from "axios"; 3 | import { Container, Grid, Typography, Box } from "@material-ui/core"; 4 | import ProjectGroup from "./ProjectGroupCard"; 5 | import Spinner from "../spinner/Spinner"; 6 | import Banner from "./Banner"; 7 | 8 | const Projects = () => { 9 | const [loading, setLoading] = useState(true); 10 | const [domains, setDomains] = useState([]); 11 | 12 | useEffect(() => { 13 | axios 14 | .get(process.env.REACT_APP_API + "/domains") 15 | .then((res) => { 16 | const domainList = res.data; 17 | setDomains(domainList); 18 | }) 19 | .catch((err) => console.error(err)) 20 | .finally(() => setLoading(false)); 21 | }, []); 22 | return loading ? ( 23 | 24 | ) : ( 25 | 26 | 27 | 28 | 29 | 30 | 31 | 36 | Project Categories 37 | 38 | 39 | {domains.length && 40 | domains.map((group) => ( 41 | 42 | 48 | 49 | ))} 50 | 51 | 52 | 53 | 54 | ); 55 | }; 56 | 57 | export default Projects; 58 | -------------------------------------------------------------------------------- /new_client/src/components/resources/Resource.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Grid, Typography, makeStyles } from "@material-ui/core"; 3 | 4 | const useResourceStyles = makeStyles({ 5 | resource: { 6 | backgroundColor: "rgba(25, 25, 25, 0.50)", 7 | borderRadius: "10px", 8 | height: "120px", 9 | margin: "2%", 10 | cursor: "pointer", 11 | transition: "transform .2s", 12 | "&:hover, &:focus": { 13 | transform: "scale(1.10)", 14 | }, 15 | }, 16 | resourceText: { 17 | opacity: 1, 18 | color: "white", 19 | textAlign: "center", 20 | }, 21 | }); 22 | 23 | export default function Resource({ title, link, description }) { 24 | const classes = useResourceStyles(); 25 | return ( 26 | window.open(link)} 36 | > 37 | 38 | 39 | {title} 40 | 41 | 42 | {description} 43 | 44 | 45 | 46 | ); 47 | } 48 | -------------------------------------------------------------------------------- /new_client/src/components/resources/ResourcePage.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import axios from "axios"; 3 | import { 4 | Box, 5 | Container, 6 | Grid, 7 | ThemeProvider, 8 | Typography, 9 | createMuiTheme, 10 | responsiveFontSizes, 11 | } from "@material-ui/core"; 12 | 13 | import Topic from "./Topic"; 14 | import Spinner from "../spinner/Spinner"; 15 | 16 | const colors = [ 17 | "rgba(188, 51, 51, 1)", 18 | "rgba(52, 131, 61, 1)", 19 | "rgba(105,1,38,1)", 20 | "rgba(0, 1, 106, 1)", 21 | "rgba(188, 51, 51, 1)", 22 | "rgba(122,88,255,1)", 23 | ]; 24 | 25 | const responsiveFonts = responsiveFontSizes(createMuiTheme()); 26 | 27 | export default function ResourcePage() { 28 | const [topics, setTopics] = useState([]); 29 | const [isLoading, setIsLoading] = useState(true); 30 | 31 | useEffect(() => { 32 | const getTopics = async () => { 33 | try { 34 | const { data: topics } = await axios.get( 35 | process.env.REACT_APP_API + "/topics" 36 | ); 37 | setTopics(topics); 38 | setIsLoading(false); 39 | } catch (error) { 40 | console.log(error); 41 | } 42 | }; 43 | getTopics(); 44 | }, []); 45 | 46 | return ( 47 | 48 | 49 | 50 | Resources 51 | 52 | {isLoading ? ( 53 | 54 | ) : ( 55 | 56 | 57 | {topics 58 | ? topics.map((topic, index) => ( 59 | 65 | )) 66 | : "Your mind, and your calm"} 67 | 68 | 69 | )} 70 | 71 | 72 | ); 73 | } 74 | -------------------------------------------------------------------------------- /new_client/src/components/resources/Topic.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { 3 | ExpansionPanel, 4 | ExpansionPanelDetails, 5 | ExpansionPanelSummary, 6 | Grid, 7 | Typography, 8 | makeStyles, 9 | } from "@material-ui/core"; 10 | import ExpandMoreIcon from "@material-ui/icons/ExpandMore"; 11 | 12 | import Resource from "./Resource"; 13 | 14 | const useTopicStyles = makeStyles({ 15 | topic: { 16 | width: "100%", 17 | color: "rgba(255, 255, 255, 0.95)", 18 | marginTop: "0.5%", 19 | marginBottom: "0.5%", 20 | }, 21 | }); 22 | 23 | export default function Topic({ name, resources, color }) { 24 | const classes = useTopicStyles(); 25 | return ( 26 | 31 | } 33 | aria-controls="panel1a-content" 34 | id="panel1a-header" 35 | > 36 | 37 | {name} 38 | 39 | 40 | 41 | 42 | {resources.length > 0 ? ( 43 | resources.map((resource, index) => ( 44 | 50 | )) 51 | ) : ( 52 | 53 |

No resources have been added for this topic yet.

54 |
55 | )} 56 |
57 |
58 |
59 | ); 60 | } 61 | -------------------------------------------------------------------------------- /new_client/src/components/spinner/Spinner.css: -------------------------------------------------------------------------------- 1 | .Loader, 2 | .Loader:before, 3 | .Loader:after { 4 | background: #52b107; 5 | -webkit-animation: load1 1s infinite ease-in-out; 6 | animation: load1 1s infinite ease-in-out; 7 | width: 1em; 8 | height: 4em; 9 | } 10 | .Loader { 11 | color: #52b107; 12 | text-indent: -9999em; 13 | margin: 88px auto; 14 | position: fixed; 15 | left: 50%; 16 | top: 50%; 17 | font-size: 11px; 18 | -webkit-transform: translateZ(0); 19 | -ms-transform: translateZ(0); 20 | transform: translateZ(0); 21 | -webkit-animation-delay: -0.16s; 22 | animation-delay: -0.16s; 23 | } 24 | .Loader:before, 25 | .Loader:after { 26 | position: absolute; 27 | top: 0; 28 | content: ""; 29 | } 30 | .Loader:before { 31 | left: -1.5em; 32 | -webkit-animation-delay: -0.32s; 33 | animation-delay: -0.32s; 34 | } 35 | .Loader:after { 36 | left: 1.5em; 37 | } 38 | @-webkit-keyframes load1 { 39 | 0%, 40 | 80%, 41 | 100% { 42 | box-shadow: 0 0; 43 | height: 4em; 44 | } 45 | 40% { 46 | box-shadow: 0 -2em; 47 | height: 5em; 48 | } 49 | } 50 | @keyframes load1 { 51 | 0%, 52 | 80%, 53 | 100% { 54 | box-shadow: 0 0; 55 | height: 4em; 56 | } 57 | 40% { 58 | box-shadow: 0 -2em; 59 | height: 5em; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /new_client/src/components/spinner/Spinner.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | import "./Spinner.css"; 4 | 5 | const spinner = (props) =>
Loading...
; 6 | 7 | export default spinner; 8 | -------------------------------------------------------------------------------- /new_client/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", 4 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /new_client/src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom"; 3 | import "./index.css"; 4 | import App from "./App"; 5 | import * as serviceWorker from "./serviceWorker"; 6 | import "bootstrap/dist/css/bootstrap.css"; 7 | 8 | ReactDOM.render( 9 | 10 | 11 | , 12 | document.getElementById("root") 13 | ); 14 | 15 | // If you want your app to work offline and load faster, you can change 16 | // unregister() to register() below. Note this comes with some pitfalls. 17 | // Learn more about service workers: https://bit.ly/CRA-PWA 18 | serviceWorker.unregister(); 19 | -------------------------------------------------------------------------------- /new_client/src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /new_client/src/reducers/authReducer.js: -------------------------------------------------------------------------------- 1 | import { 2 | USER_LOADED, 3 | USER_LOADING, 4 | AUTH_ERROR, 5 | LOGIN_SUCCESS, 6 | LOGIN_FAIL, 7 | REGISTER_SUCCESS, 8 | REGISTER_FAIL, 9 | LOGOUT_SUCCESS, 10 | NEW_PASSWORD_SUCCESS, 11 | REFRESH_TOKENS, 12 | } from "../actions/types"; 13 | 14 | const initialState = { 15 | token: localStorage.getItem("token"), 16 | refreshToken: localStorage.getItem("refreshToken"), 17 | isAuthenticated: 18 | !!localStorage.getItem("token") && 19 | !!localStorage.getItem("userID") && 20 | !!localStorage.getItem("refreshToken"), 21 | isLoading: null, 22 | userID: localStorage.getItem("userID") ? localStorage.getItem("userID") : "", 23 | username: localStorage.getItem("username") 24 | ? localStorage.getItem("username") 25 | : "", 26 | newPassword: false, 27 | }; 28 | 29 | export default function authReducer(state = initialState, action) { 30 | switch (action.type) { 31 | case USER_LOADING: 32 | return { 33 | ...state, 34 | isLoading: true, 35 | }; 36 | case USER_LOADED: 37 | return { 38 | ...state, 39 | isLoading: false, 40 | }; 41 | case LOGIN_SUCCESS: 42 | if (action.payload.rememberme) { 43 | localStorage.setItem("token", action.payload.token); 44 | localStorage.setItem("refreshToken", action.payload.refreshToken); 45 | localStorage.setItem("userID", action.payload.userID); 46 | localStorage.setItem("username", action.payload.username); 47 | } 48 | return { 49 | ...state, 50 | ...action.payload, 51 | isAuthenticated: true, 52 | isLoading: false, 53 | }; 54 | case NEW_PASSWORD_SUCCESS: 55 | return { 56 | ...state, 57 | newPassword: true, 58 | isAuthenticated: false, 59 | }; 60 | case AUTH_ERROR: 61 | case LOGIN_FAIL: 62 | case LOGOUT_SUCCESS: 63 | case REGISTER_FAIL: 64 | case REGISTER_SUCCESS: 65 | localStorage.removeItem("token"); 66 | localStorage.removeItem("refreshToken"); 67 | localStorage.removeItem("userID"); 68 | localStorage.removeItem("username"); 69 | return { 70 | ...state, 71 | token: null, 72 | userID: "", 73 | username: "", 74 | isAuthenticated: false, 75 | isLoading: false, 76 | }; 77 | case REFRESH_TOKENS: 78 | if (action.payload.token && action.payload.refreshToken) { 79 | localStorage.setItem("token", action.payload.token); 80 | localStorage.setItem("refreshToken", action.payload.refreshToken); 81 | } 82 | return { 83 | ...state, 84 | ...action.payload, 85 | isAuthenticated: true, 86 | isLoading: false, 87 | }; 88 | default: 89 | return state; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /new_client/src/reducers/errorReducer.js: -------------------------------------------------------------------------------- 1 | import { GET_ERRORS, CLEAR_ERRORS } from "../actions/types"; 2 | 3 | const initialState = { 4 | msg: {}, 5 | status: null, 6 | id: null, 7 | }; 8 | 9 | export default function errorReducer(state = initialState, action) { 10 | switch (action.type) { 11 | case GET_ERRORS: 12 | return { 13 | msg: action.payload.msg, 14 | status: action.payload.status, 15 | id: action.payload.id, 16 | }; 17 | case CLEAR_ERRORS: 18 | return { 19 | msg: {}, 20 | status: null, 21 | id: null, 22 | }; 23 | default: 24 | return state; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /new_client/src/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from "redux"; 2 | import authReducer from "./authReducer"; 3 | import errorReducer from "./errorReducer"; 4 | 5 | const rootReducer = combineReducers({ 6 | auth: authReducer, 7 | error: errorReducer, 8 | }); 9 | 10 | export default rootReducer; 11 | -------------------------------------------------------------------------------- /new_client/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import "@testing-library/jest-dom/extend-expect"; 6 | -------------------------------------------------------------------------------- /new_client/src/store/configureStore.js: -------------------------------------------------------------------------------- 1 | import { createStore, compose, applyMiddleware } from "redux"; 2 | import rootReducer from "../reducers"; 3 | import thunk from "redux-thunk"; 4 | 5 | export default function configureStore(initialState) { 6 | const middleware = [thunk]; 7 | const composeEnhancers = 8 | window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; 9 | 10 | const store = createStore( 11 | rootReducer, 12 | initialState, 13 | composeEnhancers(applyMiddleware(...middleware)) 14 | ); 15 | 16 | if (module.hot) { 17 | module.hot.accept("../reducers", () => { 18 | const nextRootReducer = require("../reducers").default; 19 | store.replaceReducer(nextRootReducer); 20 | }); 21 | } 22 | 23 | return store; 24 | } 25 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cocwebsite", 3 | "version": "0.0.1", 4 | "private": true, 5 | "description": "monorepo for Community Of Coders, VJTI's website", 6 | "scripts": { 7 | "start:client": "yarn workspace coc-client start", 8 | "start:server": "yarn workspace coc-server start:dev", 9 | "dev": "concurrently --kill-others-on-fail \"yarn start:server\" \"yarn start:client\"" 10 | }, 11 | "workspaces": [ 12 | "server", 13 | "new_client" 14 | ], 15 | "repository": { 16 | "type": "git", 17 | "url": "git+https://github.com/CommunityOfCoders/COCWebsite.git" 18 | }, 19 | "license": "GPL-3.0-or-later", 20 | "bugs": { 21 | "url": "https://github.com/CommunityOfCoders/COCWebsite/issues" 22 | }, 23 | "homepage": "https://www.communityofcoders.in/", 24 | "dependencies": { 25 | "concurrently": "^7.0.0" 26 | } 27 | } -------------------------------------------------------------------------------- /prod/nginx.conf: -------------------------------------------------------------------------------- 1 | server { 2 | server_name communityofcoders.in www.communityofcoders.in; 3 | 4 | root /home/ubuntu/COCWebsite/new_client/build; 5 | index index.html index.htm; 6 | 7 | gzip on; 8 | gzip_vary on; 9 | gzip_proxied any; 10 | gzip_types text/plain application/javascript text/css application/json application/x-javascript text/javascript; 11 | gzip_comp_level 6; 12 | 13 | client_max_body_size 3M; 14 | 15 | location ~* \.(?:ico|css|js|gif|jpe?g|png|webp)$ { 16 | expires 365d; 17 | add_header Vary Accept-Encoding; 18 | add_header Cache-Control public; 19 | access_log off; 20 | } 21 | 22 | location / { 23 | try_files $uri $uri/ /index.html; 24 | } 25 | 26 | location /server { 27 | rewrite ^/server/(.*) /$1 break; 28 | proxy_pass http://127.0.0.1:8000; 29 | proxy_set_header Host $host; 30 | proxy_set_header X-Real-IP ip_address; 31 | } 32 | 33 | listen 443 ssl; # managed by Certbot 34 | ssl_certificate /etc/letsencrypt/live/communityofcoders.in/fullchain.pem; # managed by Certbot 35 | ssl_certificate_key /etc/letsencrypt/live/communityofcoders.in/privkey.pem; # managed by Certbot 36 | include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot 37 | ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot 38 | 39 | } 40 | 41 | 42 | 43 | 44 | server { 45 | if ($host = www.communityofcoders.in) { 46 | return 301 https://$host$request_uri; 47 | } # managed by Certbot 48 | 49 | 50 | if ($host = communityofcoders.in) { 51 | return 301 https://$host$request_uri; 52 | } # managed by Certbot 53 | 54 | 55 | server_name communityofcoders.in www.communityofcoders.in; 56 | listen 80; 57 | return 404; # managed by Certbot 58 | } 59 | -------------------------------------------------------------------------------- /server/.env.example: -------------------------------------------------------------------------------- 1 | CLOUDINARY_SECRET=your-cloudinary-secret 2 | MONGO_URI=your-dev-db-uri 3 | MONGO_URI_PROD=your-prod-db-uri 4 | ENCPASSWORD=your-generated-encpassword 5 | CRYPTOKEY=your-special-cryptokey 6 | CLOUDINARY_NAME=your-cloudinary-bucket-name 7 | CLOUDINARY_APIKEY=your-cloudinary-apikey 8 | GPHOTOSURL=your-gphotos-url 9 | MOCKAROO_API_KEY=your-mockaroo-apikey 10 | PASSWORD_HASH=your-password-hash -------------------------------------------------------------------------------- /server/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "parserOptions": { 3 | "ecmaVersion": 2018 4 | }, 5 | 6 | "env": { 7 | "es6": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /server/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | npm-debug.log* 3 | .env 4 | uploads/ 5 | src/views/*.html -------------------------------------------------------------------------------- /server/.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true -------------------------------------------------------------------------------- /server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "coc-server", 3 | "version": "1.0.0", 4 | "description": "Server for front end", 5 | "main": "src/app.js", 6 | "scripts": { 7 | "start": "NODE_ENV=production node src/app", 8 | "pretest": "eslint --ignore-path .gitignore . ", 9 | "test": "NODE_ENV=test mocha --recursive --timeout 120000 --exit", 10 | "start:dev": "nodemon src/app" 11 | }, 12 | "engines": { 13 | "node": ">=16.0.0", 14 | "npm": ">=8.0.0" 15 | }, 16 | "author": "", 17 | "license": "GPL-3.0-or-later", 18 | "dependencies": { 19 | "axios": "^0.21.2", 20 | "cloudinary": "^1.15.0", 21 | "compression": "^1.7.4", 22 | "cors": "^2.8.5", 23 | "date-fns": "^2.17.0", 24 | "dotenv": "^8.2.0", 25 | "ejs": "^3.1.7", 26 | "express": "^4.16.4", 27 | "express-validator": "^6.10.0", 28 | "jsonwebtoken": "^8.5.1", 29 | "mongoose": "^5.4.20", 30 | "morgan": "^1.9.1", 31 | "multer": "^1.4.1", 32 | "node-schedule": "^1.3.2", 33 | "nodemailer": "^6.4.11", 34 | "npm": "^6.14.7", 35 | "password-hasher": "^1.0.1", 36 | "redis": "^3.1.1", 37 | "sib-api-v3-sdk": "^8.2.0" 38 | }, 39 | "devDependencies": { 40 | "chai": "^4.2.0", 41 | "chai-http": "^4.3.0", 42 | "concurrently": "^5.1.0", 43 | "eslint": "^7.1.0", 44 | "eslint-config-strongloop": "^2.1.0", 45 | "mocha": "^7.1.2", 46 | "mongodb-memory-server": "^6.6.1", 47 | "nodemon": "^2.0.3" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /server/src/app.js: -------------------------------------------------------------------------------- 1 | require("dotenv").config(); 2 | const express = require("express"); 3 | const cors = require("cors"); 4 | const morgan = require("morgan"); 5 | const path = require("path"); 6 | const routes = require("./routes"); 7 | const config = require("./config"); 8 | const compression = require("compression"); 9 | const dbconnect = require("./config/dbconnect"); 10 | const rescheduler = require("./utility/eventRescheduler"); 11 | 12 | const app = express(); 13 | 14 | app.use(express.json({ limit: "10mb" })); 15 | 16 | var corsOptions = { 17 | origin: "http://localhost:3000", 18 | optionsSuccessStatus: 200, // For legacy browser support 19 | }; 20 | 21 | if (process.env.NODE_ENV === "production") { 22 | // corsOptions.origin = "https://communityofcoders.in"; 23 | corsOptions.origin = "*"; 24 | } 25 | 26 | app.use(cors(corsOptions)); 27 | 28 | app.set("view engine", "ejs"); 29 | 30 | if (process.env.NODE_ENV !== "test") { 31 | app.use(morgan("combined")); 32 | } 33 | 34 | routes(app); 35 | 36 | dbconnect(rescheduler.reschedule); 37 | 38 | app.get("/ethvjti", (req, res) => { 39 | res.send({"ok": "ok"}); 40 | }); 41 | 42 | app.use(express.static(path.resolve(__dirname, "../../new_client/build"))); 43 | 44 | app.get("/*", (req, res) => { 45 | res.sendFile(path.join(__dirname, "../../new_client/build/index.html")); 46 | }); 47 | 48 | let port = config.port; 49 | if (process.env.NODE_ENV === "test") port = 8001; 50 | 51 | app.listen(port, () => { 52 | console.log(`Server started on port ${port}`); 53 | }); 54 | 55 | module.exports = app; 56 | -------------------------------------------------------------------------------- /server/src/config/dbconnect.js: -------------------------------------------------------------------------------- 1 | require("dotenv").config(); 2 | const mongoose = require("mongoose"); 3 | 4 | function connect(callback) { 5 | const mongooseOptions = { 6 | useCreateIndex: true, 7 | useNewUrlParser: true, 8 | useUnifiedTopology: true, 9 | useFindAndModify: false, 10 | autoIndex: process.env.NODE_ENV !== "production" 11 | }; 12 | 13 | let connectionString = "mongodb://localhost:27017/test"; 14 | 15 | if (process.env.NODE_ENV !== "test") { 16 | if (process.env.NODE_ENV === "production") { 17 | connectionString = process.env.MONGO_URI_PROD; 18 | } else { 19 | connectionString = process.env.MONGO_URI; 20 | } 21 | } 22 | mongoose.connect(connectionString, mongooseOptions).then(() => { 23 | callback(); 24 | }); 25 | mongoose.Promise = global.Promise; 26 | mongoose.connection.on("open", () => console.log(`MongoDB Connected`)); 27 | mongoose.connection.on("error", console.error.bind(console, "Mongo Error")); 28 | // callback(); 29 | } 30 | 31 | module.exports = connect; 32 | -------------------------------------------------------------------------------- /server/src/config/index.js: -------------------------------------------------------------------------------- 1 | const config = { 2 | port: process.env.PORT || 8000, 3 | redis_port: process.env.REDIS_PORT || 6379, 4 | privateKey: process.env.JWT_PRIVATE_KEY || "COC is great", 5 | refreshPrivateKey: process.env.JWT_REFRESH_PRIVATE_KEY || "VJTI is great", 6 | oAuthClientID: 7 | "867161018507-an34btl13d6n23ujgcjnjpm4qvdacqss.apps.googleusercontent.com", 8 | oAuthclientSecret: "visPWNEfpoigIUS4MxzGxXPC", 9 | searchPageSize: 100, 10 | albumPageSize: 50, 11 | apiEndpoint: "https://photoslibrary.googleapis.com", 12 | env: "development" 13 | }; 14 | 15 | module.exports = config; 16 | -------------------------------------------------------------------------------- /server/src/config/redis.js: -------------------------------------------------------------------------------- 1 | const redis = require("redis"); 2 | const config = require("./index"); 3 | 4 | const redis_port = config.redis_port; 5 | 6 | const redis_client = redis.createClient(redis_port); 7 | 8 | module.exports = redis_client; 9 | -------------------------------------------------------------------------------- /server/src/config/sib.js: -------------------------------------------------------------------------------- 1 | const SibApiV3Sdk = require('sib-api-v3-sdk'); 2 | 3 | var defaultClient = SibApiV3Sdk.ApiClient.instance; 4 | var apiKey = defaultClient.authentications['api-key']; 5 | apiKey.apiKey = process.env.SIB_API_KEY; 6 | 7 | var apiInstance = new SibApiV3Sdk.ContactsApi(); 8 | 9 | module.exports = apiInstance; -------------------------------------------------------------------------------- /server/src/controllers/AchievementsController.js: -------------------------------------------------------------------------------- 1 | const Achievement = require('../models/Achievement'); 2 | const replaceDriveURL = require('../utility/replaceDriveURL'); 3 | 4 | module.exports = { 5 | async createAchievement(req, res, next) { 6 | try { 7 | const body = req.body; 8 | let projectUrl = ""; 9 | if (!!body['Project URL (Optional)'] && body['Project URL (Optional)'].length > 0) { 10 | projectUrl = body['Project URL (Optional)'][0]; 11 | } 12 | const achievement = { 13 | title: body['Achievement Title'][0], 14 | owner: { 15 | fullName: body['Full Name'][0], 16 | email: body['Email Address'][0] 17 | }, 18 | imageUrl: replaceDriveURL(body['Achievement Image'][0]), 19 | description: body['Achievement Description'][0] 20 | } 21 | if (!!projectUrl) { 22 | achievement["projectUrl"] = projectUrl; 23 | } 24 | await Achievement.create(achievement); 25 | res.status(200).json({ Status: "OK" }); 26 | next(); 27 | } catch (e) { 28 | return res.status(500).json({ error: e.message }); 29 | } 30 | }, 31 | async allAchievements(_, res, next) { 32 | try { 33 | const achievements = await Achievement.find({}).lean(); 34 | res.locals.cache = achievements; 35 | res.status(200).json(achievements); 36 | next(); 37 | } catch (e) { 38 | return res.status(500).json({ error: e.message }); 39 | } 40 | }, 41 | 42 | async getDummyAchievements(_, res) { 43 | const achievements = [ 44 | { 45 | title: 'First in SIH Hackathon', 46 | owner: { 47 | fullName: 'Smartest guy', 48 | email: 'guy@gmail.com' 49 | }, 50 | imageUrl: 'https://dealersupport.co.uk/wp-content/uploads/2020/03/iStock-659111108-587x381.jpg', 51 | projectUrl: 'https://github.com/CommunityOfCoders/COCWebsite', 52 | description: 'First in national hackathon with over 200 teams. Won in problem statement that implemented a basic crypto system.' 53 | }, 54 | { 55 | title: 'First in ACM-ICPC', 56 | owner: { 57 | fullName: 'Super smart guy', 58 | email: 'guy2@gmail.com' 59 | }, 60 | imageUrl: 'https://image.freepik.com/free-vector/winner_23-2147506357.jpg?2', 61 | projectUrl: 'https://github.com/CommunityOfCoders/COCWebsite', 62 | description: 'Won the Olympics of competitive coding globally. ' 63 | }, 64 | { 65 | title: 'Google internship', 66 | owner: { 67 | fullName: 'Richest guy', 68 | email: 'richguy@gmail.com' 69 | }, 70 | imageUrl: 'https://image.freepik.com/free-vector/winner_23-2147506357.jpg?2', 71 | description: 'Do I really need to explain that?' 72 | } 73 | ] 74 | return res.status(200).json(achievements) 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /server/src/controllers/AlumniController.js: -------------------------------------------------------------------------------- 1 | const Alumnus = require('../models/Alumnus'); 2 | const replaceDriveURL = require('../utility/replaceDriveURL'); 3 | 4 | module.exports = { 5 | async createAlumnus(req, res, next) { 6 | // Shape of Data 7 | /* 8 | { 9 | Timestamp: [ '2/3/2021 14:07:55' ], 10 | 'Current Company/Institute Name': [ 'VJTI' ], 11 | 'Full Github Profile URL': [ 'https://github.com/ShubhankarKG' ] // Optional, 12 | 'Full Profile URL (portfolio)': [ 'https://abc.xyz' ] // Optional, 13 | '': [ '' ], 14 | 'Full Twitter Profile URL': [ 'https://twitter.com/ShubhankarKG' ] // Optional, 15 | 'Current Professional Title': [ 'Student' ], 16 | 'Email Address': [ 'shubhankar.gupto.11@gmail.com' ], 17 | 'Full Instagram Profile URL': [ '' ] // Optional, 18 | 'Full Facebook Profile URL': [ '' ] // Optional, 19 | 'Last Name': [ 'Gupta' ], 20 | 'Graduation Year': [ '2022' ], 21 | 'Current Work City': [ 'badlapur' ], 22 | 'First Name': [ 'Shubhankar' ], 23 | 'Full LinkedIn Profile URL': [ 'None' ] // Optional, 24 | 'Profile Image': [ 25 | 'https://drive.google.com/open?id=179e1u3bsbwolEv0bgEBEbz25zLjN10gp' 26 | ] 27 | } 28 | */ 29 | try { 30 | const body = req.body; 31 | // Compulsory stuff 32 | let alumnus = { 33 | fullName: body["First Name"][0] + " " + body["Last Name"][0], 34 | email: body["Email Address"][0], 35 | city: body["Current Work City"][0], 36 | graduationYear: body["Graduation Year"][0], 37 | imageUrl: replaceDriveURL(body["Profile Image"][0]), 38 | company: body["Current Company/Institute Name"][0], 39 | professionalTitle: body["Current Professional Title"][0], 40 | } 41 | 42 | // Optional stuff 43 | alumnus["socialUrls"] = {}; 44 | if (body["Full Github Profile URL"] && body["Full Github Profile URL"].length > 0) { 45 | alumnus["socialUrls"]["github"] = body["Full Github Profile URL"][0]; 46 | } 47 | if (body["Full LinkedIn Profile URL"] && body["Full LinkedIn Profile URL"].length > 0) { 48 | alumnus["socialUrls"]["linkedin"] = body["Full LinkedIn Profile URL"][0]; 49 | } 50 | if (body["Full Twitter Profile URL"] && body["Full Twitter Profile URL"].length > 0) { 51 | alumnus["socialUrls"]["twitter"] = body["Full Twitter Profile URL"][0]; 52 | } 53 | if (body["Full Instagram Profile URL"] && body["Full Instagram Profile URL"].length > 0) { 54 | alumnus["socialUrls"]["instagram"] = body["Full Instagram Profile URL"][0]; 55 | } 56 | if (body["Full Facebook Profile URL"] && body["Full Facebook Profile URL"].length > 0) { 57 | alumnus["socialUrls"]["instagram"] = body["Full Facebook Profile URL"][0]; 58 | } 59 | if (body["Full Profile URL (portfolio)"] && body["Full Profile URL (portfolio)"].length > 0) { 60 | alumnus["socialUrls"]["personal"] = body["Full Profile URL (portfolio)"][0]; 61 | } 62 | await Alumnus.create(alumnus); 63 | res.status(200).json({ Status: "OK" }); 64 | next(); 65 | } catch (e) { 66 | return res.status(500).json({ error: e.message }); 67 | } 68 | 69 | }, 70 | async allAlumni(_, res, next) { 71 | try { 72 | const alumni = await Alumnus.find({}).lean(); 73 | res.locals.cache = alumni; 74 | res.status(200).json(alumni); 75 | next(); 76 | } catch (e) { 77 | return res.status(500).json({ error: e.message }); 78 | } 79 | } 80 | }; 81 | -------------------------------------------------------------------------------- /server/src/controllers/Blogs.js: -------------------------------------------------------------------------------- 1 | const User = require("../models/User"); 2 | const Blog = require("../models/Blog"); 3 | 4 | module.exports = { 5 | async allBlogs(_req, res) { 6 | try { 7 | let blogs = await Blog.find().lean(); 8 | blogs = blogs.sort((a, b) => { 9 | if (Date(b.date) > Date(a.date)) return 1; 10 | else return -1; 11 | }); 12 | res.status(200).json({ blogs }); 13 | } catch (e) { 14 | res.status(400).json({ error: e.message }); 15 | } 16 | }, 17 | 18 | async viewBlogById(req, res) { 19 | try { 20 | const blogId = req.params.id; 21 | const blog = await Blog.findById(blogId).lean(); 22 | if (blog) { 23 | return res.status(200).json(blog); 24 | } else { 25 | res.status(404).json({ 26 | error: "The requested blog doesn't exist", 27 | }); 28 | } 29 | } catch (e) { 30 | res.status(500).json({ error: e.message }); 31 | } 32 | }, 33 | 34 | async viewBlogsByTag(req, res) { 35 | try { 36 | const tag = req.params.tag; 37 | let blogs = await Blog.find({tags: {$in: [tag]}}) 38 | blogs = blogs.sort((a, b) => { 39 | if (Date(b.date) > Date(a.date)) return 1; 40 | else return -1; 41 | }); 42 | res.status(200).json({ blogs }); 43 | } catch (e) { 44 | res.status(500).json({ error: e.message }); 45 | } 46 | }, 47 | 48 | async uploadBlog(req, res) { 49 | try { 50 | // Assumed that req.body already has required fields 51 | const blog = await Blog.create(req.body); 52 | res.status(201).json({ 53 | id: blog._id, 54 | }); 55 | } catch (error) { 56 | res.status(500).json({ 57 | error, 58 | }); 59 | } 60 | }, 61 | 62 | async editBlogById(req, res) { 63 | try { 64 | // Assumed that req.body already has required fields 65 | const blog = await Blog.findByIdAndUpdate(req.params.id, req.body, { 66 | new: true, 67 | }).select({ "_id": 1, "blogTitle": 1 }).lean(); 68 | res.json({ 69 | id: blog._id, 70 | blogTitle: blog.blogTitle, 71 | }); 72 | } catch (error) { 73 | res.status(400).json({ 74 | error: error.message, 75 | }); 76 | } 77 | }, 78 | async deleteBlogById(req, res, next) { 79 | try { 80 | const blogId = req.params.id; 81 | await Blog.findByIdAndDelete(blogId).lean(); 82 | res.status(204).json({}); 83 | } catch(error) { 84 | res.status(500).json({ 85 | error, 86 | }); 87 | } 88 | }, 89 | }; 90 | -------------------------------------------------------------------------------- /server/src/controllers/DomainController.js: -------------------------------------------------------------------------------- 1 | const Domain = require('../models/Domain.js'); 2 | 3 | module.exports = { 4 | async allDomains(_req, res, next) { 5 | try { 6 | const domains = await Domain.find().lean(); 7 | res.status(200).json(domains); 8 | res.locals.cache = domains; 9 | next(); 10 | } catch (e) { 11 | res.status(500).json({ error: e.message }); 12 | } 13 | }, 14 | async viewDomainById(req, res) { 15 | try { 16 | const domain = await Domain.findById(req.params.id).lean(); 17 | if (domain) { 18 | res.status(200).json(domain); 19 | } else { 20 | res.status(404).json({ error: "The requested domain doesn't exist" }); 21 | } 22 | } catch (e) { 23 | res.status(500).json({ error: e.message }); 24 | } 25 | }, 26 | async createDomain(req, res, next) { 27 | try { 28 | const domain = await Domain.create(req.body); 29 | res.status(201).json({ id: domain._id }); 30 | next(); 31 | } catch (e) { 32 | res.status(500).json({ error: e.message }); 33 | } 34 | }, 35 | async editDomainById(req, res, next) { 36 | try { 37 | const domain = await Domain.findByIdAndUpdate(req.params.id, req.body, { 38 | new: true 39 | }).lean(); 40 | res.status(200).json(domain); 41 | next(); 42 | } catch (e) { 43 | res.status(500).json({ error: e.message }); 44 | } 45 | }, 46 | async deleteDomainById(req, res, next) { 47 | await Domain.findByIdAndRemove(req.params.id).lean(); 48 | res.status(204).json({}); 49 | next(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /server/src/controllers/EthVJTIController.js: -------------------------------------------------------------------------------- 1 | const EthUser = require("../models/EthVJTIWallet"); 2 | const sendEmail = require("../utility/sendEmail"); 3 | 4 | const generateOTP = () => { 5 | var digits = "0123456789"; 6 | let OTP = ""; 7 | for (let i = 0; i < 4; i++) { 8 | OTP += digits[Math.floor(Math.random() * 10)]; 9 | } 10 | return OTP; 11 | }; 12 | 13 | // sending mail to single user 14 | const sendMailToSingerUser = async (otp, email) => { 15 | const mailSubject = "EthVJTI Launch NFT One Time Password"; 16 | const mailData = `Your OTP for EthVJTI Launch NFT is: ${otp}`; 17 | await sendEmail(email, mailSubject, mailData); 18 | }; 19 | 20 | const sendOTP = async (req, res) => { 21 | try { 22 | const { email, walletAddress } = req.body; 23 | const newOTP = generateOTP(); 24 | 25 | const userDetails = { 26 | email, 27 | walletAddress, 28 | isMinted: false, 29 | emailVerificationOTP: newOTP, 30 | }; 31 | 32 | const userCheck = await EthUser.findOne({ 33 | email: email, 34 | }) 35 | .lean(); 36 | 37 | let newUser; 38 | if(userCheck){ 39 | if(userCheck.isMinted){ 40 | return res.status(400).json({ error: "NFT is already minted for this user" }); 41 | } 42 | sendMailToSingerUser(newOTP, email); 43 | newUser = await EthUser.findByIdAndUpdate( 44 | userCheck._id, 45 | userDetails, 46 | {new: true} 47 | ); 48 | }else{ 49 | res.status(404).json({error: "Email ID was not registered"}); 50 | } 51 | 52 | return res 53 | .status(200) 54 | .json({ 55 | message: `OTP Sent to ${email}`, 56 | user: newUser, 57 | }); 58 | } catch (error) { 59 | return res.status(400).json({ error: error.message }); 60 | } 61 | }; 62 | 63 | const verifyOTP = async (req, res) => { 64 | try { 65 | const { email, otp } = req.body; 66 | 67 | const userCheck = await EthUser.findOne({ 68 | email: email, 69 | }) 70 | .lean(); 71 | if(userCheck && userCheck.emailVerificationOTP == otp){ 72 | // await EthUser.findByIdAndUpdate(userCheck._id, {isMinted: true, emailVerificationOTP: ""}); 73 | await EthUser.findByIdAndUpdate(userCheck._id, {emailVerificationOTP: ""}); 74 | return res.status(200).json({ message: "OTP Correct", email: email }); 75 | } 76 | return res.status(400).json({ error: "OTP not valid" }); 77 | } catch (error) { 78 | return res.status(400).json({ error: error.message }); 79 | } 80 | }; 81 | 82 | const setMinted = async (req, res) => { 83 | try { 84 | const { email, walletAddress } = req.body; 85 | 86 | const userCheck = await EthUser.findOne({ 87 | email: email, 88 | }) 89 | .lean(); 90 | if(userCheck){ 91 | await EthUser.findByIdAndUpdate(userCheck._id, {isMinted: true, emailVerificationOTP: ""}); 92 | return res.status(200).json({ message: "User set as minted", email: email }); 93 | } 94 | return res.status(400).json({ error: "Email not found" }); 95 | } catch (error) { 96 | return res.status(400).json({ error: error.message }); 97 | } 98 | }; 99 | 100 | 101 | module.exports = { 102 | sendOTP, 103 | verifyOTP, 104 | setMinted 105 | } -------------------------------------------------------------------------------- /server/src/controllers/GlimpseController.js: -------------------------------------------------------------------------------- 1 | require("dotenv").config(); 2 | const axios = require("axios"); 3 | const Glimpses = require("../models/GLimpses"); 4 | const extractPhotos = require("../utility/extractPhotos"); 5 | 6 | module.exports = { 7 | async getPhotos(req, res) { 8 | const { gPhotosUrl } = req.body; 9 | const response = await axios.get(gPhotosUrl); 10 | res.status(200).json(extractPhotos(response.data)); 11 | }, 12 | 13 | async getAllGlimpses(req, res) { 14 | try { 15 | const glimpses = await Glimpses.find({}); 16 | const imageUrls = glimpses.map((glimpse) => glimpse.albumPath); 17 | const response = await axios.all(imageUrls.map((url) => axios.get(url))); 18 | let returnArr = []; 19 | for (let i = 0; i < glimpses.length; i += 1) { 20 | const result = extractPhotos(response[i].data)[0]; 21 | const modObj = { 22 | ...glimpses[i]["_doc"], 23 | preview: result, 24 | }; 25 | returnArr.push(modObj); 26 | } 27 | return res.status(200).json({ data: returnArr }); 28 | } catch (e) { 29 | return res.status(500).json({ error: e.message }); 30 | } 31 | }, 32 | 33 | async getGlimpse(req, res) { 34 | const { id } = req.params; 35 | if (!id) { 36 | return res.status(404).json({ error: "Glimpse does not exist" }); 37 | } 38 | try { 39 | const glimpse = await Glimpses.findById(id); 40 | return res.status(200).json({ glimpse }); 41 | } catch (e) { 42 | return res.status(500).json({ error: e.message }); 43 | } 44 | }, 45 | 46 | async addGlimpse(req, res) { 47 | const { albumPath, eventName } = req.body; 48 | if (!albumPath) { 49 | return res.status(400).json({ error: "Incomplete albumPath" }); 50 | } 51 | if (!eventName) { 52 | return res.status(400).json({ error: "Incomplete eventName" }); 53 | } 54 | 55 | // Check on albumPath because Eventnames shall be same over a period of time 56 | const existingGlimpse = await Glimpses.findOne({ albumPath }); 57 | if (!!existingGlimpse) { 58 | return res.status(422).json({ error: "Glimpse already exists" }); 59 | } 60 | 61 | const newGlimpse = { albumPath, eventName }; 62 | try { 63 | const glimpse = await Glimpses.create(newGlimpse); 64 | return res.status(201).json({ glimpse }); 65 | } catch (e) { 66 | return res.status(500).json({ error: e.message }); 67 | } 68 | }, 69 | 70 | async editGlimpse(req, res) { 71 | const { albumPath, eventName } = req.body; 72 | const { id } = req.params; 73 | 74 | const newGlimpse = { albumPath, eventName }; 75 | try { 76 | const glimpse = await Glimpses.findByIdAndUpdate(id, newGlimpse, { 77 | new: true, 78 | }); 79 | return res.status(200).json({ glimpse }); 80 | } catch (e) { 81 | return res.status(500).json({ error: e.message }); 82 | } 83 | }, 84 | 85 | async deleteGlimpse(req, res) { 86 | const { id } = req.params; 87 | 88 | try { 89 | await Glimpses.findByIdAndDelete(id); 90 | return res.status(204).json({}); 91 | } catch (e) { 92 | return res.status(500).json({ error: e.message }); 93 | } 94 | }, 95 | }; 96 | -------------------------------------------------------------------------------- /server/src/controllers/ProjectController.js: -------------------------------------------------------------------------------- 1 | const Domain = require('../models/Domain.js'); 2 | const Project = require('../models/Project.js'); 3 | 4 | module.exports = { 5 | async allProjects(_req, res, next) { 6 | try { 7 | const projects = await Project.find().populate({ 8 | path: 'domains', 9 | select: ['_id', 'domainName'] 10 | }).lean().exec(); 11 | res.locals.cache = projects; 12 | res.status(200).json({ projects }); 13 | next(); 14 | } catch (e) { 15 | res.status(500).json({ error: e.message }); 16 | } 17 | }, 18 | async viewProjectsByDomain(req, res) { 19 | try { 20 | const domain = await Domain.findById(req.params.id).populate({ 21 | path: 'projects', 22 | populate: { 23 | path: 'domains', 24 | select: ['_id', 'domainName'] 25 | } 26 | }); 27 | if (domain) { 28 | res.status(200).json({ projects: domain.projects }); 29 | } else { 30 | res.status(404).json({ error: "The requested domain doesn't exist" }); 31 | } 32 | } catch (e) { 33 | res.status(500).json({ error: e }); 34 | } 35 | }, 36 | async viewProjectById(req, res) { 37 | try { 38 | const project = await Project.findById(req.params.id).populate({ 39 | path: 'domains', 40 | select: ['_id', 'domainName'] 41 | }).lean().exec(); 42 | if (project) { 43 | res.status(200).json(project); 44 | } else { 45 | res.status(404).json({ error: "The requested project doesn't exist" }); 46 | } 47 | } catch (e) { 48 | res.status(500).json({ error: e.message }); 49 | } 50 | }, 51 | async createProject(req, res, next) { 52 | try { 53 | // assumes that domain of the project already exists 54 | const project = await Project.create(req.body); 55 | for (const domainId of project.domains) { 56 | let domain = await Domain.findById(domainId); 57 | domain.projects.push(project._id); 58 | await domain.save(); 59 | } 60 | res.status(201).json({ id: project._id }); 61 | next(); 62 | } catch (e) { 63 | res.status(500).json({ error: e.message }); 64 | } 65 | }, 66 | async deleteProjectById(req, res, next) { 67 | try { 68 | const projectId = req.params.id; 69 | const project = await Project.findById(projectId); 70 | const domains = project.domains; 71 | for (const domainId of domains) { 72 | let domain = await Domain.findById(domainId); 73 | domain.projects = domain.projects.filter((id) => { 74 | return id !== projectId; 75 | }); 76 | await domain.save(); 77 | } 78 | await Project.findByIdAndRemove(projectId).lean(); 79 | res.status(204).json({}); 80 | next(); 81 | } catch (e) { 82 | res.status(500).json({ error: e.message }); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /server/src/controllers/Register.js: -------------------------------------------------------------------------------- 1 | const FormElement = require('../models/FormElement'); 2 | module.exports = { 3 | regForm(req, res) { 4 | const elements = elementsValidate(req.elements); 5 | for(const element of elements) { 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /server/src/middleware/blog.js: -------------------------------------------------------------------------------- 1 | const jwt = require("jsonwebtoken"); 2 | const config = require("../config"); 3 | const Blog = require("../models/Blog"); 4 | 5 | module.exports = { 6 | async isBlogAuthorized(req, res, next) { 7 | try { 8 | const token = req.headers.authorization.split(" ")[1]; 9 | const decodedToken = jwt.verify(token, config.privateKey); 10 | if (decodedToken.user.isBlogAuthorized) return next(); 11 | else return res.status(403).json({ error: "Blog not authorized" }); 12 | } catch (e) { 13 | return res.status(500).json({ error: e.message }); 14 | } 15 | // req.flash('error_msgs', 'Please log in to access this page'); 16 | }, 17 | 18 | async isBlogWritten(req, res, next) { 19 | const { id } = req.params; 20 | const blog = await Blog.findById(id).select({"authorID":1}).lean(); 21 | if (blog.authorID.toString() === req.userID) { 22 | next(); 23 | } else { 24 | return res.status(403).json({ error: "You have not written this blog!" }); 25 | } 26 | }, 27 | }; 28 | -------------------------------------------------------------------------------- /server/src/middleware/cache.js: -------------------------------------------------------------------------------- 1 | const redis_client = require("../config/redis"); 2 | 3 | module.exports = { 4 | getFromCache(req, res, next) { 5 | const type = req.path.split("/")[2]; // returns blogs, events, etc. 6 | redis_client.get(type, (err, data) => { 7 | if (err) { 8 | next(); 9 | } 10 | 11 | if (data != null) { 12 | const return_data = JSON.parse(data); 13 | console.log("Returning from cache"); 14 | res.status(200).json(return_data); 15 | } else { 16 | next(); 17 | } 18 | }); 19 | }, 20 | 21 | deleteCache(req, res) { 22 | const type = req.path.split("/")[2]; // returns blogs, events, etc. 23 | redis_client.del(type); 24 | }, 25 | 26 | setCache(req, res) { 27 | const type = req.path.split("/")[2]; 28 | redis_client.set(type, JSON.stringify(res.locals.cache)) 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /server/src/middleware/event.js: -------------------------------------------------------------------------------- 1 | const { body, param, query } = require('express-validator'); 2 | 3 | module.exports = { 4 | validate(method) { 5 | switch (method) { 6 | case 'checkID': { 7 | return [ 8 | param('id', 'invalid id').isMongoId() 9 | ] 10 | } 11 | case 'checkEventBody': { 12 | return [ 13 | body('eventName', 'eventName is required').exists(), 14 | body('description', 'description is required').exists().trim().escape(), 15 | body('venue', 'venue is required').exists(), 16 | body('date', 'date is required').exists(), 17 | body('graduationYear', 'graduationYear is required').exists(), 18 | ] 19 | } 20 | case 'checkFormURL': { 21 | return [ 22 | body('formURL', 'formURL is required').exists() 23 | ] 24 | } 25 | case 'checkQueryParams': { 26 | return [ 27 | query('uid', 'uid is required').exists().isMongoId(), 28 | query('eid', 'eid is required').exists().isMongoId() 29 | ] 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /server/src/middleware/upload.js: -------------------------------------------------------------------------------- 1 | const multer = require('multer') 2 | const path = require('path') 3 | 4 | function checkFileType(file, cb){ 5 | // Allowed ext 6 | const filetypes = /jpeg|jpg|png|gif|pdf/; 7 | // Check ext 8 | const extname = filetypes.test(path.extname(file.originalname).toLowerCase()); 9 | // Check mime 10 | const mimetype = filetypes.test(file.mimetype); 11 | 12 | if(mimetype && extname){ 13 | return cb(null,true); 14 | } else { 15 | cb('Error: Images Only!'); 16 | } 17 | } 18 | 19 | var upload = multer({ 20 | dest: 'uploads/', 21 | limits:{fileSize: 30*1024*1024}, 22 | fileFilter: function(req, file, cb){ 23 | checkFileType(file, cb); 24 | } 25 | }); 26 | 27 | module.exports = upload -------------------------------------------------------------------------------- /server/src/middleware/user.js: -------------------------------------------------------------------------------- 1 | const User = require("../models/User") 2 | 3 | module.exports = { 4 | async isMember(req,res,next){ 5 | try{ 6 | if(req.user.isMember) 7 | return next(); 8 | else 9 | return res.status(403).json({error:"You are not authorized"}) 10 | }catch(e){ 11 | return res.status(500).json({error:e.message}) 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /server/src/models/Achievement.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | 3 | const achievement = new mongoose.Schema({ 4 | title: { 5 | type: String, 6 | required: true, 7 | }, 8 | owner: { 9 | type: { 10 | fullName: { 11 | type: String, 12 | required: true 13 | }, 14 | email: { 15 | type: String, 16 | required: true 17 | } 18 | }, 19 | required: true 20 | }, 21 | description: { 22 | type: String, 23 | required: true 24 | }, 25 | imageUrl: { 26 | type: String, 27 | required: true 28 | }, 29 | projectUrl: { 30 | type: String, 31 | required: false 32 | } 33 | }); 34 | 35 | const Achievement = mongoose.model('achievement', achievement); 36 | 37 | module.exports = Achievement; 38 | -------------------------------------------------------------------------------- /server/src/models/Alumnus.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | 3 | const alumnus = new mongoose.Schema({ 4 | fullName: { 5 | type: String, 6 | required: true 7 | }, 8 | email: { 9 | type: String, 10 | required: true 11 | }, 12 | city: { 13 | type: String, 14 | required: true 15 | }, 16 | graduationYear: { 17 | type: String, 18 | required: true 19 | }, 20 | socialUrls: { 21 | personal: String, 22 | facebook: String, 23 | github: String, 24 | instagram: String, 25 | linkedin: String, 26 | twitter: String, 27 | }, 28 | imageUrl: { 29 | type: String, 30 | }, 31 | company: { 32 | type: String, 33 | required: true 34 | }, 35 | professionalTitle: { 36 | type: String, 37 | required: true 38 | }, 39 | date: { 40 | type: Date, 41 | default: Date.now 42 | } 43 | }); 44 | 45 | const Alumnus = mongoose.model('alumnus', alumnus); 46 | 47 | module.exports = Alumnus; 48 | -------------------------------------------------------------------------------- /server/src/models/Blog.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | 3 | const blog = new mongoose.Schema({ 4 | blogTitle: { 5 | type: String, 6 | required: true 7 | }, 8 | blogContent: { 9 | type: String, 10 | required: true 11 | }, 12 | tags: { 13 | type: Array, 14 | required: false 15 | }, 16 | date: { 17 | type: Date, 18 | required: true, 19 | default: Date.now 20 | }, 21 | author: { 22 | type: String, 23 | required: true 24 | }, 25 | authorID: { 26 | type: mongoose.Schema.Types.ObjectId, 27 | ref: 'users', 28 | required: true 29 | } 30 | }); 31 | 32 | const Blog = mongoose.model('blog', blog); 33 | 34 | module.exports = Blog; 35 | -------------------------------------------------------------------------------- /server/src/models/Company.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const company = new mongoose.Schema({ 4 | title: { 5 | type: String, 6 | required: true, 7 | unique: true, 8 | }, 9 | image: { 10 | url: String, 11 | public_id: String, 12 | }, 13 | }); 14 | 15 | const Company = mongoose.model("company", company); 16 | 17 | module.exports = Company; 18 | -------------------------------------------------------------------------------- /server/src/models/Domain.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | 3 | const domain = new mongoose.Schema({ 4 | domainName: { 5 | type: String, 6 | required: true 7 | }, 8 | domainDescription: { 9 | type: String, 10 | required: true 11 | }, 12 | imageUrl: { 13 | type: String, 14 | required: true 15 | }, 16 | projects: { 17 | type: [{ 18 | type: mongoose.Schema.Types.ObjectId, 19 | ref: 'project' 20 | }], 21 | required: false, 22 | default: [] 23 | } 24 | }); 25 | 26 | const Domain = mongoose.model('domain', domain); 27 | 28 | module.exports = Domain; 29 | -------------------------------------------------------------------------------- /server/src/models/EthVJTIWallet.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose') 2 | 3 | const ethuser = new mongoose.Schema({ 4 | email: { 5 | type: String, 6 | required: true 7 | }, 8 | walletAddress: { 9 | type: String, 10 | required: false 11 | }, 12 | isMinted: { 13 | type: Boolean, 14 | required: false, 15 | default: false, 16 | }, 17 | emailVerificationOTP: { 18 | type: String, 19 | required: false 20 | } 21 | }) 22 | 23 | ethuser.index({ email: 1 }) 24 | 25 | const EthUser = mongoose.model('ethuser', ethuser) 26 | 27 | module.exports = EthUser; 28 | -------------------------------------------------------------------------------- /server/src/models/Event.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const event = new mongoose.Schema({ 4 | eventName: { 5 | type: String, 6 | required: true, 7 | }, 8 | description: { 9 | type: String, 10 | required: true, 11 | }, 12 | venue: { 13 | type: String, 14 | required: true, 15 | }, 16 | date: { 17 | type: String, 18 | required: true, 19 | }, 20 | graduationYearFrom: { 21 | type: Number, 22 | required: true, 23 | }, 24 | graduationYearTo: { 25 | type: Number, 26 | required: true, 27 | }, 28 | image: { 29 | url: String, 30 | public_id: String, 31 | }, 32 | // form: { 33 | // type: mongoose.Schema.Types.ObjectId, 34 | // ref: 'registerForm' 35 | // } 36 | form: { 37 | type: String, 38 | }, 39 | registeredUsers: { 40 | type: [ 41 | { 42 | type: mongoose.Schema.Types.ObjectId, 43 | ref: "users", 44 | }, 45 | ], 46 | required: false, 47 | default: [], 48 | }, 49 | }); 50 | 51 | const Event = mongoose.model("events", event); 52 | 53 | module.exports = Event; 54 | -------------------------------------------------------------------------------- /server/src/models/FormElement.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | 3 | const formElement = new mongoose.Schema({ 4 | elementType: { 5 | type: String, 6 | enum: ['text', 'email', 'url', 'number', 'checkbox', 'radio', 'textarea', 'label'], 7 | required: true 8 | }, 9 | name: { 10 | type: String, 11 | required: true 12 | }, 13 | attr: [mongoose.Schema.Types.Mixed] 14 | }); 15 | 16 | const FormElement = mongoose.model('formElement', formElement); 17 | 18 | module.exports = FormElement; -------------------------------------------------------------------------------- /server/src/models/GLimpses.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose') 2 | 3 | const glimpse = new mongoose.Schema({ 4 | eventName: { 5 | type: String, 6 | required: true 7 | }, 8 | albumPath: { 9 | type: String 10 | } 11 | }) 12 | 13 | const Glimpses = mongoose.model('glimpses',glimpse) 14 | 15 | module.exports = Glimpses; -------------------------------------------------------------------------------- /server/src/models/Interview.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose') 2 | 3 | const interview = new mongoose.Schema({ 4 | title: { 5 | type: String, 6 | required: true, 7 | unique: true, 8 | }, 9 | createdBy: { type: String, required: true }, 10 | userId: { type: mongoose.Schema.Types.ObjectId, ref: 'users' }, 11 | company: { 12 | type: mongoose.Schema.Types.ObjectId, 13 | ref: 'company' 14 | }, 15 | companyRequest: { type: String, required: true }, 16 | content: { type: Object }, 17 | isVerified: { type: Boolean, default: false }, 18 | isDraft: { type: Boolean, required: true }, 19 | appliedFor: { type: String, required: true }, 20 | appliedYear: { type: Number, required: true }, 21 | }); 22 | 23 | const Interview = mongoose.model('interview', interview); 24 | 25 | module.exports = Interview; 26 | -------------------------------------------------------------------------------- /server/src/models/Magazine.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | 3 | const magazine = new mongoose.Schema({ 4 | 5 | magazineName : { 6 | type:String, 7 | required:true, 8 | }, 9 | date : { 10 | type:Date, 11 | required:true, 12 | }, 13 | 14 | description : { 15 | type:String, 16 | }, 17 | 18 | downloadURL : { 19 | type:String, 20 | }, 21 | photoURL : { 22 | type:String, 23 | } 24 | }); 25 | 26 | const Magazine = mongoose.model("magazines",magazine); 27 | 28 | module.exports = Magazine; -------------------------------------------------------------------------------- /server/src/models/Project.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | 3 | const project = new mongoose.Schema({ 4 | projectTitle: { 5 | type: String, 6 | required: true 7 | }, 8 | projectDescription: { 9 | type: String, 10 | required: true 11 | }, 12 | imageUrl: { 13 | type: String, 14 | required: true 15 | }, 16 | projectUrl: { 17 | type: String, 18 | required: true 19 | }, 20 | date: { 21 | type: Date, 22 | required: true, 23 | default: Date.now 24 | }, 25 | owner: { 26 | type: { 27 | name: { 28 | type: String, 29 | required: true 30 | }, 31 | email: String, 32 | githubUrl: String 33 | }, 34 | required: true 35 | }, 36 | domains: { 37 | type: [{ 38 | type: mongoose.Schema.Types.ObjectId, 39 | ref: 'domain' 40 | }], 41 | required: true 42 | } 43 | }); 44 | 45 | const Project = mongoose.model('project', project); 46 | 47 | module.exports = Project; 48 | -------------------------------------------------------------------------------- /server/src/models/RegisterForm.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | const Schema = mongoose.Schema; 3 | 4 | const registerForm = Schema({ 5 | formElements: [{ 6 | type: Schema.Types.ObjectId, 7 | ref: 'formElement' 8 | }], 9 | maxGradYear: Number, 10 | title: String, 11 | description: String, 12 | max_responses: Number, 13 | mail_response: Boolean, 14 | closeTime: Date 15 | }); 16 | 17 | module.exports = mongoose.Model('registerForm', registerForm); -------------------------------------------------------------------------------- /server/src/models/Resources.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const resource = new mongoose.Schema({ 4 | title: { 5 | type: String, 6 | required: true, 7 | }, 8 | description: { 9 | type: String, 10 | required: true, 11 | }, 12 | link: { 13 | type: String, 14 | required: true, 15 | }, 16 | }); 17 | 18 | const topic = new mongoose.Schema({ 19 | name: { 20 | type: String, 21 | required: true, 22 | }, 23 | resources: { 24 | type: [ 25 | { 26 | type: mongoose.Schema.Types.ObjectId, 27 | ref: "resource", 28 | }, 29 | ], 30 | default: [], 31 | required: false, 32 | }, 33 | }); 34 | 35 | const Resource = mongoose.model("resource", resource); 36 | const Topic = mongoose.model("topic", topic); 37 | 38 | module.exports = { Resource, Topic }; 39 | -------------------------------------------------------------------------------- /server/src/models/User.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose') 2 | 3 | const user = new mongoose.Schema({ 4 | username: { 5 | type: String, 6 | unique: true, 7 | required: true 8 | }, 9 | password: { 10 | type: String, 11 | required: true 12 | }, 13 | email: { 14 | type: String, 15 | required: true 16 | }, 17 | graduationYear: { 18 | type: Number, 19 | required: true 20 | }, 21 | isMember: { // if true, the name and image will be shown on the members page 22 | type: Boolean, 23 | required: true, 24 | default: false 25 | }, 26 | isBlogAuthorized: { 27 | type: Boolean, 28 | required: true, 29 | default: false 30 | }, 31 | description: { // member description 32 | type: String, 33 | required: false 34 | }, 35 | image: { // member image 36 | data: Buffer, 37 | contentType: String, 38 | default: "" 39 | }, 40 | passwordResetToken: { 41 | type: String, 42 | required: false 43 | }, 44 | passwordResetTokenTime: { 45 | type: Date, 46 | required: false 47 | }, 48 | isEmailVerified: { 49 | type:Boolean, 50 | required: true, 51 | default: false 52 | }, 53 | emailVerificationToken: { 54 | type: String, 55 | required: false 56 | } 57 | }) 58 | 59 | user.index({ username: 1 }) 60 | 61 | const User = mongoose.model('users', user) 62 | 63 | module.exports = User; 64 | -------------------------------------------------------------------------------- /server/src/utility/crypt.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config(); 2 | const crypto = require('crypto'); 3 | 4 | const algorithm = 'aes-256-ctr'; 5 | const cryptoKey = process.env.CRYPTOKEY; 6 | 7 | const encrypt = text => { 8 | const cipher = crypto.createCipher(algorithm, cryptoKey); 9 | let crypted = cipher.update(text, 'utf8', 'hex'); 10 | crypted += cipher.final('hex'); 11 | return crypted; 12 | }; 13 | 14 | const decrypt = text => { 15 | const decipher = crypto.createDecipher(algorithm, cryptoKey); 16 | let dec = decipher.update(text, 'hex', 'utf-8'); 17 | dec += decipher.final('utf-8'); 18 | return dec; 19 | }; 20 | 21 | module.exports = { 22 | encrypt, 23 | decrypt, 24 | }; 25 | -------------------------------------------------------------------------------- /server/src/utility/eventRescheduler.js: -------------------------------------------------------------------------------- 1 | const Event = require('../models/Event'); 2 | const User = require('../models/User'); 3 | const scheduler = require('./scheduler'); 4 | const path = require('path'); 5 | const ejs = require('ejs'); 6 | 7 | const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; 8 | 9 | const getNotificationDate = eventDate => { 10 | return new Date( 11 | parseInt(eventDate[3]), 12 | months.indexOf(eventDate[1]), 13 | parseInt(eventDate[2]), 14 | 3 15 | ); // Sends notification at 08:30 IST at the day of the event 16 | }; 17 | 18 | module.exports = { 19 | async reschedule() { 20 | console.log("Scheduling Events"); 21 | const events = await Event.find(); 22 | events.forEach(async event => { 23 | if (event.registeredUsers && event.registeredUsers.length !== 0) { 24 | event.registeredUsers.forEach(async uid => { 25 | const user = await User.findById(uid); 26 | const eventDate = event.date.split('-'); 27 | const notificationDate = getNotificationDate( 28 | eventDate[0].split(' ') 29 | ); 30 | const userEmail = user.email; 31 | const mailData = await ejs.renderFile(path.resolve(__dirname, '../views','eventReminder.ejs'), 32 | { event, user }); 33 | const data = { 34 | jobName: `${event._id}-${userEmail}`, 35 | to: userEmail, 36 | subject: `${event.eventName} Reminder!!`, 37 | message: mailData, 38 | }; 39 | scheduler.scheduleEmailNotification(notificationDate, data); 40 | }); 41 | } 42 | }); 43 | }, 44 | }; 45 | -------------------------------------------------------------------------------- /server/src/utility/extractPhotos.js: -------------------------------------------------------------------------------- 1 | const regex = /\["(https:\/\/lh3\.googleusercontent\.com\/[a-zA-Z0-9\-_]*)"/g 2 | 3 | function extractPhotos(content) { 4 | const links = new Set(); 5 | let match; 6 | while (match = regex.exec(content)) { 7 | links.add(match[1]) 8 | } 9 | return Array.from(links) 10 | } 11 | 12 | module.exports = extractPhotos; -------------------------------------------------------------------------------- /server/src/utility/getBaseURL.js: -------------------------------------------------------------------------------- 1 | module.exports = getBaseURL = () => { 2 | if (process.env.NODE_ENV === "production") 3 | return "https://communityofcoders.in" 4 | return "http://localhost:3000" 5 | } -------------------------------------------------------------------------------- /server/src/utility/getEncPassword.js: -------------------------------------------------------------------------------- 1 | /** 2 | * To get encrypted file execute this file using the command CRYPTOKEY=newSecretKey node getEncPassword 3 | * Also add the password to be encrypted in the string in the encrypt function 4 | */ 5 | 6 | const crypt = require('./crypt.js'); 7 | const encPassword = crypt.encrypt('' /** Enter password here to get encrypted password */); 8 | console.log(encPassword); 9 | console.log(crypt.decrypt(encPassword)); 10 | -------------------------------------------------------------------------------- /server/src/utility/getMailOptions.js: -------------------------------------------------------------------------------- 1 | module.exports = getMailOptions = (to, subject, message) => { 2 | return { 3 | from: { 4 | name: "Community Of Coders", 5 | address: 'coc@vjti.ac.in' 6 | }, 7 | to, 8 | subject, 9 | html: message, 10 | }; 11 | }; 12 | -------------------------------------------------------------------------------- /server/src/utility/insert.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | const project = require("../models/Project"); 3 | const domain = require("../models/Domain"); 4 | 5 | const genCheckArr = (obj, key, elem) => { 6 | if (Array.isArray(obj[key])) { 7 | if (!obj[key].includes(elem)) { 8 | obj[key].push(elem); 9 | } 10 | } else { 11 | obj[key] = [elem]; 12 | } 13 | } 14 | 15 | const insertDomains = async () => { 16 | await mongoose.connect(process.env.MONGO_URI); 17 | let projects = await project.find({}) 18 | for (let i = 0; i < projects.length; i++) { 19 | if (!Array.isArray(projects[i].domains)) { 20 | projects[i].domains = [projects[i].domains] 21 | } 22 | await projects[i].save(); 23 | } 24 | console.log("Done...") 25 | process.exit(0); 26 | } 27 | 28 | const insertProjects = async () => { 29 | await mongoose.connect(process.env.MONGO_URI); 30 | let projects = await project.find(); 31 | for (let i = 0; i < projects.length; i++) { 32 | for (let j = 0; j < projects[i].domains.length; j++) { 33 | let requiredDomain = await domain.findById(projects[i].domains[j]) 34 | genCheckArr(requiredDomain, "projects", projects[i]._id); 35 | await requiredDomain.save(); 36 | } 37 | } 38 | console.log("Done"); 39 | process.exit(0); 40 | }; -------------------------------------------------------------------------------- /server/src/utility/replaceDriveURL.js: -------------------------------------------------------------------------------- 1 | function replaceDriveURL(googleDriveURL) { 2 | return googleDriveURL.replace("/open?", "/uc?export=view&"); 3 | } 4 | 5 | module.exports = replaceDriveURL; 6 | -------------------------------------------------------------------------------- /server/src/utility/scheduler.js: -------------------------------------------------------------------------------- 1 | const schedule = require('node-schedule'); 2 | const sendEmail = require('./sendEmail'); 3 | 4 | const scheduleEmailNotification = (date, data) => { 5 | const { jobName, to, subject, message } = data; 6 | schedule.scheduleJob(jobName, date, () => { 7 | sendEmail(to, subject, message); 8 | }); 9 | }; 10 | 11 | const removeNotification = data => { 12 | const { substring } = data; 13 | for (const prop in schedule.scheduledJobs) { 14 | if (prop.includes(substring)) { 15 | schedule.scheduledJobs[prop].cancel(); 16 | } 17 | } 18 | }; 19 | 20 | const rescheduleNotification = (date, data) => { 21 | const { prefix } = data; 22 | for (const prop in schedule.scheduledJobs) { 23 | if (prop.toString().startsWith(prefix)) { 24 | schedule.scheduledJobs[prop].reschedule(date); 25 | } 26 | } 27 | }; 28 | 29 | const getNumberOfJobs = () => { 30 | return Object.keys(schedule.scheduledJobs).length; 31 | }; 32 | 33 | module.exports = { 34 | scheduleEmailNotification, 35 | removeNotification, 36 | rescheduleNotification, 37 | getNumberOfJobs, 38 | }; 39 | -------------------------------------------------------------------------------- /server/src/utility/sendEmail.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config(); 2 | const nodemailer = require('nodemailer'); 3 | const crypt = require('./crypt'); 4 | const getMailOptions = require('./getMailOptions'); 5 | 6 | const sendinbluePass = process.env.SENDINBLUE_PASS; 7 | 8 | const transport = nodemailer.createTransport({ 9 | host: 'smtp-relay.sendinblue.com', 10 | port: 587, 11 | secure: false, 12 | auth: { 13 | user: 'communityofcoders@gmail.com', 14 | pass: sendinbluePass, 15 | }, 16 | }); 17 | 18 | module.exports = sendMail = async (to, subject, message) => { 19 | const mailOptions = getMailOptions(to, subject, message); 20 | transport.sendMail(mailOptions, error => { 21 | if (error) { 22 | console.log(error); 23 | } 24 | }); 25 | }; 26 | -------------------------------------------------------------------------------- /server/src/views/emailVerification.ejs: -------------------------------------------------------------------------------- 1 | <%- include('partials/base') %> 2 | 3 | 14 |
15 | <%- include('partials/header') %> 16 | 17 |
18 |

Verify Email

19 |

Dear <%= username %>,

20 |
21 |

22 | We need to verify your email address: <%= email %> 23 |

24 | 25 |
26 | VERIFY EMAIL 40 |
41 |
42 | 43 |
44 | <%- include('partials/footer') %> 45 |

46 | If you are having trouble clicking the button, copy and paste 47 | the URL below in your browser 48 |

49 |

50 | <%= link %> 55 |

56 |
57 |
58 | 59 | 60 | -------------------------------------------------------------------------------- /server/src/views/eventReminder.ejs: -------------------------------------------------------------------------------- 1 | <%- include('partials/base') %> 2 | 3 | 14 |
15 | <%- include('partials/header') %> 16 | 17 |
18 |
19 |

Dear <%= user.username %>,

20 |

21 | This is a reminder mail! Following are the event details: 22 |

23 |
24 |

<%= event.eventName %>

25 | 26 | 27 | 33 | 36 | 37 | 38 | 46 | 47 |
28 | 32 | 34 |

Date: Today

35 |
39 |

40 | Location: 41 | <%= event.venue %> 44 |

45 |
48 |

About the Event

49 |

<%= event.description %>

50 | 51 |

52 | We will be waiting! 53 |

54 |
55 |
<%- include('partials/footer') %>
56 |
57 | 58 | 59 | -------------------------------------------------------------------------------- /server/src/views/eventRsvp.ejs: -------------------------------------------------------------------------------- 1 | <%- include('partials/base') %> 2 | 13 |
14 | <%- include('partials/header') %> 15 | 16 |
17 |
18 |

Dear <%= user.username %>,

19 |

20 | There's a new event published. Here are the details: 21 |

22 |
23 |

<%= event.eventName %>

24 | 25 | 26 | 32 | 38 | 39 | 40 | 48 | 49 | 50 | 58 | 59 |
27 | 31 | 33 |

34 | Date: 35 | <%= event.day %> 36 |

37 |
41 |

42 | Time: 43 | <%= event.time %> 46 |

47 |
51 |

52 | Location: 53 | <%= event.venue %> 56 |

57 |
60 |

About the Event

61 |

<%= event.description %>

62 | 63 |
67 | R.S.V.P 81 |
82 |

83 | Hope to see you there! 84 |

85 |
86 | 87 |
88 | <%- include('partials/footer') %> 89 | 90 |

91 | If you are having trouble clicking the button, copy and paste 92 | the URL below in your browser 93 |

94 |

95 | <%= link %> 100 |

101 |
102 |
103 | 104 | 105 | -------------------------------------------------------------------------------- /server/src/views/forgotPassword.ejs: -------------------------------------------------------------------------------- 1 | <%- include('partials/base') %> 2 | 3 | 14 |
15 | <%- include('partials/header') %> 16 | 17 |
18 |

Reset Password!

19 |

Dear <%= username %>,

20 |
21 |

22 | We have received a request to reset the password for your 23 | account. 24 |

25 |

26 | If you made this request, please click on the button below to 27 | complete the process. 28 |

29 |
30 |

31 | This link is valid only for an hour. 32 |

33 |
34 | RESET PASSWORD 48 |

49 | If you did not initiate this, you can safely ignore this 50 | mail. 51 |

52 |
53 |
54 | 55 |
56 | <%- include('partials/footer') %> 57 | 58 |

59 | If you are having trouble clicking the button, copy and paste 60 | the URL below in your browser 61 |

62 |

63 | <%= link %> 68 |

69 |
70 |
71 | 72 | 73 | -------------------------------------------------------------------------------- /server/src/views/partials/base.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 71 | 72 | -------------------------------------------------------------------------------- /server/src/views/partials/footer.ejs: -------------------------------------------------------------------------------- 1 |

2 | Regards,
Community Of 4 | Coders 5 | 6 |

7 |
8 | -------------------------------------------------------------------------------- /server/src/views/partials/header.ejs: -------------------------------------------------------------------------------- 1 |
8 | 14 |
15 | -------------------------------------------------------------------------------- /server/src/views/view.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs") 2 | const ejs = require("ejs"); 3 | const path = require("path"); 4 | 5 | /* 6 | Given a filename.ejs, the script outputs filename.html. Useful for debugging. 7 | Caveats: Objects need to be passed manually. 8 | Example runs on eventReminder.ejs 9 | */ 10 | (async (filename) => { 11 | const data = await ejs.renderFile(filename, { user: { username: "Shubhankar" }, event: {}, link: "" }); 12 | fs.writeFileSync(path.resolve(__dirname, `./${filename.split(".")[0]}.html`), data); 13 | })("eventReminder.ejs"); -------------------------------------------------------------------------------- /server/test/test_helper.js: -------------------------------------------------------------------------------- 1 | const config = require("../src/config"); 2 | const mongoose = require("mongoose"); 3 | const MongoMemoryServer = require("mongodb-memory-server").MongoMemoryServer; 4 | mongoose.Promise = global.Promise; 5 | 6 | const mongoOptions = { 7 | useCreateIndex: true, 8 | useNewUrlParser: true, 9 | useUnifiedTopology: true, 10 | useFindAndModify: false, 11 | }; 12 | 13 | before(async () => { 14 | config.env = "test"; 15 | mongoServer = new MongoMemoryServer(); 16 | const mongoUri = await mongoServer.getConnectionString(); 17 | await mongoose.connect(mongoUri, mongoOptions); 18 | console.log(`Mongo URI started on ${mongoUri}`); 19 | }); 20 | 21 | after(async () => { 22 | await mongoose.disconnect(); 23 | await mongoServer.stop(); 24 | console.log(`Mongo URI stopped`); 25 | }); 26 | -------------------------------------------------------------------------------- /server/uploads/010005318b2fe0c83f26d482b261d97f: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/server/uploads/010005318b2fe0c83f26d482b261d97f -------------------------------------------------------------------------------- /server/uploads/2815bb07c5ee99459487475e32ff5a8f: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/server/uploads/2815bb07c5ee99459487475e32ff5a8f -------------------------------------------------------------------------------- /server/uploads/51ca0e888fab2e8396370a0ac8ff1231: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/server/uploads/51ca0e888fab2e8396370a0ac8ff1231 -------------------------------------------------------------------------------- /server/uploads/7f91b0468cab55575d11fc94a31adf29: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/server/uploads/7f91b0468cab55575d11fc94a31adf29 -------------------------------------------------------------------------------- /server/uploads/8b20dcb16dce18c83488e6d1d3688e8e: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/server/uploads/8b20dcb16dce18c83488e6d1d3688e8e -------------------------------------------------------------------------------- /server/uploads/97122fcf6b9f76fdb164348974712e80: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/server/uploads/97122fcf6b9f76fdb164348974712e80 -------------------------------------------------------------------------------- /server/uploads/a3122a26109526aa384414dd4d7be8c6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/server/uploads/a3122a26109526aa384414dd4d7be8c6 -------------------------------------------------------------------------------- /server/uploads/a5e90613a602fbf9f9a84ebaee1451f1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/server/uploads/a5e90613a602fbf9f9a84ebaee1451f1 -------------------------------------------------------------------------------- /server/uploads/a62563021f1a907365fec1a7393c28dd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/server/uploads/a62563021f1a907365fec1a7393c28dd -------------------------------------------------------------------------------- /server/uploads/df08f0d1cf7bf29acc7aabcd1152af2e: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityOfCoders/COCWebsite/265ea683f75374a33120ad409128b6bd3f41cbbd/server/uploads/df08f0d1cf7bf29acc7aabcd1152af2e --------------------------------------------------------------------------------