├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── build.yml │ ├── deploy.yml │ └── eslint.yml ├── .gitignore ├── .vscode ├── extensions.json └── settings.json ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── RepoCover.png └── api ├── .env.example ├── .eslintignore ├── .eslintrc ├── .gitignore ├── .nvmrc ├── .prettierignore ├── .prettierrc ├── .vscode ├── extensions.json └── settings.json ├── Dockerfile ├── package.json ├── src ├── apollo │ ├── DeveloperInfo │ │ ├── index.ts │ │ ├── mutations.ts │ │ ├── queries.ts │ │ └── type.ts │ ├── Event │ │ ├── index.ts │ │ ├── mutations.ts │ │ ├── queries.ts │ │ └── type.ts │ ├── EventRegistration │ │ ├── index.ts │ │ ├── mutations.ts │ │ ├── queries.ts │ │ └── type.ts │ ├── Institute │ │ ├── index.ts │ │ ├── mutations.ts │ │ ├── queries.ts │ │ └── type.ts │ ├── Location │ │ ├── index.ts │ │ ├── mutations.ts │ │ ├── queries.ts │ │ └── type.ts │ ├── Org │ │ ├── index.ts │ │ ├── mutations.ts │ │ ├── queries.ts │ │ └── type.ts │ ├── Scalars │ │ ├── DateTime.ts │ │ ├── GenderType.ts │ │ ├── OrgType.ts │ │ ├── Pagination.ts │ │ ├── RepeatType.ts │ │ ├── StatusType.ts │ │ ├── TransactionType.ts │ │ └── index.ts │ ├── Story │ │ ├── index.ts │ │ ├── mutations.ts │ │ ├── queries.ts │ │ └── type.ts │ ├── Team │ │ ├── index.ts │ │ ├── mutations.ts │ │ ├── queries.ts │ │ └── type.ts │ ├── Transaction │ │ ├── index.ts │ │ ├── mutations.ts │ │ ├── queries.ts │ │ └── type.ts │ ├── User │ │ ├── index.ts │ │ ├── mutations.ts │ │ ├── queries.ts │ │ └── type.ts │ ├── index.ts │ └── server.ts ├── config │ ├── firebase.ts │ ├── index.ts │ ├── mongoose.ts │ ├── nexus.ts │ └── winston.ts ├── constants │ ├── auth.ts │ ├── env.ts │ └── index.ts ├── helpers │ ├── auth │ │ ├── checkPermisionLegacy.ts │ │ ├── checkPermissions.ts │ │ ├── index.ts │ │ └── verify.ts │ ├── errorClass │ │ ├── authError.ts │ │ └── index.ts │ └── index.ts ├── index.ts ├── prisma │ └── schema.prisma ├── rest │ ├── controller │ │ ├── auth │ │ │ ├── get.ts │ │ │ ├── index.ts │ │ │ └── update.ts │ │ ├── base │ │ │ ├── event.ts │ │ │ ├── health.ts │ │ │ ├── index.ts │ │ │ ├── transaction.ts │ │ │ ├── user.ts │ │ │ └── zimbra.ts │ │ ├── index.ts │ │ └── instamojo │ │ │ ├── index.ts │ │ │ ├── payment.ts │ │ │ └── webhook.ts │ ├── index.ts │ ├── model │ │ ├── index.ts │ │ └── permissions.ts │ ├── routes │ │ ├── auth.ts │ │ ├── health.ts │ │ ├── index.ts │ │ └── instamojo.ts │ └── server.ts ├── types │ ├── env.d.ts │ └── modules.d.ts └── utils │ ├── context.ts │ ├── getUnique.ts │ └── index.ts ├── tsconfig.eslint.json ├── tsconfig.json └── yarn.lock /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Your checklist for this pull request 2 | 🚨Please review the [guidelines for contributing](../CONTRIBUTING.md) to this repository. 3 | 4 | - [ ] Make sure you are requesting to **pull a topic/feature/bugfix branch** (right side). Don't request your default branch! 5 | - [ ] Make sure you are making a pull request against the **default branch** (left side). Also you should start *your branch* off *default branch*. 6 | - [ ] Check the commit's or even all commits' message styles matches our requested structure. 7 | - [ ] Check your code additions will fail neither code linting checks nor unit test. 8 | - [ ] I have added necessary documentation (if appropriate) 9 | 10 | ### Description 11 | Please describe your pull request. 12 | 13 | ❤️Thank you! 14 | 15 | ### Post merge checklist 16 | - [ ] Follow steps from the [guidelines for contributing](../CONTRIBUTING.md) to this repository. 17 | - [ ] If you are a new contributor, ping in the thread and one of the maintainers will add you to all-contributors list. 18 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Docker Image CI 2 | 3 | on: 4 | workflow_call: 5 | secrets: 6 | PERSONAL_TOKEN: 7 | required: true 8 | USERNAME: 9 | required: true 10 | 11 | jobs: 12 | build-and-push: 13 | name: Build Docker Image 14 | runs-on: ubuntu-latest 15 | defaults: 16 | run: 17 | shell: bash 18 | working-directory: api 19 | steps: 20 | - uses: actions/checkout@v2 21 | - name: Setup Docker buildx 22 | uses: docker/setup-buildx-action@v1 23 | 24 | - name: Login to GitHub Container Registry 25 | uses: docker/login-action@v1 26 | with: 27 | registry: ghcr.io 28 | username: ${{ secrets.USERNAME }} 29 | password: ${{ secrets.PERSONAL_TOKEN }} 30 | - name: Build and push 31 | uses: docker/build-push-action@v2 32 | with: 33 | context: api/ 34 | push: true 35 | tags: | 36 | ghcr.io/${{ github.repository }}:latest 37 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy to VM 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | env: 7 | PORT: ${{ secrets.PORT }} 8 | MONGO_AUTH_DB: ${{ secrets.MONGO_AUTH_DB }} 9 | DATABASE_URL: ${{ secrets.DATABASE_URL }} 10 | PROJECT_ID: ${{ secrets.PROJECT_ID }} 11 | PRIVATE_KEY_ID: ${{ secrets.PRIVATE_KEY_ID }} 12 | PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }} 13 | CLIENT_EMAIL: ${{ secrets.CLIENT_EMAIL }} 14 | CLIENT_ID: ${{ secrets.CLIENT_ID }} 15 | AUTH_URI: ${{ secrets.AUTH_URI }} 16 | TOKEN_URI: ${{ secrets.TOKEN_URI }} 17 | AUTH_PROVIDER: ${{ secrets.AUTH_PROVIDER }} 18 | CERT_URL: ${{ secrets.CERT_URL }} 19 | INSTAMOJO_CLIENT_ID: ${{ secrets.INSTAMOJO_CLIENT_ID }} 20 | INSTAMOJO_CLIENT_SECRET: ${{ secrets.INSTAMOJO_CLIENT_SECRET }} 21 | INSTAMOJO_BASE_URL: ${{ secrets.INSTAMOJO_BASE_URL }} 22 | ALLOWED_CLIENT_URL: ${{ secrets.ALLOWED_CLIENT_URL }} 23 | 24 | jobs: 25 | # build: 26 | # uses: dscnitrourkela/project-dates/.github/workflows/build.yml@main 27 | # secrets: 28 | # USERNAME: ${{ secrets.USERNAME }} 29 | # PERSONAL_TOKEN: ${{ secrets.PERSONAL_TOKEN }} 30 | 31 | deploy: 32 | runs-on: [self-hosted, dsc-main] 33 | defaults: 34 | run: 35 | shell: bash 36 | working-directory: api 37 | strategy: 38 | matrix: 39 | node-version: [16.x] 40 | # needs: build 41 | steps: 42 | # - name: Remove existing env 43 | # run: rm .env || true 44 | - uses: actions/checkout@v2 45 | - name: Deploy Server 46 | uses: actions/setup-node@v2 47 | with: 48 | node-version: ${{ matrix.node-version }} 49 | - name: Create Env 50 | run: | 51 | touch .env 52 | echo PORT=$PORT >> .env 53 | echo DATABASE_URL=$DATABASE_URL >> .env 54 | echo MONGO_AUTH_DB=$MONGO_AUTH_DB >> .env 55 | echo PROJECT_ID=$PROJECT_ID >> .env 56 | echo PRIVATE_KEY_ID=$PRIVATE_KEY_ID >> .env 57 | echo PRIVATE_KEY=$PRIVATE_KEY >> .env 58 | echo CLIENT_EMAIL=$CLIENT_EMAIL >> .env 59 | echo CLIENT_ID=$CLIENT_ID >> .env 60 | echo AUTH_URI=$AUTH_URI >> .env 61 | echo TOKEN_URI=$TOKEN_URI >> .env 62 | echo AUTH_PROVIDER=$AUTH_PROVIDER >> .env 63 | echo CERT_URL=$CERT_URL >> .env 64 | echo INSTAMOJO_CLIENT_ID=$INSTAMOJO_CLIENT_ID >> .env 65 | echo INSTAMOJO_CLIENT_SECRET=$INSTAMOJO_CLIENT_SECRET >> .env 66 | echo INSTAMOJO_BASE_URL=$INSTAMOJO_BASE_URL >> .env 67 | echo ALLOWED_CLIENT_URL=$ALLOWED_CLIENT_URL >> .env 68 | # - name: Pull Docker Image 69 | # run: docker pull ghcr.io/${{ github.repository }}:latest 70 | - name: Build Docker Image 71 | run: docker build -t ghcr.io/${{ github.repository }}:latest . 72 | - name: Stop existing container 73 | run: docker stop project-dates || true 74 | - name: Remove stopped container 75 | run: docker rm project-dates || true 76 | - name: Start container 77 | run: docker run --name=project-dates --env-file=.env -p $PORT:$PORT -d ghcr.io/${{ github.repository }}:latest 78 | - name: Remove Unused Images 79 | run: docker image prune -f 80 | -------------------------------------------------------------------------------- /.github/workflows/eslint.yml: -------------------------------------------------------------------------------- 1 | name: reviewdog 2 | 3 | on: 4 | pull_request_target: 5 | types: [labeled] 6 | 7 | jobs: 8 | eslint: 9 | name: runner / eslint 10 | runs-on: ubuntu-latest 11 | timeout-minutes: 5 12 | if: contains(github.event.pull_request.labels.*.name, 'lint-check') 13 | defaults: 14 | run: 15 | shell: bash 16 | working-directory: api 17 | steps: 18 | - uses: actions/checkout@v2 19 | name: Clone code 20 | - uses: actions/cache@v2 21 | name: Cache 22 | id: cache-mods 23 | with: 24 | path: | 25 | **/node_modules 26 | key: cache-${{ runner.os }}-linter-${{ hashFiles('**/yarn.lock') }} 27 | - name: Install NPM Packages 28 | run: | 29 | yarn install 30 | - name: Lint Source Code 31 | uses: reviewdog/action-eslint@v1 32 | with: 33 | reporter: github-pr-review # Change reporter. 34 | eslint_flags: "src/ --ext .ts" 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.toptal.com/developers/gitignore/api/node,yarn 2 | # Edit at https://www.toptal.com/developers/gitignore?templates=node,yarn 3 | 4 | ### Node ### 5 | .DS_Store 6 | # Logs 7 | logs 8 | *.log 9 | npm-debug.log* 10 | yarn-debug.log* 11 | yarn-error.log* 12 | lerna-debug.log* 13 | .pnpm-debug.log* 14 | 15 | # Diagnostic reports (https://nodejs.org/api/report.html) 16 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 17 | 18 | # Runtime data 19 | pids 20 | *.pid 21 | *.seed 22 | *.pid.lock 23 | 24 | # Directory for instrumented libs generated by jscoverage/JSCover 25 | lib-cov 26 | 27 | # Coverage directory used by tools like istanbul 28 | coverage 29 | *.lcov 30 | 31 | # nyc test coverage 32 | .nyc_output 33 | 34 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 35 | .grunt 36 | 37 | # Bower dependency directory (https://bower.io/) 38 | bower_components 39 | 40 | # node-waf configuration 41 | .lock-wscript 42 | 43 | # Compiled binary addons (https://nodejs.org/api/addons.html) 44 | build/Release 45 | 46 | # Dependency directories 47 | node_modules/ 48 | jspm_packages/ 49 | 50 | # Snowpack dependency directory (https://snowpack.dev/) 51 | web_modules/ 52 | 53 | # TypeScript cache 54 | *.tsbuildinfo 55 | 56 | # Optional npm cache directory 57 | .npm 58 | 59 | # Optional eslint cache 60 | .eslintcache 61 | 62 | # Optional stylelint cache 63 | .stylelintcache 64 | 65 | # Microbundle cache 66 | .rpt2_cache/ 67 | .rts2_cache_cjs/ 68 | .rts2_cache_es/ 69 | .rts2_cache_umd/ 70 | 71 | # Optional REPL history 72 | .node_repl_history 73 | 74 | # Output of 'npm pack' 75 | *.tgz 76 | 77 | # Yarn Integrity file 78 | .yarn-integrity 79 | 80 | # dotenv environment variable files 81 | .env 82 | .env.development.local 83 | .env.test.local 84 | .env.production.local 85 | .env.local 86 | 87 | # parcel-bundler cache (https://parceljs.org/) 88 | .cache 89 | .parcel-cache 90 | 91 | # Next.js build output 92 | .next 93 | out 94 | 95 | # Nuxt.js build / generate output 96 | .nuxt 97 | dist 98 | 99 | # Gatsby files 100 | .cache/ 101 | # Comment in the public line in if your project uses Gatsby and not Next.js 102 | # https://nextjs.org/blog/next-9-1#public-directory-support 103 | # public 104 | 105 | # vuepress build output 106 | .vuepress/dist 107 | 108 | # vuepress v2.x temp and cache directory 109 | .temp 110 | 111 | # Docusaurus cache and generated files 112 | .docusaurus 113 | 114 | # Serverless directories 115 | .serverless/ 116 | 117 | # FuseBox cache 118 | .fusebox/ 119 | 120 | # DynamoDB Local files 121 | .dynamodb/ 122 | 123 | # TernJS port file 124 | .tern-port 125 | 126 | # Stores VSCode versions used for testing VSCode extensions 127 | .vscode-test 128 | 129 | # yarn v2 130 | .yarn/cache 131 | .yarn/unplugged 132 | .yarn/build-state.yml 133 | .yarn/install-state.gz 134 | .pnp.* 135 | 136 | ### Node Patch ### 137 | # Serverless Webpack directories 138 | .webpack/ 139 | 140 | # Optional stylelint cache 141 | 142 | # SvelteKit build / generate output 143 | .svelte-kit 144 | 145 | ### yarn ### 146 | # https://yarnpkg.com/getting-started/qa#which-files-should-be-gitignored 147 | 148 | .yarn/* 149 | !.yarn/releases 150 | !.yarn/patches 151 | !.yarn/plugins 152 | !.yarn/sdks 153 | !.yarn/versions 154 | 155 | # if you are NOT using Zero-installs, then: 156 | # comment the following lines 157 | !.yarn/cache 158 | 159 | # and uncomment the following lines 160 | # .pnp.* 161 | 162 | # End of https://www.toptal.com/developers/gitignore/api/node,yarn -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "dbaeumer.vscode-eslint", 4 | "esbenp.prettier-vscode", 5 | "formulahendry.auto-rename-tag", 6 | "mgmcdermott.vscode-language-babel", 7 | "eg2.vscode-npm-script", 8 | "visualstudioexptteam.vscodeintellicode", 9 | "graphql.vscode-graphql", 10 | "dozerg.tsimportsorter" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.defaultFormatter": "esbenp.prettier-vscode", 3 | "editor.formatOnSave": true, 4 | "editor.detectIndentation": true, 5 | "editor.snippetSuggestions": "top", 6 | "editor.wordBasedSuggestions": "off", 7 | "editor.suggest.localityBonus": true, 8 | "editor.acceptSuggestionOnCommitCharacter": false, 9 | "[javascript]": { 10 | "editor.defaultFormatter": "esbenp.prettier-vscode", 11 | "editor.suggestSelection": "recentlyUsed", 12 | "editor.suggest.showKeywords": false 13 | }, 14 | "[json]": { 15 | "editor.defaultFormatter": "esbenp.prettier-vscode" 16 | }, 17 | "editor.renderWhitespace": "boundary", 18 | "files.defaultLanguage": "{activeEditorLanguage}", 19 | "javascript.validate.enable": false, 20 | "search.exclude": { 21 | "**/node_modules": true, 22 | "**/bower_components": true, 23 | "**/coverage": true, 24 | "**/dist": true, 25 | "**/build": true, 26 | "**/.build": true, 27 | "**/.gh-pages": true 28 | }, 29 | "editor.codeActionsOnSave": { 30 | "source.fixAll.eslint": "never" 31 | }, 32 | "eslint.validate": ["javascript", "javascriptreact"], 33 | "npm.runSilent": false, 34 | "explorer.confirmDragAndDrop": false, 35 | "editor.formatOnPaste": false, 36 | "editor.cursorSmoothCaretAnimation": "off", 37 | "editor.smoothScrolling": false 38 | } 39 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at team@dscnitrourkela.org. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | When contributing to this repository, please first discuss the change you wish to make via issue with the maintainers of this repository before making a change. 4 | 5 | Please note we have a code of conduct, please follow it in all your interactions with the project. 6 | 7 | ## Pull Request Process 8 | 9 | 1. Ensure any install or build dependencies are removed before the end of the layer when doing a 10 | build. Add only relevant files to commit and ignore the rest to keep the repo clean. 11 | 2. Update the README.md with details of changes to the interface, this includes new environment 12 | variables, exposed ports, useful file locations and container parameters. 13 | 3. You should request review from the maintainers once you submit the Pull Request. 14 | 15 | ## Instructions 16 | 17 | - Git Workflow 18 | 19 | ```bash 20 | ## Step 1: Fork Repository 21 | 22 | ## Step 2: Git Set Up & Download 23 | # Clone the repo 24 | $ git clone https://github.com//.git 25 | # Add upstream remote 26 | $ git remote add upstream https://github.com/dscnitrourkela/project-dates.git 27 | # Fetch and merge with upstream/development 28 | $ git fetch upstream 29 | $ git merge upstream/development 30 | 31 | ## Step 2: Create and Publish Working Branch 32 | $ git checkout -b //{} 33 | $ git push origin //{} 34 | 35 | ## Types: 36 | # wip - Work in Progress; long term work; mainstream changes; 37 | # feat - New Feature; future planned; non-mainstream changes; 38 | # bug - Bug Fixes 39 | # exp - Experimental; random experiemntal features; 40 | ``` 41 | 42 | - On Task Completion: 43 | 44 | ```bash 45 | ## Committing and pushing your work 46 | # Ensure branch 47 | $ git branch 48 | # Fetch and merge with upstream/development 49 | $ git fetch upstream 50 | $ git merge upstream/development 51 | # Add untracked files 52 | $ git add . 53 | # Commit all changes with appropriate commit message and description 54 | $ git commit -m "your-commit-message" -m "your-commit-description" 55 | # Fetch and merge with upstream/development again 56 | $ git fetch upstream 57 | $ git merge upstream/development 58 | # Push changes to your forked repository 59 | $ git push origin //{} 60 | 61 | ## Creating the PR using GitHub Website 62 | # Create Pull Request from //{} branch in your forked repository to the development branch in the upstream repository 63 | # After creating PR, add a Reviewer (Any Admin) and yourself as the assignee 64 | # Link Pull Request to appropriate Issue, or Project+Milestone (if no issue created) 65 | # IMPORTANT: Do Not Merge the PR unless specifically asked to by an admin. 66 | ``` 67 | 68 | - After PR Merge 69 | 70 | ```bash 71 | # Delete branch from forked repo 72 | $ git branch -d //{} 73 | $ git push --delete origin //{} 74 | # Fetch and merge with upstream/development 75 | $ git checkout development 76 | $ git pull upstream 77 | $ git push origin 78 | ``` 79 | 80 | - Always follow [commit message standards](https://chris.beams.io/posts/git-commit/) 81 | - About the [fork-and-branch workflow](https://blog.scottlowe.org/2015/01/27/using-fork-branch-git-workflow/) 82 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 DSC NIT Rourkela 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | [![All Contributors](https://img.shields.io/badge/all_contributors-4-orange.svg?style=flat-square)](#contributors-) 4 | 5 | 6 | 7 | [![Starware](https://img.shields.io/badge/Starware-⭐-black?labelColor=f9b00d)](https://github.com/zepfietje/starware) 8 | 9 | 10 | 11 |

12 | Logo 13 |

14 |

Project Dates

15 | 16 | [![Forks][forks-shield]][forks-url] 17 | [![Stargazers][stars-shield]][stars-url] 18 | [![Issues][issues-shield]][issues-url] 19 | [![MIT License][license-shield]][license-url] 20 | 21 | ## About 22 | 23 | **This is the backend repository for campus guide at NIT Rourkela. It is a respository managing the API for managinng, controlling and authorising the users with respect to the mobile application of Avenue.** 24 | 25 |

26 | 27 |

28 |
Project developed and maintained by DSC NIT Rourkela
29 | 30 | ## Tech Stack 31 | 32 | This project uses the following technologies : 33 | 34 | --- 35 | 36 | ## Local Setup 37 | 38 | This section contains the procedure to setup the project on your local machine. 39 | 40 | `PREREQUISITE INSTALLATIONS` 41 | 42 | > 1. Docker 43 | > 2. Docker Compose 44 | 45 | > Node.js required only for linting locally 46 | 47 | 1. **Fork** the repo on GitHub 48 | 2. **Clone** the project to your own machine 49 | 3. Prepare the env for project. 50 | 51 | `cd api && mv .env.example .env` 52 | 53 | 4. Add Mongo DB URI in `.env` file 54 | 5. Build the docker image 55 | 56 | `docker-compose build --no-cache` 57 | 58 | 6. Spin the server. 59 | 60 | `docker-compose up` 61 | 62 | --- 63 | 64 | ## Documentation Notes 65 | 66 | This section contains a quick guide about the features of the application. 67 | 68 | --- 69 | 70 | ## Contributing 🎃 71 | 72 | This repository is one of the many repositories maintained by DSC NIT Rourkela NIT Rourkela.
73 | Our Slack Community: [Slack Invite](http://bit.ly/NITRDevs)
74 | 75 | Please refer to the project's style and contribution guidelines for submitting patches and additions. In general, we follow the "fork-and-pull" Git workflow. 76 | 77 | NOTE 1: Please abide by the [Contributing Guidelines](https://github.com/dscnitrourkela/project-dates/blob/development/CONTRIBUTING.md). 78 | 79 | NOTE 2: Please abide by the [Code of Conduct](https://github.com/dscnitrourkela/project-dates/blob/development/CODE_OF_CONDUCT.md). 80 | 81 | ## Starware 82 | 83 | `dscnitrourkela/project-dates` is Starware. 84 | This means you're free to use the project, as long as you star its GitHub repository. 85 | Your appreciation makes us grow and glow up. 🌠 86 | 87 | ## Contributors ✨ 88 | 89 | Thanks goes to these wonderful people. Check out the roles [here](https://allcontributors.org/docs/en/emoji-key): 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 |

Roshan Kumar Shaw

💻 📆 👀

Harish

💻 📆 👀

Abel Mathew

💻 📆

All Contributors

🔧
102 | 103 | 104 | 105 | 106 | 107 | 108 | This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! 109 | 110 | [contributors-shield]: https://img.shields.io/github/contributors/dscnitrourkela/project-dates?style=for-the-badge 111 | [contributors-url]: https://github.com/dscnitrourkela/project-dates/graphs/contributors 112 | [forks-shield]: https://img.shields.io/github/forks/dscnitrourkela/project-dates?style=for-the-badge 113 | [forks-url]: https://github.com/dscnitrourkela/project-dates/network/members 114 | [stars-shield]: https://img.shields.io/github/stars/dscnitrourkela/project-dates?style=for-the-badge 115 | [stars-url]: https://github.com/dscnitrourkela/project-dates/stargazers 116 | [issues-shield]: https://img.shields.io/github/issues/dscnitrourkela/project-dates?style=for-the-badge 117 | [issues-url]: https://github.com/dscnitrourkela/project-dates/issues 118 | [license-shield]: https://img.shields.io/github/license/dscnitrourkela/project-dates?style=for-the-badge 119 | [license-url]: https://github.com/dscnitrourkela/project-dates/blob/main/LICENSE 120 | -------------------------------------------------------------------------------- /RepoCover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dscnitrourkela/project-dates/9bd0a3901eff1c60bf6a23a3dc35b6cff92d62d7/RepoCover.png -------------------------------------------------------------------------------- /api/.env.example: -------------------------------------------------------------------------------- 1 | PORT=8000 2 | DATABASE_URL= 3 | MONGO_AUTH_DB= 4 | PROJECT_ID= 5 | PRIVATE_KEY_ID= 6 | PRIVATE_KEY= 7 | CLIENT_EMAIL= 8 | CLIENT_ID= 9 | AUTH_URI= 10 | TOKEN_URI= 11 | AUTH_PROVIDER= 12 | CERT_URL= 13 | INSTAMOJO_CLIENT_ID= 14 | INSTAMOJO_CLIENT_SECRET= 15 | INSTAMOJO_BASE_URL= 16 | ALLOWED_CLIENT_URL=[] -------------------------------------------------------------------------------- /api/.eslintignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.toptal.com/developers/gitignore/api/node,yarn 2 | # Edit at https://www.toptal.com/developers/gitignore?templates=node,yarn 3 | 4 | ### Node ### 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | yarn-debug.log* 10 | yarn-error.log* 11 | lerna-debug.log* 12 | .pnpm-debug.log* 13 | 14 | # Diagnostic reports (https://nodejs.org/api/report.html) 15 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 16 | 17 | # Runtime data 18 | pids 19 | *.pid 20 | *.seed 21 | *.pid.lock 22 | 23 | # Directory for instrumented libs generated by jscoverage/JSCover 24 | lib-cov 25 | 26 | # Coverage directory used by tools like istanbul 27 | coverage 28 | *.lcov 29 | 30 | # nyc test coverage 31 | .nyc_output 32 | 33 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 34 | .grunt 35 | 36 | # Bower dependency directory (https://bower.io/) 37 | bower_components 38 | 39 | # node-waf configuration 40 | .lock-wscript 41 | 42 | # Compiled binary addons (https://nodejs.org/api/addons.html) 43 | build/Release 44 | 45 | # Dependency directories 46 | node_modules/ 47 | jspm_packages/ 48 | 49 | # Snowpack dependency directory (https://snowpack.dev/) 50 | web_modules/ 51 | 52 | # TypeScript cache 53 | *.tsbuildinfo 54 | 55 | # Optional npm cache directory 56 | .npm 57 | 58 | # Optional eslint cache 59 | .eslintcache 60 | 61 | # Optional stylelint cache 62 | .stylelintcache 63 | 64 | # Microbundle cache 65 | .rpt2_cache/ 66 | .rts2_cache_cjs/ 67 | .rts2_cache_es/ 68 | .rts2_cache_umd/ 69 | 70 | # Optional REPL history 71 | .node_repl_history 72 | 73 | # Output of 'npm pack' 74 | *.tgz 75 | 76 | # Yarn Integrity file 77 | .yarn-integrity 78 | 79 | # dotenv environment variable files 80 | .env 81 | .env.development.local 82 | .env.test.local 83 | .env.production.local 84 | .env.local 85 | 86 | # parcel-bundler cache (https://parceljs.org/) 87 | .cache 88 | .parcel-cache 89 | 90 | # Next.js build output 91 | .next 92 | out 93 | 94 | # Nuxt.js build / generate output 95 | .nuxt 96 | dist 97 | 98 | # Gatsby files 99 | .cache/ 100 | # Comment in the public line in if your project uses Gatsby and not Next.js 101 | # https://nextjs.org/blog/next-9-1#public-directory-support 102 | # public 103 | 104 | # vuepress build output 105 | .vuepress/dist 106 | 107 | # vuepress v2.x temp and cache directory 108 | .temp 109 | 110 | # Docusaurus cache and generated files 111 | .docusaurus 112 | 113 | # Serverless directories 114 | .serverless/ 115 | 116 | # FuseBox cache 117 | .fusebox/ 118 | 119 | # DynamoDB Local files 120 | .dynamodb/ 121 | 122 | # TernJS port file 123 | .tern-port 124 | 125 | # Stores VSCode versions used for testing VSCode extensions 126 | .vscode-test 127 | 128 | # yarn v2 129 | .yarn/cache 130 | .yarn/unplugged 131 | .yarn/build-state.yml 132 | .yarn/install-state.gz 133 | .pnp.* 134 | 135 | ### Node Patch ### 136 | # Serverless Webpack directories 137 | .webpack/ 138 | 139 | # Optional stylelint cache 140 | 141 | # SvelteKit build / generate output 142 | .svelte-kit 143 | 144 | ### yarn ### 145 | # https://yarnpkg.com/getting-started/qa#which-files-should-be-gitignored 146 | 147 | .yarn/* 148 | !.yarn/releases 149 | !.yarn/patches 150 | !.yarn/plugins 151 | !.yarn/sdks 152 | !.yarn/versions 153 | 154 | # if you are NOT using Zero-installs, then: 155 | # comment the following lines 156 | !.yarn/cache 157 | 158 | # and uncomment the following lines 159 | # .pnp.* 160 | 161 | # End of https://www.toptal.com/developers/gitignore/api/node,yarn -------------------------------------------------------------------------------- /api/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "extends": [ 4 | "airbnb-base", 5 | "eslint:recommended", 6 | "plugin:@typescript-eslint/recommended", 7 | "prettier" 8 | ], 9 | "plugins": ["import", "@typescript-eslint", "prettier"], 10 | "env": { 11 | "browser": true, 12 | "jest": true, 13 | "node": true, 14 | "es6": true 15 | }, 16 | "globals": { 17 | "Atomics": "readonly", 18 | "SharedArrayBuffer": "readonly" 19 | }, 20 | "settings": { 21 | "import/parsers": { 22 | "@typescript-eslint/parser": [".ts", ".tsx"] 23 | }, 24 | "import/resolver": { 25 | "typescript": { 26 | "alwaysTryTypes": true 27 | }, 28 | "node": { 29 | "extensions": [".js", ".jsx", ".ts", ".tsx", ".d.ts"] 30 | } 31 | }, 32 | "node": { 33 | "allowModules": [], 34 | "resolvePaths": ["./src"], 35 | "tryExtensions": [".js", ".json", ".ts", ".d.ts"] 36 | } 37 | }, 38 | "parser": "@typescript-eslint/parser", 39 | "parserOptions": { 40 | "ecmaVersion": 2020, 41 | "sourceType": "module", 42 | "project": "./tsconfig.eslint.json" 43 | }, 44 | "rules": { 45 | "node/no-unsupported-features/es-syntax": 0, 46 | "import/extensions": 0, 47 | "import/no-extraneous-dependencies": 0, 48 | "node/no-extraneous-import": 0, 49 | "class-methods-use-this": 0, 50 | "max-classes-per-file": 0, 51 | "import/no-unresolved": "error", 52 | "import/prefer-default-export": 0, 53 | "@typescript-eslint/no-empty-interface": 0 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /api/.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.toptal.com/developers/gitignore/api/node,yarn 2 | # Edit at https://www.toptal.com/developers/gitignore?templates=node,yarn 3 | 4 | ### Node ### 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | yarn-debug.log* 10 | yarn-error.log* 11 | lerna-debug.log* 12 | .pnpm-debug.log* 13 | 14 | # Diagnostic reports (https://nodejs.org/api/report.html) 15 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 16 | 17 | # Runtime data 18 | pids 19 | *.pid 20 | *.seed 21 | *.pid.lock 22 | 23 | # Directory for instrumented libs generated by jscoverage/JSCover 24 | lib-cov 25 | 26 | # Coverage directory used by tools like istanbul 27 | coverage 28 | *.lcov 29 | 30 | # nyc test coverage 31 | .nyc_output 32 | 33 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 34 | .grunt 35 | 36 | # Bower dependency directory (https://bower.io/) 37 | bower_components 38 | 39 | # node-waf configuration 40 | .lock-wscript 41 | 42 | # Compiled binary addons (https://nodejs.org/api/addons.html) 43 | build/Release 44 | 45 | # Dependency directories 46 | node_modules/ 47 | jspm_packages/ 48 | 49 | # Snowpack dependency directory (https://snowpack.dev/) 50 | web_modules/ 51 | 52 | # TypeScript cache 53 | *.tsbuildinfo 54 | 55 | # Optional npm cache directory 56 | .npm 57 | 58 | # Optional eslint cache 59 | .eslintcache 60 | 61 | # Optional stylelint cache 62 | .stylelintcache 63 | 64 | # Microbundle cache 65 | .rpt2_cache/ 66 | .rts2_cache_cjs/ 67 | .rts2_cache_es/ 68 | .rts2_cache_umd/ 69 | 70 | # Optional REPL history 71 | .node_repl_history 72 | 73 | # Output of 'npm pack' 74 | *.tgz 75 | 76 | # Yarn Integrity file 77 | .yarn-integrity 78 | 79 | # dotenv environment variable files 80 | .env 81 | .env.development.local 82 | .env.test.local 83 | .env.production.local 84 | .env.local 85 | 86 | # parcel-bundler cache (https://parceljs.org/) 87 | .cache 88 | .parcel-cache 89 | 90 | # Next.js build output 91 | .next 92 | out 93 | 94 | # Nuxt.js build / generate output 95 | .nuxt 96 | dist 97 | 98 | # Gatsby files 99 | .cache/ 100 | # Comment in the public line in if your project uses Gatsby and not Next.js 101 | # https://nextjs.org/blog/next-9-1#public-directory-support 102 | # public 103 | 104 | # vuepress build output 105 | .vuepress/dist 106 | 107 | # vuepress v2.x temp and cache directory 108 | .temp 109 | 110 | # Docusaurus cache and generated files 111 | .docusaurus 112 | 113 | # Serverless directories 114 | .serverless/ 115 | 116 | # FuseBox cache 117 | .fusebox/ 118 | 119 | # DynamoDB Local files 120 | .dynamodb/ 121 | 122 | # TernJS port file 123 | .tern-port 124 | 125 | # Stores VSCode versions used for testing VSCode extensions 126 | .vscode-test 127 | 128 | # yarn v2 129 | .yarn/cache 130 | .yarn/unplugged 131 | .yarn/build-state.yml 132 | .yarn/install-state.gz 133 | .pnp.* 134 | 135 | ### Node Patch ### 136 | # Serverless Webpack directories 137 | .webpack/ 138 | 139 | # Optional stylelint cache 140 | 141 | # SvelteKit build / generate output 142 | .svelte-kit 143 | 144 | ### yarn ### 145 | # https://yarnpkg.com/getting-started/qa#which-files-should-be-gitignored 146 | 147 | .yarn/* 148 | !.yarn/releases 149 | !.yarn/patches 150 | !.yarn/plugins 151 | !.yarn/sdks 152 | !.yarn/versions 153 | 154 | # if you are NOT using Zero-installs, then: 155 | # comment the following lines 156 | !.yarn/cache 157 | 158 | # and uncomment the following lines 159 | # .pnp.* 160 | 161 | # End of https://www.toptal.com/developers/gitignore/api/node,yarn 162 | 163 | node_modules 164 | nexus_generated 165 | firebase.json -------------------------------------------------------------------------------- /api/.nvmrc: -------------------------------------------------------------------------------- 1 | lts/gallium 2 | -------------------------------------------------------------------------------- /api/.prettierignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.toptal.com/developers/gitignore/api/node,yarn 2 | # Edit at https://www.toptal.com/developers/gitignore?templates=node,yarn 3 | 4 | ### Node ### 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | yarn-debug.log* 10 | yarn-error.log* 11 | lerna-debug.log* 12 | .pnpm-debug.log* 13 | 14 | # Diagnostic reports (https://nodejs.org/api/report.html) 15 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 16 | 17 | # Runtime data 18 | pids 19 | *.pid 20 | *.seed 21 | *.pid.lock 22 | 23 | # Directory for instrumented libs generated by jscoverage/JSCover 24 | lib-cov 25 | 26 | # Coverage directory used by tools like istanbul 27 | coverage 28 | *.lcov 29 | 30 | # nyc test coverage 31 | .nyc_output 32 | 33 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 34 | .grunt 35 | 36 | # Bower dependency directory (https://bower.io/) 37 | bower_components 38 | 39 | # node-waf configuration 40 | .lock-wscript 41 | 42 | # Compiled binary addons (https://nodejs.org/api/addons.html) 43 | build/Release 44 | 45 | # Dependency directories 46 | node_modules/ 47 | jspm_packages/ 48 | 49 | # Snowpack dependency directory (https://snowpack.dev/) 50 | web_modules/ 51 | 52 | # TypeScript cache 53 | *.tsbuildinfo 54 | 55 | # Optional npm cache directory 56 | .npm 57 | 58 | # Optional eslint cache 59 | .eslintcache 60 | 61 | # Optional stylelint cache 62 | .stylelintcache 63 | 64 | # Microbundle cache 65 | .rpt2_cache/ 66 | .rts2_cache_cjs/ 67 | .rts2_cache_es/ 68 | .rts2_cache_umd/ 69 | 70 | # Optional REPL history 71 | .node_repl_history 72 | 73 | # Output of 'npm pack' 74 | *.tgz 75 | 76 | # Yarn Integrity file 77 | .yarn-integrity 78 | 79 | # dotenv environment variable files 80 | .env 81 | .env.development.local 82 | .env.test.local 83 | .env.production.local 84 | .env.local 85 | 86 | # parcel-bundler cache (https://parceljs.org/) 87 | .cache 88 | .parcel-cache 89 | 90 | # Next.js build output 91 | .next 92 | out 93 | 94 | # Nuxt.js build / generate output 95 | .nuxt 96 | dist 97 | 98 | # Gatsby files 99 | .cache/ 100 | # Comment in the public line in if your project uses Gatsby and not Next.js 101 | # https://nextjs.org/blog/next-9-1#public-directory-support 102 | # public 103 | 104 | # vuepress build output 105 | .vuepress/dist 106 | 107 | # vuepress v2.x temp and cache directory 108 | .temp 109 | 110 | # Docusaurus cache and generated files 111 | .docusaurus 112 | 113 | # Serverless directories 114 | .serverless/ 115 | 116 | # FuseBox cache 117 | .fusebox/ 118 | 119 | # DynamoDB Local files 120 | .dynamodb/ 121 | 122 | # TernJS port file 123 | .tern-port 124 | 125 | # Stores VSCode versions used for testing VSCode extensions 126 | .vscode-test 127 | 128 | # yarn v2 129 | .yarn/cache 130 | .yarn/unplugged 131 | .yarn/build-state.yml 132 | .yarn/install-state.gz 133 | .pnp.* 134 | 135 | ### Node Patch ### 136 | # Serverless Webpack directories 137 | .webpack/ 138 | 139 | # Optional stylelint cache 140 | 141 | # SvelteKit build / generate output 142 | .svelte-kit 143 | 144 | ### yarn ### 145 | # https://yarnpkg.com/getting-started/qa#which-files-should-be-gitignored 146 | 147 | .yarn/* 148 | !.yarn/releases 149 | !.yarn/patches 150 | !.yarn/plugins 151 | !.yarn/sdks 152 | !.yarn/versions 153 | 154 | # if you are NOT using Zero-installs, then: 155 | # comment the following lines 156 | !.yarn/cache 157 | 158 | # and uncomment the following lines 159 | # .pnp.* 160 | 161 | # End of https://www.toptal.com/developers/gitignore/api/node,yarn -------------------------------------------------------------------------------- /api/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "avoid", 3 | "bracketSpacing": true, 4 | "endOfLine": "lf", 5 | "htmlWhitespaceSensitivity": "css", 6 | "insertPragma": false, 7 | "printWidth": 80, 8 | "proseWrap": "always", 9 | "quoteProps": "as-needed", 10 | "requirePragma": false, 11 | "semi": true, 12 | "singleQuote": true, 13 | "tabWidth": 2, 14 | "trailingComma": "all", 15 | "useTabs": false 16 | } 17 | -------------------------------------------------------------------------------- /api/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "dbaeumer.vscode-eslint", 4 | "esbenp.prettier-vscode", 5 | "formulahendry.auto-rename-tag", 6 | "mgmcdermott.vscode-language-babel", 7 | "eg2.vscode-npm-script", 8 | "visualstudioexptteam.vscodeintellicode", 9 | "graphql.vscode-graphql", 10 | "mike-co.import-sorter", 11 | "prisma.prisma" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /api/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "typescript.tsdk": "node_modules/typescript/lib", 3 | "editor.defaultFormatter": "esbenp.prettier-vscode", 4 | "editor.formatOnSave": true, 5 | "editor.detectIndentation": true, 6 | "editor.snippetSuggestions": "top", 7 | "editor.wordBasedSuggestions": false, 8 | "editor.suggest.localityBonus": true, 9 | "editor.acceptSuggestionOnCommitCharacter": false, 10 | "[typescript]": { 11 | "editor.defaultFormatter": "esbenp.prettier-vscode", 12 | "editor.suggestSelection": "recentlyUsed", 13 | "editor.suggest.showKeywords": false 14 | }, 15 | "[json]": { 16 | "editor.defaultFormatter": "esbenp.prettier-vscode" 17 | }, 18 | "[prisma]": { 19 | "editor.defaultFormatter": "Prisma.prisma" 20 | }, 21 | "editor.renderWhitespace": "boundary", 22 | "files.defaultLanguage": "{activeEditorLanguage}", 23 | "search.exclude": { 24 | "**/node_modules": true, 25 | "**/bower_components": true, 26 | "**/coverage": true, 27 | "**/dist": true, 28 | "**/build": true, 29 | "**/.build": true, 30 | "**/.gh-pages": true 31 | }, 32 | "editor.codeActionsOnSave": { 33 | "source.fixAll.eslint": false 34 | }, 35 | "eslint.validate": ["typescript"], 36 | "npm.runSilent": false, 37 | "explorer.confirmDragAndDrop": false, 38 | "editor.formatOnPaste": false, 39 | "editor.cursorSmoothCaretAnimation": "off", 40 | "editor.smoothScrolling": false, 41 | "importSorter.sortConfiguration.customOrderingRules.rules": [ 42 | { 43 | "type": "importMember", 44 | "regex": "^$", 45 | "orderLevel": 5, 46 | "disableSort": true 47 | }, 48 | { 49 | "regex": "react", 50 | "orderLevel": 8, 51 | "disableSort": true 52 | }, 53 | { 54 | "regex": "^[^.@]", 55 | "orderLevel": 15 56 | }, 57 | { 58 | "regex": "^[@]", 59 | "orderLevel": 10 60 | }, 61 | { 62 | "regex": "^[.]", 63 | "orderLevel": 30 64 | } 65 | ] 66 | } 67 | -------------------------------------------------------------------------------- /api/Dockerfile: -------------------------------------------------------------------------------- 1 | # FROM node:16 2 | # WORKDIR /usr/src/app 3 | # COPY ["package*.json", "yarn.lock*", "./"] 4 | # COPY tsconfig.json ./ 5 | # COPY src ./src 6 | # RUN npm install --global yarn --force 7 | # RUN yarn install 8 | # RUN yarn build 9 | # ## this is stage two , where the app actually runs 10 | # FROM node:16 11 | # WORKDIR /usr/src/app 12 | # COPY package.json ./ 13 | # RUN npm install --global yarn --force 14 | # RUN yarn install --production --force --silent 15 | # COPY tsconfig.json ./ 16 | # COPY --from=0 /usr/src/app/dist ./dist 17 | # COPY --from=0 /usr/src/app/src/nexus_generated ./src/nexus_generated 18 | # EXPOSE 8000 19 | # CMD [ "yarn", "start" ] 20 | FROM node:16 21 | 22 | # Create app directory 23 | WORKDIR /usr/src/app 24 | 25 | # Install app dependencies 26 | # A wildcard is used to ensure both package.json AND package-lock.json are copied 27 | COPY ["package*.json", "yarn.lock*", "./"] 28 | 29 | RUN npm install --global yarn --force 30 | RUN yarn install --force --silent 31 | 32 | # Bundle app source 33 | COPY . . 34 | 35 | RUN yarn build 36 | EXPOSE 8000 37 | CMD [ "yarn", "start" ] 38 | -------------------------------------------------------------------------------- /api/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "avenue-api", 3 | "author": "dscnitrourkela", 4 | "description": "GraphQL APIs for Avenue NITR", 5 | "version": "1.0.0", 6 | "main": "dist/index.js", 7 | "license": "MIT", 8 | "homepage": "https://github.com/dscnitrourkela/project-dates#readme", 9 | "keywords": [ 10 | "nitr", 11 | "avenue", 12 | "dsc", 13 | "dscnitr", 14 | "api", 15 | "graphql", 16 | "apollo", 17 | "typescript", 18 | "node", 19 | "mongodb", 20 | "prisma", 21 | "nexus" 22 | ], 23 | "bugs": { 24 | "url": "https://github.com/dscnitrourkela/project-dates/issues" 25 | }, 26 | "repository": { 27 | "type": "git", 28 | "url": "git+https://github.com/dscnitrourkela/project-dates.git" 29 | }, 30 | "scripts": { 31 | "generate:nexus": "ts-node --transpile-only -r tsconfig-paths/register src/config/nexus", 32 | "generate:prisma": "prisma generate --schema=./src/prisma/schema.prisma", 33 | "prisma:update": "prisma db push --schema=./src/prisma/schema.prisma", 34 | "generate": "yarn generate:nexus && yarn generate:prisma", 35 | "dev": "nodemon --exec ts-node -r tsconfig-paths/register src/index.ts", 36 | "start:server": "node -r ts-node/register/transpile-only -r tsconfig-paths/register dist/index.js", 37 | "start": "yarn prisma:update && yarn start:server", 38 | "build:dev": "tsc", 39 | "build": "yarn generate && tsc", 40 | "prettier:fix": "yarn prettier --write .", 41 | "prettier:check": "yarn prettier --check .", 42 | "lint:fix": "yarn eslint --fix \"**/*.ts\"", 43 | "lint:find": "yarn eslint \"**/*.tx\"" 44 | }, 45 | "hooks": { 46 | "predeploy": "yarn install --production", 47 | "postdeploy": "yarn install --production=false" 48 | }, 49 | "devDependencies": { 50 | "@types/cors": "^2.8.12", 51 | "@types/express": "^4.17.14", 52 | "@types/graphql-iso-date": "^3.4.0", 53 | "@types/node": "^18.8.5", 54 | "@typescript-eslint/eslint-plugin": "^5.40.0", 55 | "@typescript-eslint/parser": "^5.40.0", 56 | "eslint": "^8.25.0", 57 | "eslint-config": "^0.3.0", 58 | "eslint-config-airbnb": "^19.0.4", 59 | "eslint-config-airbnb-base": "^15.0.0", 60 | "eslint-config-airbnb-typescript": "^17.0.0", 61 | "eslint-config-prettier": "^8.5.0", 62 | "eslint-import-resolver-typescript": "^3.5.1", 63 | "eslint-plugin-import": "^2.26.0", 64 | "eslint-plugin-jest": "^27.1.1", 65 | "eslint-plugin-node": "^11.1.0", 66 | "eslint-plugin-prettier": "^4.2.1", 67 | "nodemon": "^2.0.20", 68 | "prettier": "^2.7.1", 69 | "typescript": "^4.8.4" 70 | }, 71 | "dependencies": { 72 | "@apollo/server": "^4.0.0", 73 | "@prisma/client": "^4.4.0", 74 | "axios": "^1.1.3", 75 | "cors": "^2.8.5", 76 | "dotenv": "^16.0.3", 77 | "express": "^4.18.2", 78 | "firebase-admin": "^11.1.0", 79 | "graphql": "^16.6.0", 80 | "graphql-iso-date": "^3.6.1", 81 | "mongoose": "^6.6.7", 82 | "nexus": "^1.3.0", 83 | "prisma": "^4.4.0", 84 | "ts-node": "^10.9.1", 85 | "tsconfig-paths": "^4.1.0", 86 | "winston": "^3.8.2" 87 | }, 88 | "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e" 89 | } 90 | -------------------------------------------------------------------------------- /api/src/apollo/DeveloperInfo/index.ts: -------------------------------------------------------------------------------- 1 | export * from './type'; 2 | export * from './queries'; 3 | export * from './mutations'; 4 | -------------------------------------------------------------------------------- /api/src/apollo/DeveloperInfo/mutations.ts: -------------------------------------------------------------------------------- 1 | import { PERMISSIONS } from 'constants/auth'; 2 | import { checkGqlPermissions } from 'helpers/auth/checkPermissions'; 3 | import { idArg, inputObjectType, mutationField, nonNull } from 'nexus'; 4 | 5 | export const DeveloperInfoCreateInputType = inputObjectType({ 6 | name: 'DeveloperInfoCreateInputType', 7 | description: `Input arguments used in createDeveloperInfo mutation`, 8 | definition(t) { 9 | t.nonNull.string('name'); 10 | t.nonNull.id('github'); 11 | }, 12 | }); 13 | 14 | export const createDeveloperInfo = mutationField('createDeveloperInfo', { 15 | type: 'DeveloperInfo', 16 | description: `Creates a new developer information record`, 17 | authorize: (_parent, _args, ctx) => 18 | checkGqlPermissions(ctx, [ 19 | PERMISSIONS.SUPER_ADMIN, 20 | PERMISSIONS.SUPER_EDITOR, 21 | ]), 22 | args: { 23 | developerInfo: nonNull('DeveloperInfoCreateInputType'), 24 | }, 25 | resolve(_parent, args, { prisma }) { 26 | return prisma.developerInfo.create({ 27 | data: args.developerInfo, 28 | }); 29 | }, 30 | }); 31 | 32 | export const DeveloperInfoUpdateInputType = inputObjectType({ 33 | name: 'DeveloperInfoUpdateInputType', 34 | description: `Input arguments used in updateDeveloperInfo mutation`, 35 | definition(t) { 36 | t.string('name'); 37 | t.id('github'); 38 | }, 39 | }); 40 | 41 | export const updateDeveloperInfo = mutationField('updateDeveloperInfo', { 42 | type: 'DeveloperInfo', 43 | description: `Updates an existing developer information record`, 44 | authorize: (_parent, _args, ctx) => 45 | checkGqlPermissions(ctx, [ 46 | PERMISSIONS.SUPER_ADMIN, 47 | PERMISSIONS.SUPER_EDITOR, 48 | ]), 49 | args: { 50 | id: nonNull(idArg()), 51 | developerInfo: nonNull('DeveloperInfoUpdateInputType'), 52 | }, 53 | resolve(_parent, args, { prisma }) { 54 | return prisma.developerInfo.update({ 55 | where: { 56 | id: args.id, 57 | }, 58 | data: { 59 | name: args.developerInfo?.name || undefined, 60 | github: args.developerInfo?.github || undefined, 61 | }, 62 | }); 63 | }, 64 | }); 65 | 66 | export const deleteDeveloperInfo = mutationField('deleteDeveloperInfo', { 67 | type: 'DeveloperInfo', 68 | description: `Deletes an existing developer information record`, 69 | authorize: (_parent, _args, ctx) => 70 | checkGqlPermissions(ctx, [ 71 | PERMISSIONS.SUPER_ADMIN, 72 | PERMISSIONS.SUPER_EDITOR, 73 | ]), 74 | args: { 75 | id: nonNull(idArg()), 76 | }, 77 | resolve(_parent, args, { prisma }) { 78 | return prisma.developerInfo.delete({ 79 | where: { 80 | id: args.id, 81 | }, 82 | }); 83 | }, 84 | }); 85 | -------------------------------------------------------------------------------- /api/src/apollo/DeveloperInfo/queries.ts: -------------------------------------------------------------------------------- 1 | import { idArg, list, queryField } from 'nexus'; 2 | 3 | export const developerInfo = queryField('developerInfo', { 4 | type: list('DeveloperInfo'), 5 | description: `Returns a list of all the developers of the application`, 6 | args: { 7 | id: idArg(), 8 | }, 9 | resolve(_parent, args, { prisma }) { 10 | const { id } = args; 11 | 12 | if (id) { 13 | return prisma.developerInfo.findMany({ 14 | where: { 15 | id: id || undefined, 16 | }, 17 | }); 18 | } 19 | 20 | return prisma.developerInfo.findMany(); 21 | }, 22 | }); 23 | -------------------------------------------------------------------------------- /api/src/apollo/DeveloperInfo/type.ts: -------------------------------------------------------------------------------- 1 | import { objectType } from 'nexus'; 2 | 3 | export const DeveloperInfo = objectType({ 4 | name: 'DeveloperInfo', 5 | description: `Refers to the various developers of the Avenue Application including the backend, frontend and mobile team`, 6 | definition(t) { 7 | t.nonNull.id('id'); 8 | t.nonNull.string('name'); 9 | t.nonNull.id('github'); 10 | }, 11 | }); 12 | -------------------------------------------------------------------------------- /api/src/apollo/Event/index.ts: -------------------------------------------------------------------------------- 1 | export * from './type'; 2 | export * from './queries'; 3 | export * from './mutations'; 4 | -------------------------------------------------------------------------------- /api/src/apollo/Event/mutations.ts: -------------------------------------------------------------------------------- 1 | import { PERMISSIONS } from 'constants/auth'; 2 | import { checkGqlPermissions } from 'helpers/auth/checkPermissions'; 3 | import { idArg, inputObjectType, mutationField, nonNull, list } from 'nexus'; 4 | 5 | export const EventCreateInputType = inputObjectType({ 6 | name: 'EventCreateInputType', 7 | description: `Input arguments used in createEvent mutation`, 8 | definition(t) { 9 | t.nonNull.string('name'); 10 | t.string('subHeading'); 11 | t.nonNull.string('description'); 12 | t.string('prizeMoney'); 13 | t.list.nonNull.string('contact'); 14 | t.nonNull.string('poster'); 15 | t.string('rules'); 16 | t.nullable.id('locationID'); 17 | t.nonNull.date('startDate'); 18 | t.date('endDate'); 19 | t.nonNull.list.nonNull.id('orgID'); 20 | t.orgType('orgType'); 21 | t.list.nonNull.string('notes'); 22 | t.list.nonNull.id('pocID'); 23 | t.boolean('weekly'); 24 | t.repeatType('repeatDay', { default: null }); 25 | t.int('priority'); 26 | t.string('type'); 27 | t.status('status', { default: 'DRAFT' }); 28 | }, 29 | }); 30 | 31 | export const createEvent = mutationField('createEvent', { 32 | type: 'Event', 33 | description: `Creates a new event record`, 34 | authorize: (_parent, args, ctx) => 35 | checkGqlPermissions( 36 | ctx, 37 | [ 38 | PERMISSIONS.SUPER_ADMIN, 39 | PERMISSIONS.SUPER_EDITOR, 40 | PERMISSIONS.ORG_ADMIN, 41 | PERMISSIONS.ORG_EDITOR, 42 | ], 43 | args.orgID, 44 | ), 45 | args: { 46 | orgID: nonNull(idArg()), 47 | event: nonNull('EventCreateInputType'), 48 | }, 49 | resolve(_parent, args, { prisma }) { 50 | return prisma.event.create({ 51 | data: { 52 | ...args.event, 53 | contact: args.event.contact || [], 54 | pocID: args.event.pocID || [], 55 | notes: args.event.notes || [], 56 | }, 57 | }); 58 | }, 59 | }); 60 | 61 | export const EventUpdateInputType = inputObjectType({ 62 | name: 'EventUpdateInputType', 63 | description: `Input arguments used in updateEvent mutation`, 64 | definition(t) { 65 | t.string('name'); 66 | t.string('subHeading'); 67 | t.string('description'); 68 | t.string('prizeMoney'); 69 | t.list.nonNull.string('contact'); 70 | t.string('rules'); 71 | t.string('poster'); 72 | t.id('locationID'); 73 | t.date('startDate'); 74 | t.date('endDate'); 75 | t.list.nonNull.id('orgID'); 76 | t.orgType('orgType'); 77 | t.list.nonNull.string('notes'); 78 | t.list.nonNull.id('pocID'); 79 | t.boolean('weekly'); 80 | t.repeatType('repeatDay'); 81 | t.int('priority'); 82 | t.string('type'); 83 | t.status('status'); 84 | }, 85 | }); 86 | 87 | export const updateEvent = mutationField('updateEvent', { 88 | type: 'Event', 89 | description: `Updates an existing event record`, 90 | authorize: (_parent, args, ctx) => 91 | checkGqlPermissions( 92 | ctx, 93 | [ 94 | PERMISSIONS.SUPER_ADMIN, 95 | PERMISSIONS.SUPER_EDITOR, 96 | PERMISSIONS.ORG_ADMIN, 97 | PERMISSIONS.ORG_EDITOR, 98 | ], 99 | args.orgID, 100 | ), 101 | args: { 102 | id: nonNull(idArg()), 103 | orgID: nonNull(idArg()), 104 | event: nonNull('EventUpdateInputType'), 105 | }, 106 | resolve(_parent, args, { prisma }) { 107 | return prisma.event.update({ 108 | where: { 109 | id: args.id, 110 | }, 111 | data: { 112 | name: args.event?.name || undefined, 113 | subHeading: args.event?.subHeading || undefined, 114 | prizeMoney: args.event?.prizeMoney || undefined, 115 | contact: args.event?.contact || undefined, 116 | description: args.event?.description || undefined, 117 | poster: args.event?.poster || undefined, 118 | rules: args.event?.rules || undefined, 119 | startDate: args.event?.startDate || undefined, 120 | endDate: args.event?.endDate || undefined, 121 | orgID: args.event?.orgID || undefined, 122 | orgType: args.event?.orgType || undefined, 123 | priority: args.event?.priority || undefined, 124 | type: args.event?.type?.toUpperCase() || undefined, 125 | status: args.event?.status || undefined, 126 | }, 127 | }); 128 | }, 129 | }); 130 | 131 | // Mutation to add multiple events at once 132 | export const createMultipleEvents = mutationField('createMultipleEvents', { 133 | type: list('Event'), 134 | description: 'Creates multiple events at once', 135 | authorize: (_parent, args, ctx) => 136 | checkGqlPermissions( 137 | ctx, 138 | [ 139 | PERMISSIONS.SUPER_ADMIN, 140 | PERMISSIONS.SUPER_EDITOR, 141 | PERMISSIONS.ORG_ADMIN, 142 | PERMISSIONS.ORG_EDITOR, 143 | ], 144 | args.orgID, 145 | ), 146 | args: { 147 | orgID: nonNull(idArg()), 148 | events: nonNull(list(nonNull('EventCreateInputType'))), 149 | }, 150 | async resolve(_parent, args, { prisma }) { 151 | const createdEvents = await Promise.all( 152 | args.events.map(async (eventData: typeof args.events[number]) => 153 | prisma.event.create({ 154 | data: { 155 | ...eventData, 156 | status: eventData.status || 'ACTIVE', 157 | type: eventData.type?.toUpperCase(), 158 | contact: eventData.contact || [], 159 | pocID: eventData.pocID || [], 160 | notes: eventData.notes || [], 161 | }, 162 | }), 163 | ), 164 | ); 165 | 166 | return createdEvents; 167 | }, 168 | }); 169 | -------------------------------------------------------------------------------- /api/src/apollo/Event/queries.ts: -------------------------------------------------------------------------------- 1 | import { checkGqlPermissions } from 'helpers/auth/checkPermissions'; 2 | import { idArg, list, queryField, stringArg } from 'nexus'; 3 | 4 | export const getEventsByType = queryField('getEventsByType', { 5 | type: list('Event'), 6 | description: `Returns as list of events depending upon the arguments`, 7 | authorize: (_parent, args, ctx) => 8 | args.orgID ? true : checkGqlPermissions(ctx, []), 9 | args: { 10 | orgID: idArg(), 11 | type: stringArg(), 12 | pagination: 'paginationInputType', 13 | }, 14 | async resolve(_parent, args, { prisma }) { 15 | const { type, pagination } = args; 16 | 17 | return prisma.event.findMany({ 18 | skip: pagination?.skip, 19 | take: pagination?.take, 20 | where: { 21 | type: type || undefined, 22 | }, 23 | }); 24 | }, 25 | }); 26 | -------------------------------------------------------------------------------- /api/src/apollo/Event/type.ts: -------------------------------------------------------------------------------- 1 | import { objectType } from 'nexus'; 2 | 3 | export const Event = objectType({ 4 | name: 'Event', 5 | description: 6 | 'Refers to the various events created by the different organisations', 7 | definition(t) { 8 | t.nonNull.id('id'); 9 | t.nonNull.string('name'); 10 | t.string('subHeading'); 11 | t.string('prizeMoney'); 12 | t.nonNull.string('description'); 13 | t.nonNull.string('poster'); 14 | t.string('rules'); 15 | t.nonNull.date('startDate'); 16 | t.date('endDate'); 17 | t.orgType('orgType'); 18 | t.nonNull.list.nonNull.string('notes'); 19 | t.int('priority'); 20 | t.string('type'); 21 | t.status('status'); 22 | 23 | t.id('locationID'); 24 | 25 | t.list.nonNull.string('contact'); 26 | t.nonNull.list.nonNull.id('pocID'); 27 | t.nonNull.list.field('poc', { 28 | type: 'User', 29 | async resolve(parent, _args, { prisma }) { 30 | return prisma.user.findMany({ 31 | where: { 32 | id: { 33 | in: parent.pocID, 34 | }, 35 | }, 36 | }); 37 | }, 38 | }); 39 | 40 | t.nonNull.list.nonNull.id('orgID'); 41 | t.nonNull.list.field('org', { 42 | type: 'Org', 43 | resolve(parent, _args, { prisma }) { 44 | return prisma.org.findMany({ 45 | where: { 46 | id: { 47 | in: parent.orgID, 48 | }, 49 | }, 50 | }); 51 | }, 52 | }); 53 | 54 | t.nonNull.int('eventRegistrationCount', { 55 | resolve(parent, _args, { prisma }) { 56 | return prisma.eventRegistration.count({ 57 | where: { 58 | eventID: parent.id, 59 | }, 60 | }); 61 | }, 62 | }); 63 | 64 | t.nonNull.list.field('eventRegistration', { 65 | type: 'EventRegistration', 66 | resolve(parent, _args, { prisma }) { 67 | return prisma.eventRegistration.findMany({ 68 | where: { 69 | eventID: parent.id, 70 | }, 71 | }); 72 | }, 73 | }); 74 | }, 75 | }); 76 | -------------------------------------------------------------------------------- /api/src/apollo/EventRegistration/index.ts: -------------------------------------------------------------------------------- 1 | export * from './type'; 2 | export * from './queries'; 3 | export * from './mutations'; 4 | -------------------------------------------------------------------------------- /api/src/apollo/EventRegistration/mutations.ts: -------------------------------------------------------------------------------- 1 | import { PERMISSIONS } from 'constants/auth'; 2 | import { checkGqlPermissions } from 'helpers/auth/checkPermissions'; 3 | import { idArg, inputObjectType, mutationField, nonNull } from 'nexus'; 4 | 5 | export const EventRegistrationCreateInputType = inputObjectType({ 6 | name: 'EventRegistrationCreateInputType', 7 | description: `Input arguments used in createEventRegistration mutation`, 8 | definition(t) { 9 | t.nonNull.id('eventID'); 10 | t.nonNull.id('userID'); 11 | }, 12 | }); 13 | 14 | export const createEventRegistration = mutationField( 15 | 'createEventRegistration', 16 | { 17 | type: 'EventRegistration', 18 | description: `Creates an event registration record`, 19 | authorize: (_parent, _args, ctx) => checkGqlPermissions(ctx, []), 20 | args: { 21 | eventRegistration: nonNull('EventRegistrationCreateInputType'), 22 | }, 23 | resolve(_parent, args, { prisma }) { 24 | return prisma.eventRegistration.create({ 25 | data: args.eventRegistration, 26 | }); 27 | }, 28 | }, 29 | ); 30 | 31 | export const deleteEventRegistration = mutationField( 32 | 'deleteEventRegistration', 33 | { 34 | type: 'EventRegistration', 35 | description: `Deletes an existing event registration record`, 36 | authorize: (_parent, _args, ctx) => 37 | checkGqlPermissions(ctx, [ 38 | PERMISSIONS.SUPER_ADMIN, 39 | PERMISSIONS.SUPER_EDITOR, 40 | ]), 41 | args: { 42 | id: nonNull(idArg()), 43 | }, 44 | resolve(_parent, args, { prisma }) { 45 | return prisma.eventRegistration.delete({ 46 | where: { 47 | id: args.id, 48 | }, 49 | }); 50 | }, 51 | }, 52 | ); 53 | -------------------------------------------------------------------------------- /api/src/apollo/EventRegistration/queries.ts: -------------------------------------------------------------------------------- 1 | import { PERMISSIONS } from 'constants/auth'; 2 | import { checkGqlPermissions } from 'helpers/auth/checkPermissions'; 3 | import { idArg, list, queryField, nonNull } from 'nexus'; 4 | 5 | export const eventRegistration = queryField('eventRegistration', { 6 | type: list(nonNull('EventRegistration')), 7 | 8 | // to fetch list of eventIds for events where user has registered 9 | description: `Returns a list of events depending upon the arguments`, 10 | authorize: (_parent, args, ctx) => 11 | args.orgID || args.userID 12 | ? checkGqlPermissions(ctx, []) 13 | : checkGqlPermissions( 14 | ctx, 15 | [ 16 | PERMISSIONS.SUPER_ADMIN, 17 | PERMISSIONS.SUPER_EDITOR, 18 | PERMISSIONS.SUPER_VIEWER, 19 | PERMISSIONS.ORG_ADMIN, 20 | PERMISSIONS.ORG_EDITOR, 21 | PERMISSIONS.ORG_VIEWER, 22 | ], 23 | args.orgID || undefined, 24 | ), 25 | args: { 26 | id: idArg(), 27 | userID: idArg(), 28 | eventID: idArg(), 29 | orgID: idArg(), 30 | pagination: 'paginationInputType', 31 | }, 32 | resolve(_parent, args, { prisma }) { 33 | const { id, userID, eventID, pagination } = args; 34 | 35 | if (id || userID || eventID) { 36 | return prisma.eventRegistration.findMany({ 37 | skip: pagination?.skip, 38 | take: pagination?.take, 39 | where: { 40 | id: id || undefined, 41 | userID: userID || undefined, 42 | eventID: eventID || undefined, 43 | }, 44 | }); 45 | } 46 | 47 | return prisma.eventRegistration.findMany(); 48 | }, 49 | }); 50 | -------------------------------------------------------------------------------- /api/src/apollo/EventRegistration/type.ts: -------------------------------------------------------------------------------- 1 | import { objectType } from 'nexus'; 2 | 3 | export const EventRegistration = objectType({ 4 | name: 'EventRegistration', 5 | description: 'Refers to the registrations of a user for a particular event', 6 | definition(t) { 7 | t.nonNull.id('id'); 8 | 9 | t.nonNull.id('eventID'); 10 | t.field('event', { 11 | type: 'Event', 12 | resolve(parent, _args, { prisma }) { 13 | return prisma.event.findUnique({ 14 | where: { 15 | id: parent.eventID, 16 | }, 17 | }); 18 | }, 19 | }); 20 | 21 | t.nonNull.id('userID'); 22 | t.field('user', { 23 | type: 'User', 24 | resolve(parent, _args, { prisma }) { 25 | return prisma.user.findUnique({ 26 | where: { 27 | id: parent.userID, 28 | }, 29 | }); 30 | }, 31 | }); 32 | }, 33 | }); 34 | -------------------------------------------------------------------------------- /api/src/apollo/Institute/index.ts: -------------------------------------------------------------------------------- 1 | export * from './type'; 2 | // export * from './queries'; 3 | // export * from './mutations'; 4 | -------------------------------------------------------------------------------- /api/src/apollo/Institute/mutations.ts: -------------------------------------------------------------------------------- 1 | // import { mutationField, nonNull, stringArg } from 'nexus'; 2 | 3 | // export const incrementInstituteRegistration = mutationField( 4 | // 'incrementInstituteRegistration', 5 | // { 6 | // type: 'Institute', 7 | // description: 'Increments the registration count for an institute', 8 | // args: { 9 | // instituteId: nonNull(stringArg()), // The ID of the institute where the user is registering 10 | // }, 11 | // async resolve(_parent, { instituteId }, { prisma }) { 12 | // // Fetch the current registration count 13 | // const institute = await prisma.institute.findUnique({ 14 | // where: { id: instituteId }, 15 | // }); 16 | 17 | // if (!institute) { 18 | // throw new Error('Institute not found'); 19 | // } 20 | 21 | // // Increment the registration count 22 | // return prisma.institute.update({ 23 | // where: { id: instituteId }, 24 | // data: { 25 | // registrations: (institute.registrations || 0) + 1, 26 | // }, 27 | // }); 28 | // }, 29 | // }, 30 | // ); 31 | -------------------------------------------------------------------------------- /api/src/apollo/Institute/queries.ts: -------------------------------------------------------------------------------- 1 | // import { queryField, list, nonNull } from 'nexus'; 2 | 3 | // export const institutes = queryField('institutes', { 4 | // type: list(nonNull('Institute')), 5 | // description: 'Fetch a list of institutes with their registration stats', 6 | // resolve(_parent, _args, { prisma }) { 7 | // return prisma.institute.findMany({ 8 | // select: { 9 | // id: true, 10 | // name: true, 11 | // registrations: true, 12 | // }, 13 | // }); 14 | // }, 15 | // }); 16 | -------------------------------------------------------------------------------- /api/src/apollo/Institute/type.ts: -------------------------------------------------------------------------------- 1 | import { objectType } from 'nexus'; 2 | 3 | export const Institute = objectType({ 4 | name: 'Institute', 5 | description: 'Institute or College participating in fest details', 6 | definition(t) { 7 | t.nonNull.string('id'); 8 | t.nonNull.string('name'); 9 | t.string('description'); 10 | t.int('registrations'); 11 | t.status('status'); 12 | t.date('createdAt'); 13 | t.date('updatedAt'); 14 | }, 15 | }); 16 | -------------------------------------------------------------------------------- /api/src/apollo/Location/index.ts: -------------------------------------------------------------------------------- 1 | export * from './type'; 2 | export * from './queries'; 3 | export * from './mutations'; 4 | -------------------------------------------------------------------------------- /api/src/apollo/Location/mutations.ts: -------------------------------------------------------------------------------- 1 | import { PERMISSIONS } from 'constants/auth'; 2 | import { checkGqlPermissions } from 'helpers/auth/checkPermissions'; 3 | import { idArg, inputObjectType, mutationField, nonNull } from 'nexus'; 4 | 5 | export const LocationCreateInputType = inputObjectType({ 6 | name: 'LocationCreateInputType', 7 | description: `Input arguments used in createLocation mutation`, 8 | definition(t) { 9 | t.nonNull.string('name'); 10 | t.nonNull.string('description'); 11 | t.float('lat'); 12 | t.float('long'); 13 | }, 14 | }); 15 | 16 | export const createLocation = mutationField('createLocation', { 17 | type: 'Location', 18 | description: `Creates a new location record`, 19 | authorize: (_parent, _args, ctx) => 20 | checkGqlPermissions(ctx, [ 21 | PERMISSIONS.SUPER_ADMIN, 22 | PERMISSIONS.SUPER_EDITOR, 23 | ]), 24 | args: { 25 | location: nonNull('LocationCreateInputType'), 26 | }, 27 | resolve(_parent, args, { prisma }) { 28 | return prisma.location.create({ 29 | data: args.location, 30 | }); 31 | }, 32 | }); 33 | 34 | export const LocationUpdateInputType = inputObjectType({ 35 | name: 'LocationUpdateInputType', 36 | description: `Input arguments used in updateLocation mutation`, 37 | definition(t) { 38 | t.string('name'); 39 | t.string('description'); 40 | t.float('lat'); 41 | t.float('long'); 42 | }, 43 | }); 44 | 45 | export const updateLocation = mutationField('updateLocation', { 46 | type: 'Location', 47 | description: 'Updates the existing Location record', 48 | authorize: (_parent, _args, ctx) => 49 | checkGqlPermissions(ctx, [ 50 | PERMISSIONS.SUPER_ADMIN, 51 | PERMISSIONS.SUPER_EDITOR, 52 | ]), 53 | args: { 54 | id: nonNull(idArg()), 55 | location: nonNull('LocationUpdateInputType'), 56 | }, 57 | resolve(_parent, args, { prisma }) { 58 | return prisma.location.update({ 59 | where: { 60 | id: args.id, 61 | }, 62 | data: { 63 | ...args.location, 64 | name: args.location?.name || undefined, 65 | description: args.location?.description || undefined, 66 | }, 67 | }); 68 | }, 69 | }); 70 | 71 | export const deleteLocation = mutationField('deleteLocation', { 72 | type: 'Location', 73 | description: `Deletes an existing location record`, 74 | authorize: (_parent, _args, ctx) => 75 | checkGqlPermissions(ctx, [ 76 | PERMISSIONS.SUPER_ADMIN, 77 | PERMISSIONS.SUPER_EDITOR, 78 | ]), 79 | args: { 80 | id: nonNull(idArg()), 81 | }, 82 | resolve(_parent, args, { prisma }) { 83 | return prisma.location.delete({ 84 | where: { 85 | id: args.id, 86 | }, 87 | }); 88 | }, 89 | }); 90 | -------------------------------------------------------------------------------- /api/src/apollo/Location/queries.ts: -------------------------------------------------------------------------------- 1 | import { checkGqlPermissions } from 'helpers/auth/checkPermissions'; 2 | import { idArg, list, queryField } from 'nexus'; 3 | 4 | export const location = queryField('location', { 5 | type: list('Location'), 6 | description: 7 | 'Returns a list of all the locations depending upon the arguments', 8 | authorize: (_parent, _args, ctx) => checkGqlPermissions(ctx, []), 9 | args: { 10 | id: idArg(), 11 | }, 12 | resolve(_parent, args, { prisma }) { 13 | const { id } = args; 14 | 15 | if (id) { 16 | return prisma.location.findMany({ 17 | where: { 18 | id: id || undefined, 19 | }, 20 | }); 21 | } 22 | 23 | return prisma.location.findMany(); 24 | }, 25 | }); 26 | -------------------------------------------------------------------------------- /api/src/apollo/Location/type.ts: -------------------------------------------------------------------------------- 1 | import { objectType } from 'nexus'; 2 | 3 | export const Location = objectType({ 4 | name: 'Location', 5 | description: 'Refers to the various locations present in NITR', 6 | definition(t) { 7 | t.nonNull.id('id'); 8 | t.nonNull.string('name'); 9 | t.nonNull.string('description'); 10 | t.float('lat'); 11 | t.float('long'); 12 | }, 13 | }); 14 | -------------------------------------------------------------------------------- /api/src/apollo/Org/index.ts: -------------------------------------------------------------------------------- 1 | export * from './type'; 2 | export * from './queries'; 3 | export * from './mutations'; 4 | -------------------------------------------------------------------------------- /api/src/apollo/Org/mutations.ts: -------------------------------------------------------------------------------- 1 | import { PERMISSIONS } from 'constants/auth'; 2 | import { checkGqlPermissions } from 'helpers/auth/checkPermissions'; 3 | import { 4 | idArg, 5 | inputObjectType, 6 | mutationField, 7 | nonNull, 8 | list, 9 | stringArg, 10 | } from 'nexus'; 11 | 12 | export const OrgCreateInputType = inputObjectType({ 13 | name: 'OrgCreateInputType', 14 | description: 'Input arguments used in the createOrg mutation', 15 | definition(t) { 16 | t.nonNull.string('name'); 17 | t.string('description'); 18 | t.string('logo'); 19 | t.string('tagline'); 20 | t.string('coverImg'); 21 | t.string('theme'); 22 | t.id('festID'); 23 | t.int('registrationFee', { default: 0 }); 24 | t.date('startDate'); 25 | t.date('endDate'); 26 | t.status('status'); 27 | t.int('registrations', { default: 0 }); 28 | t.orgSubType('orgSubType'); 29 | t.nonNull.orgType('orgType'); 30 | t.id('locationID'); 31 | }, 32 | }); 33 | 34 | // Mutation for adding multiple orgs/Institues at once 35 | export const createMultipleOrgs = mutationField('createMultipleOrgs', { 36 | type: list('Org'), 37 | description: 'Creates multiple organisation records at once', 38 | authorize: (_parent, _args, ctx) => checkGqlPermissions(ctx, []), 39 | args: { 40 | orgs: nonNull(list(nonNull('OrgCreateInputType'))), // Expect an array of org input objects 41 | }, 42 | async resolve(_parent, args, { prisma }) { 43 | const createdOrgs = []; 44 | 45 | // Loop over each organization input and create it in the database 46 | for (const org of args.orgs) { 47 | const createdOrg = await prisma.org.create({ 48 | data: org, 49 | }); 50 | createdOrgs.push(createdOrg); 51 | } 52 | 53 | return createdOrgs; 54 | }, 55 | }); 56 | 57 | // single-org mutation for individual creation 58 | export const createOrg = mutationField('createOrg', { 59 | type: 'Org', 60 | description: 'Creates a new organisation record', 61 | authorize: (_parent, _args, ctx) => 62 | checkGqlPermissions(ctx, [PERMISSIONS.SUPER_ADMIN]), 63 | args: { 64 | org: nonNull('OrgCreateInputType'), 65 | }, 66 | resolve(_parent, args, { prisma }) { 67 | return prisma.org.create({ 68 | data: args.org, 69 | }); 70 | }, 71 | }); 72 | 73 | // Update mutation for updating existing organizations 74 | export const OrgUpdateInputType = inputObjectType({ 75 | name: 'OrgUpdateInputType', 76 | description: 'Input arguments used in the updateOrg mutation', 77 | nonNullDefaults: { 78 | input: false, 79 | }, 80 | definition(t) { 81 | t.string('name'); 82 | t.string('description'); 83 | t.string('logo'); 84 | t.string('tagline'); 85 | t.string('coverImg'); 86 | t.string('theme'); 87 | t.int('registrationFee'); 88 | t.date('startDate'); 89 | t.date('endDate'); 90 | t.status('status'); 91 | t.orgSubType('orgSubType'); 92 | t.orgType('orgType'); 93 | t.id('locationID'); 94 | }, 95 | }); 96 | 97 | // Original update org mutation retained 98 | export const updateOrg = mutationField('updateOrg', { 99 | type: 'Org', 100 | description: 'Updates an existing organisation record', 101 | authorize: (_parent, args, ctx) => checkGqlPermissions(ctx, [], args.id), 102 | args: { 103 | id: nonNull(idArg()), 104 | org: nonNull('OrgUpdateInputType'), 105 | }, 106 | resolve(_parent, args, { prisma }) { 107 | const { 108 | name, 109 | description, 110 | logo, 111 | registrationFee, 112 | status, 113 | orgSubType, 114 | orgType, 115 | tagline, 116 | coverImg, 117 | theme, 118 | startDate, 119 | endDate, 120 | locationID, 121 | } = args.org; 122 | 123 | return prisma.org.update({ 124 | where: { 125 | id: args.id, 126 | }, 127 | data: { 128 | name: name || undefined, 129 | description: description || undefined, 130 | logo: logo || undefined, 131 | registrationFee: registrationFee || undefined, 132 | status: status || undefined, 133 | orgSubType: orgSubType || undefined, 134 | orgType: orgType || undefined, 135 | tagline: tagline || undefined, 136 | coverImg: coverImg || undefined, 137 | theme: theme || undefined, 138 | startDate: startDate || undefined, 139 | endDate: endDate || undefined, 140 | locationID: locationID || undefined, 141 | }, 142 | }); 143 | }, 144 | }); 145 | 146 | // Increment the `registrations` field for a specific org 147 | export const incrementOrgRegistration = mutationField( 148 | 'incrementOrgRegistration', 149 | { 150 | type: 'Org', 151 | description: 'Increments the registration count for an organisation', 152 | args: { 153 | orgId: nonNull(stringArg()), // The ID of the College org from which the user is registering 154 | }, 155 | async resolve(_parent, { orgId }, { prisma }) { 156 | const org = await prisma.org.findUnique({ 157 | where: { id: orgId }, 158 | }); 159 | 160 | if (!org) { 161 | throw new Error('Organisation not found'); 162 | } 163 | 164 | return prisma.org.update({ 165 | where: { id: orgId }, 166 | data: { 167 | registrations: (org.registrations || 0) + 1, 168 | }, 169 | }); 170 | }, 171 | }, 172 | ); 173 | -------------------------------------------------------------------------------- /api/src/apollo/Org/queries.ts: -------------------------------------------------------------------------------- 1 | import { idArg, list, queryField } from 'nexus'; 2 | 3 | export const org = queryField('org', { 4 | type: list('Org'), 5 | description: 6 | 'Returns a list of all the organisations depending upon the arguments', 7 | args: { 8 | id: idArg(), 9 | orgType: 'OrgType', 10 | orgSubType: 'OrgSubType', 11 | pagination: 'paginationInputType', 12 | }, 13 | resolve(_parent, args, { prisma }) { 14 | const { id, orgType, orgSubType, pagination } = args; 15 | 16 | if (id || orgType || orgSubType) { 17 | return prisma.org.findMany({ 18 | skip: pagination?.skip, 19 | take: pagination?.take, 20 | where: { 21 | id: id || undefined, 22 | orgType: orgType || undefined, 23 | orgSubType: orgSubType || undefined, 24 | }, 25 | orderBy: { 26 | registrations: 'desc', 27 | }, 28 | }); 29 | } 30 | 31 | return prisma.org.findMany({ 32 | where: { 33 | orgType: orgType || undefined, 34 | }, 35 | orderBy: { 36 | createdAt: 'desc', 37 | }, 38 | }); 39 | }, 40 | }); 41 | -------------------------------------------------------------------------------- /api/src/apollo/Org/type.ts: -------------------------------------------------------------------------------- 1 | import { objectType } from 'nexus'; 2 | 3 | export const Org = objectType({ 4 | name: 'Org', 5 | description: 'Refers to the various groups creating several different events', 6 | definition(t) { 7 | t.nonNull.id('id'); 8 | t.nonNull.string('name'); 9 | t.string('description'); 10 | t.string('logo'); 11 | t.string('tagline'); 12 | t.string('coverImg'); 13 | t.string('theme'); 14 | t.int('registrationFee'); 15 | t.int('registrations'); 16 | t.date('startDate'); 17 | t.date('endDate'); 18 | t.status('status'); 19 | // t.collegeStatus('collegeStatus'); 20 | t.orgSubType('orgSubType'); 21 | t.nonNull.orgType('orgType'); 22 | 23 | t.id('locationID'); 24 | t.field('location', { 25 | type: 'Location', 26 | resolve(parent, _args, { prisma }) { 27 | return prisma.location.findUnique({ 28 | where: { 29 | id: parent.locationID || undefined, 30 | }, 31 | }); 32 | }, 33 | }); 34 | 35 | t.id('festID'); 36 | t.field('fest', { 37 | type: 'Org', 38 | resolve(parent, _args, { prisma }) { 39 | return prisma.org 40 | .findMany({ 41 | where: { 42 | festID: parent.festID, 43 | }, 44 | }) 45 | .then(fest => fest[0]); 46 | }, 47 | }); 48 | 49 | // New field to get the count of students (users) associated with this Org 50 | t.nonNull.int('studentCount', { 51 | resolve(parent, _args, { prisma }) { 52 | return prisma.user.count({ 53 | where: { 54 | college: parent.id, 55 | }, 56 | }); 57 | }, 58 | }); 59 | }, 60 | }); 61 | -------------------------------------------------------------------------------- /api/src/apollo/Scalars/DateTime.ts: -------------------------------------------------------------------------------- 1 | import { GraphQLDateTime } from 'graphql-iso-date'; 2 | import { asNexusMethod } from 'nexus'; 3 | 4 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 5 | // @ts-ignore 6 | export const DateTime = asNexusMethod(GraphQLDateTime, 'date'); 7 | -------------------------------------------------------------------------------- /api/src/apollo/Scalars/GenderType.ts: -------------------------------------------------------------------------------- 1 | import { enumType } from 'nexus'; 2 | 3 | export const GenderType = enumType({ 4 | name: 'GenderType', 5 | members: ['MALE', 'FEMALE', 'OTHERS'], 6 | asNexusMethod: 'gender', 7 | }); 8 | -------------------------------------------------------------------------------- /api/src/apollo/Scalars/OrgType.ts: -------------------------------------------------------------------------------- 1 | import { enumType } from 'nexus'; 2 | 3 | export const OrgSubType = enumType({ 4 | name: 'OrgSubType', 5 | members: ['TECHNICAL', 'CULTURAL', 'SPORTS', 'HACKATHON', 'LITERARY', 'FMS'], 6 | asNexusMethod: 'orgSubType', 7 | }); 8 | 9 | export const OrgType = enumType({ 10 | name: 'OrgType', 11 | members: [ 12 | 'CLUB', 13 | 'HOSTEL', 14 | 'INSTITUTE', 15 | 'BRANCH', 16 | 'FEST', 17 | 'BRANCH_SEM', 18 | 'MESS', 19 | ], 20 | asNexusMethod: 'orgType', 21 | }); 22 | -------------------------------------------------------------------------------- /api/src/apollo/Scalars/Pagination.ts: -------------------------------------------------------------------------------- 1 | import { inputObjectType } from 'nexus'; 2 | 3 | export const paginationInput = inputObjectType({ 4 | name: 'paginationInputType', 5 | description: 'Input arguments used for pagination details', 6 | definition(t) { 7 | t.nonNull.int('skip', { default: 0 }); 8 | t.nonNull.int('take', { default: 100 }); 9 | }, 10 | }); 11 | -------------------------------------------------------------------------------- /api/src/apollo/Scalars/RepeatType.ts: -------------------------------------------------------------------------------- 1 | import { enumType } from 'nexus'; 2 | 3 | export const RepeatType = enumType({ 4 | name: 'RepeatType', 5 | members: [ 6 | 'SUNDAY', 7 | 'MONDAY', 8 | 'TUESDAY', 9 | 'WEDNESDAY', 10 | 'THURSDAY', 11 | 'FRIDAY', 12 | 'SATURDAY', 13 | ], 14 | asNexusMethod: 'repeatType', 15 | }); 16 | -------------------------------------------------------------------------------- /api/src/apollo/Scalars/StatusType.ts: -------------------------------------------------------------------------------- 1 | import { enumType } from 'nexus'; 2 | 3 | export const StatusType = enumType({ 4 | name: 'StatusType', 5 | members: ['ACTIVE', 'DRAFT', 'EXPIRED'], 6 | asNexusMethod: 'status', 7 | }); 8 | -------------------------------------------------------------------------------- /api/src/apollo/Scalars/TransactionType.ts: -------------------------------------------------------------------------------- 1 | import { enumType } from 'nexus'; 2 | 3 | export const TransactionType = enumType({ 4 | name: 'TransactionType', 5 | members: ['REGISTRATION', 'MERCH', 'EVENT'], 6 | asNexusMethod: 'transactionType', 7 | }); 8 | -------------------------------------------------------------------------------- /api/src/apollo/Scalars/index.ts: -------------------------------------------------------------------------------- 1 | export * from './DateTime'; 2 | export * from './GenderType'; 3 | export * from './OrgType'; 4 | export * from './RepeatType'; 5 | export * from './StatusType'; 6 | export * from './TransactionType'; 7 | export * from './Pagination'; 8 | -------------------------------------------------------------------------------- /api/src/apollo/Story/index.ts: -------------------------------------------------------------------------------- 1 | export * from './type'; 2 | export * from './queries'; 3 | export * from './mutations'; 4 | -------------------------------------------------------------------------------- /api/src/apollo/Story/mutations.ts: -------------------------------------------------------------------------------- 1 | import { PERMISSIONS } from 'constants/auth'; 2 | import { checkGqlPermissions } from 'helpers/auth/checkPermissions'; 3 | import { idArg, inputObjectType, mutationField, nonNull } from 'nexus'; 4 | 5 | export const StoryCreateInputType = inputObjectType({ 6 | name: 'StoryCreateInputType', 7 | description: 'Input arguments used in the createStory mutation', 8 | definition(t) { 9 | t.nonNull.id('orgID'); 10 | t.nonNull.string('image'); 11 | t.string('linkTo'); 12 | }, 13 | }); 14 | 15 | export const createStory = mutationField('createStory', { 16 | type: 'Story', 17 | description: 'Creates a new story record', 18 | authorize: (_parent, args, ctx) => 19 | checkGqlPermissions( 20 | ctx, 21 | [ 22 | PERMISSIONS.SUPER_ADMIN, 23 | PERMISSIONS.SUPER_EDITOR, 24 | PERMISSIONS.ORG_ADMIN, 25 | PERMISSIONS.ORG_EDITOR, 26 | ], 27 | args.orgID, 28 | ), 29 | args: { 30 | orgID: nonNull(idArg()), 31 | story: nonNull('StoryCreateInputType'), 32 | }, 33 | resolve(_parent, args, { prisma }) { 34 | return prisma.story.create({ 35 | data: args.story, 36 | }); 37 | }, 38 | }); 39 | 40 | export const deleteStory = mutationField('deleteStory', { 41 | type: 'Boolean', 42 | description: 'Deletes and existing story record', 43 | authorize: (_parent, args, ctx) => 44 | checkGqlPermissions( 45 | ctx, 46 | [ 47 | PERMISSIONS.SUPER_ADMIN, 48 | PERMISSIONS.SUPER_EDITOR, 49 | PERMISSIONS.ORG_ADMIN, 50 | PERMISSIONS.ORG_EDITOR, 51 | ], 52 | args.orgID, 53 | ), 54 | args: { 55 | id: nonNull(idArg()), 56 | orgID: nonNull(idArg()), 57 | }, 58 | async resolve(_parent, args, { prisma }) { 59 | try { 60 | await prisma.story.delete({ 61 | where: { 62 | id: args.id, 63 | }, 64 | }); 65 | return true; 66 | } catch (error) { 67 | return false; 68 | } 69 | }, 70 | }); 71 | -------------------------------------------------------------------------------- /api/src/apollo/Story/queries.ts: -------------------------------------------------------------------------------- 1 | import { checkGqlPermissions } from 'helpers/auth/checkPermissions'; 2 | import { idArg, list, queryField } from 'nexus'; 3 | 4 | export const story = queryField('story', { 5 | type: list('Story'), 6 | description: 7 | 'Returns a list of all the stories depending upon the parameters', 8 | authorize: (_parent, _args, ctx) => checkGqlPermissions(ctx, []), 9 | args: { 10 | id: idArg(), 11 | orgID: idArg(), 12 | pagination: 'paginationInputType', 13 | }, 14 | resolve(_parents, args, { prisma }) { 15 | const { id, orgID } = args; 16 | 17 | if (id || orgID) { 18 | return prisma.story.findMany({ 19 | skip: args.pagination?.skip, 20 | take: args.pagination?.take, 21 | where: { 22 | id: id || undefined, 23 | orgID: orgID || undefined, 24 | }, 25 | }); 26 | } 27 | 28 | return prisma.story.findMany(); 29 | }, 30 | }); 31 | -------------------------------------------------------------------------------- /api/src/apollo/Story/type.ts: -------------------------------------------------------------------------------- 1 | import { objectType } from 'nexus'; 2 | 3 | export const Story = objectType({ 4 | name: 'Story', 5 | description: 'Refers to the various stories put by various', 6 | definition(t) { 7 | t.nonNull.id('id'); 8 | t.nonNull.string('image'); 9 | t.string('linkTo'); 10 | 11 | t.nonNull.id('orgID'); 12 | t.nonNull.field('org', { 13 | type: 'Org', 14 | async resolve(parent, _arg, { prisma }) { 15 | const org = await prisma.org.findUnique({ 16 | where: { 17 | id: parent.orgID, 18 | }, 19 | }); 20 | 21 | if (!org) throw new Error('Org not found'); 22 | return org; 23 | }, 24 | }); 25 | }, 26 | }); 27 | -------------------------------------------------------------------------------- /api/src/apollo/Team/index.ts: -------------------------------------------------------------------------------- 1 | export * from './type'; 2 | export * from './queries'; 3 | export * from './mutations'; 4 | -------------------------------------------------------------------------------- /api/src/apollo/Team/mutations.ts: -------------------------------------------------------------------------------- 1 | import { PERMISSIONS } from 'constants/auth'; 2 | import { checkGqlPermissions } from 'helpers/auth/checkPermissions'; 3 | import { idArg, inputObjectType, list, mutationField, nonNull } from 'nexus'; 4 | 5 | export const TeamCreateInputType = inputObjectType({ 6 | name: 'TeamCreateInputType', 7 | description: 'Input arguments used in the createTeam mutation', 8 | definition(t) { 9 | t.nonNull.id('id'); 10 | t.string('position'); 11 | t.string('team'); 12 | t.nonNull.id('userID'); 13 | t.nonNull.id('orgID'); 14 | t.int('priority'); 15 | }, 16 | }); 17 | 18 | /** 19 | * A special case of creation 20 | * Since team members will be added in bulk, 21 | * this mutation takes an array of team members as input 22 | * and then after successful addition, returns a count of 23 | * all the added records. 24 | * The count could vary in case of any duplicate record is 25 | * sent (duplicates will be omitted) 26 | */ 27 | export const createTeam = mutationField('createTeam', { 28 | type: 'Int', 29 | description: 'Creates multiple/single record/s of team members', 30 | authorize: (_parent, args, ctx) => 31 | checkGqlPermissions( 32 | ctx, 33 | [ 34 | PERMISSIONS.SUPER_ADMIN, 35 | PERMISSIONS.SUPER_EDITOR, 36 | PERMISSIONS.ORG_ADMIN, 37 | PERMISSIONS.ORG_EDITOR, 38 | ], 39 | args.orgID, 40 | ), 41 | args: { 42 | team: nonNull(list(nonNull('TeamCreateInputType'))), 43 | orgID: nonNull(idArg()), 44 | }, 45 | async resolve(_parent, args, { prisma }) { 46 | const { count } = await prisma.team.createMany({ 47 | data: args.team, 48 | }); 49 | 50 | return count; 51 | }, 52 | }); 53 | 54 | export const TeamUpdateInputType = inputObjectType({ 55 | name: 'TeamUpdateInputType', 56 | description: 'Input arguments used in the udpateTeam mutation', 57 | definition(t) { 58 | t.string('position'); 59 | t.string('team'); 60 | t.id('userID'); 61 | t.id('orgID'); 62 | t.int('priority'); 63 | }, 64 | }); 65 | 66 | export const updateTeam = mutationField('updateTeam', { 67 | type: 'Team', 68 | description: 'Updates the existing team member record', 69 | authorize: (_parent, args, ctx) => 70 | checkGqlPermissions( 71 | ctx, 72 | [ 73 | PERMISSIONS.SUPER_ADMIN, 74 | PERMISSIONS.SUPER_EDITOR, 75 | PERMISSIONS.ORG_ADMIN, 76 | PERMISSIONS.ORG_EDITOR, 77 | ], 78 | args.orgID, 79 | ), 80 | args: { 81 | id: nonNull(idArg()), 82 | team: nonNull('TeamUpdateInputType'), 83 | orgID: nonNull(idArg()), 84 | }, 85 | resolve(_parent, args, { prisma }) { 86 | return prisma.team.update({ 87 | where: { 88 | id: args.id, 89 | }, 90 | data: { 91 | ...args.team, 92 | userID: args.team?.userID || undefined, 93 | orgID: args.team?.orgID || undefined, 94 | }, 95 | }); 96 | }, 97 | }); 98 | -------------------------------------------------------------------------------- /api/src/apollo/Team/queries.ts: -------------------------------------------------------------------------------- 1 | import { idArg, list, nonNull, queryField } from 'nexus'; 2 | 3 | export const team = queryField('team', { 4 | type: list('Team'), 5 | description: 6 | 'Returns a list of all the team members of the given organsation', 7 | args: { 8 | orgID: nonNull(idArg()), 9 | }, 10 | resolve(_parent, args, { prisma }) { 11 | return prisma.team.findMany({ 12 | where: { 13 | orgID: args.orgID, 14 | }, 15 | }); 16 | }, 17 | }); 18 | -------------------------------------------------------------------------------- /api/src/apollo/Team/type.ts: -------------------------------------------------------------------------------- 1 | import { objectType } from 'nexus'; 2 | 3 | export const Team = objectType({ 4 | name: 'Team', 5 | description: 'Refers to the team member part of a particular organisation', 6 | definition(t) { 7 | t.nonNull.id('id'); 8 | t.string('position'); 9 | t.string('team'); 10 | t.int('priority'); 11 | 12 | t.nonNull.id('userID'); 13 | t.nonNull.field('user', { 14 | type: 'User', 15 | async resolve(parent, _args, { prisma }) { 16 | const user = await prisma.user.findUnique({ 17 | where: { id: parent.userID }, 18 | }); 19 | 20 | if (!user) throw new Error('User not found'); 21 | return user; 22 | }, 23 | }); 24 | 25 | t.nonNull.id('orgID'); 26 | t.nonNull.field('org', { 27 | type: 'Org', 28 | async resolve(parent, _arg, { prisma }) { 29 | const org = await prisma.org.findUnique({ 30 | where: { 31 | id: parent.orgID, 32 | }, 33 | }); 34 | 35 | if (!org) throw new Error('Org not found'); 36 | return org; 37 | }, 38 | }); 39 | }, 40 | }); 41 | -------------------------------------------------------------------------------- /api/src/apollo/Transaction/index.ts: -------------------------------------------------------------------------------- 1 | export * from './type'; 2 | export * from './queries'; 3 | export * from './mutations'; 4 | -------------------------------------------------------------------------------- /api/src/apollo/Transaction/mutations.ts: -------------------------------------------------------------------------------- 1 | import { checkGqlPermissions } from 'helpers/auth/checkPermissions'; 2 | import { inputObjectType, mutationField, nonNull } from 'nexus'; 3 | 4 | export const TransactionCreateInputType = inputObjectType({ 5 | name: 'TransactionCreateInputType', 6 | description: 'Input arguments used in createTransaction mutation', 7 | definition(t) { 8 | t.nonNull.id('id'); 9 | t.nonNull.int('amount'); 10 | t.nonNull.id('userID'); 11 | t.nonNull.id('transactionID'); 12 | t.nonNull.transactionType('type'); 13 | t.nonNull.date('timestamp'); 14 | t.nonNull.id('orgID'); 15 | t.string('comment'); 16 | }, 17 | }); 18 | 19 | export const createTransaction = mutationField('createTransaction', { 20 | type: 'Transaction', 21 | description: 'Creates a new transaction record', 22 | authorize: (_parent, _args, ctx) => checkGqlPermissions(ctx, []), 23 | args: { 24 | transaction: nonNull('TransactionCreateInputType'), 25 | }, 26 | resolve(_parent, args, { prisma }) { 27 | return prisma.transaction.create({ 28 | data: args.transaction, 29 | }); 30 | }, 31 | }); 32 | -------------------------------------------------------------------------------- /api/src/apollo/Transaction/queries.ts: -------------------------------------------------------------------------------- 1 | import { PERMISSIONS } from 'constants/auth'; 2 | import { checkGqlPermissions } from 'helpers/auth/checkPermissions'; 3 | import { idArg, objectType, queryField } from 'nexus'; 4 | 5 | const PaginatedTransactionType = objectType({ 6 | name: 'PaginatedTransactionType', 7 | description: 'Paginated response for transaction query', 8 | definition(t) { 9 | t.list.field('data', { 10 | type: 'Transaction', 11 | }); 12 | t.int('count'); 13 | }, 14 | }); 15 | 16 | export const transaction = queryField('transaction', { 17 | type: PaginatedTransactionType, 18 | description: `Returns a list of transactions depending upon the arguments passed`, 19 | authorize: (_parent, args, ctx) => 20 | args.id 21 | ? checkGqlPermissions(ctx, []) 22 | : checkGqlPermissions( 23 | ctx, 24 | [PERMISSIONS.SUPER_ADMIN, PERMISSIONS.ORG_ADMIN], 25 | args.orgID || undefined, 26 | ), 27 | args: { 28 | id: idArg(), 29 | orgID: idArg(), 30 | type: 'TransactionType', 31 | userID: idArg(), 32 | pagination: 'paginationInputType', 33 | }, 34 | async resolve(_parent, args, { prisma }) { 35 | const [transactions, count] = await prisma.$transaction([ 36 | prisma.transaction.findMany({ 37 | skip: args.pagination?.skip, 38 | take: args.pagination?.take, 39 | where: { 40 | id: args.id || undefined, 41 | orgID: args.orgID || undefined, 42 | type: args.type || undefined, 43 | userID: args.userID || undefined, 44 | }, 45 | }), 46 | prisma.transaction.count({ 47 | where: { 48 | id: args.id || undefined, 49 | orgID: args.orgID || undefined, 50 | type: args.type || undefined, 51 | userID: args.userID || undefined, 52 | }, 53 | }), 54 | ]); 55 | 56 | return { 57 | data: transactions, 58 | count, 59 | }; 60 | }, 61 | }); 62 | -------------------------------------------------------------------------------- /api/src/apollo/Transaction/type.ts: -------------------------------------------------------------------------------- 1 | import { objectType } from 'nexus'; 2 | 3 | export const Transaction = objectType({ 4 | name: 'Transaction', 5 | description: 'Refers to the transaction details of any sort of payment', 6 | definition(t) { 7 | t.nonNull.id('id'); 8 | t.nonNull.int('amount'); 9 | t.nonNull.id('transactionID'); 10 | t.nonNull.transactionType('type'); 11 | t.nonNull.date('timestamp'); 12 | t.string('comment'); 13 | 14 | t.nonNull.id('userID'); 15 | t.field('user', { 16 | type: 'User', 17 | resolve(parent, _args, { prisma }) { 18 | return prisma.user.findUnique({ 19 | where: { id: parent.userID }, 20 | }); 21 | }, 22 | }); 23 | 24 | t.nonNull.id('orgID'); 25 | t.field('org', { 26 | type: 'Org', 27 | resolve(parent, _arg, { prisma }) { 28 | return prisma.org.findUnique({ 29 | where: { 30 | id: parent.orgID, 31 | }, 32 | }); 33 | }, 34 | }); 35 | }, 36 | }); 37 | -------------------------------------------------------------------------------- /api/src/apollo/User/index.ts: -------------------------------------------------------------------------------- 1 | export * from './type'; 2 | export * from './queries'; 3 | export * from './mutations'; 4 | -------------------------------------------------------------------------------- /api/src/apollo/User/mutations.ts: -------------------------------------------------------------------------------- 1 | import { checkGqlPermissions } from 'helpers/auth/checkPermissions'; 2 | import { idArg, inputObjectType, mutationField, nonNull } from 'nexus'; 3 | 4 | export const UserCreateInputType = inputObjectType({ 5 | name: 'UserCreateInputType', 6 | description: 'Input arguments used in createUser mutation', 7 | definition(t) { 8 | t.nonNull.string('email'); 9 | t.nonNull.string('uid'); 10 | t.string('name'); 11 | t.string('photo'); 12 | t.gender('gender'); 13 | t.date('dob'); 14 | t.string('state'); 15 | t.string('city'); 16 | t.string('college'); 17 | t.string('idCard'); 18 | t.string('stream'); 19 | t.string('receipt'); 20 | t.nonNull.string('mobile'); 21 | t.string('referredBy'); 22 | t.string('rollNumber'); 23 | t.string('transactionID'); 24 | t.boolean('hasPaid'); 25 | }, 26 | }); 27 | 28 | export const createUser = mutationField('createUser', { 29 | type: 'User', 30 | description: 'Creates a new user record', 31 | authorize: (_parent, _args, ctx) => checkGqlPermissions(ctx, []), 32 | args: { 33 | user: nonNull('UserCreateInputType'), 34 | }, 35 | async resolve(_parent, args, { prisma }) { 36 | const isMobileValid = args.user.mobile?.length === 10; 37 | const isEmailValid = args.user.email 38 | .toLowerCase() 39 | .match(/^[a-z0-9](\.?[a-z0-9]){5,}@g(oogle)?mail\.com$/); 40 | 41 | if (!isEmailValid) throw new Error('Invalid Email, please try again'); 42 | if (!isMobileValid) 43 | throw new Error('Invalid Mobile Number, please try again'); 44 | 45 | if (args.user.rollNumber) { 46 | const users = await prisma.user.findMany({ 47 | where: { 48 | rollNumber: args.user.rollNumber, 49 | email: args.user.email, 50 | uid: args.user.uid, 51 | mobile: args.user.mobile, 52 | }, 53 | }); 54 | 55 | if (users.length > 0) { 56 | throw new Error('Roll Number already registered'); 57 | } 58 | } 59 | 60 | if (args.user.college) { 61 | await prisma.org.update({ 62 | where: { id: args.user.college }, 63 | data: { 64 | registrations: { increment: 1 }, 65 | }, 66 | }); 67 | } 68 | 69 | return prisma.user.create({ 70 | data: { 71 | ...args.user, 72 | selfID: args.user?.mobile, 73 | }, 74 | }); 75 | }, 76 | }); 77 | 78 | export const UserUpdateInputType = inputObjectType({ 79 | name: 'UserUpdateInputType', 80 | description: 'Input arguments used in updateUser mutation', 81 | definition(t) { 82 | t.string('name'); 83 | t.string('photo'); 84 | t.gender('gender'); 85 | t.date('dob'); 86 | t.string('state'); 87 | t.string('city'); 88 | t.string('college'); 89 | t.string('stream'); 90 | t.string('mobile'); 91 | t.string('selfID'); 92 | t.id('festID'); 93 | t.string('referredBy'); 94 | t.string('rollNumber'); 95 | t.id('ca'); 96 | t.boolean('hasPaid'); 97 | }, 98 | }); 99 | 100 | export const updateUser = mutationField('updateUser', { 101 | type: 'User', 102 | description: 'Updates an existing user record', 103 | authorize: (_parent, _args, ctx) => checkGqlPermissions(ctx, []), 104 | args: { 105 | id: nonNull(idArg()), 106 | user: nonNull('UserUpdateInputType'), 107 | }, 108 | resolve(_parent, args, { prisma }) { 109 | const isMobileValid = args.user.mobile?.length === 10; 110 | if (args.user.mobile && !isMobileValid) 111 | throw new Error('Invalid Mobile Number, please try again'); 112 | 113 | return prisma.user.update({ 114 | where: { id: args.id }, 115 | data: { 116 | name: args.user?.name || undefined, 117 | photo: args.user?.photo || undefined, 118 | gender: args.user?.gender || undefined, 119 | dob: args.user?.dob || undefined, 120 | state: args.user?.state || undefined, 121 | city: args.user?.city || undefined, 122 | college: args.user?.college || undefined, 123 | stream: args.user?.stream || undefined, 124 | mobile: args.user?.mobile || undefined, 125 | selfID: args.user?.selfID || undefined, 126 | festID: args.user?.festID ? { push: args.user?.festID } : undefined, 127 | referredBy: args.user?.referredBy || undefined, 128 | rollNumber: args.user?.rollNumber || undefined, 129 | ca: args.user?.ca ? { push: args.user?.ca } : undefined, 130 | hasPaid: args.user?.hasPaid || undefined, 131 | }, 132 | }); 133 | }, 134 | }); 135 | -------------------------------------------------------------------------------- /api/src/apollo/User/queries.ts: -------------------------------------------------------------------------------- 1 | import { PERMISSIONS } from '@constants'; 2 | 3 | import { checkGqlPermissions } from 'helpers/auth/checkPermissions'; 4 | import { idArg, list, nonNull, objectType, queryField, stringArg } from 'nexus'; 5 | 6 | const PaginatedUserType = objectType({ 7 | name: 'PaginatedUserType', 8 | description: 'Paginated response for user query', 9 | definition(t) { 10 | t.list.field('data', { 11 | type: 'User', 12 | }); 13 | t.int('count'); 14 | }, 15 | }); 16 | 17 | export const user = queryField('user', { 18 | type: PaginatedUserType, 19 | description: 'Returns a list of users depending upon the parameters passed', 20 | authorize: (_parent, args, ctx) => 21 | args.id || args.uid || args.name || args.orgID 22 | ? checkGqlPermissions(ctx, []) 23 | : checkGqlPermissions( 24 | ctx, 25 | [ 26 | PERMISSIONS.SUPER_ADMIN, 27 | PERMISSIONS.SUPER_EDITOR, 28 | PERMISSIONS.SUPER_VIEWER, 29 | PERMISSIONS.ORG_ADMIN, 30 | PERMISSIONS.ORG_EDITOR, 31 | PERMISSIONS.ORG_VIEWER, 32 | ], 33 | args.orgID || undefined, 34 | ), 35 | args: { 36 | id: idArg(), 37 | uid: idArg(), 38 | name: stringArg(), 39 | orgID: idArg(), 40 | email: stringArg(), 41 | state: stringArg(), 42 | city: stringArg(), 43 | college: stringArg(), 44 | stream: stringArg(), 45 | referredBy: stringArg(), 46 | festID: list(nonNull(stringArg())), 47 | rollNumber: stringArg(), 48 | pagination: 'paginationInputType', 49 | }, 50 | async resolve(_parent, args, { prisma }) { 51 | const { 52 | id, 53 | uid, 54 | email, 55 | name, 56 | state, 57 | city, 58 | college, 59 | stream, 60 | referredBy, 61 | rollNumber, 62 | pagination, 63 | } = args; 64 | 65 | const prismaQuery = { 66 | id: id || undefined, 67 | email: email || undefined, 68 | uid: uid || undefined, 69 | name: name || undefined, 70 | state: state || undefined, 71 | city: city || undefined, 72 | college: college || undefined, 73 | stream: stream || undefined, 74 | referredBy: referredBy || undefined, 75 | rollNumber: rollNumber || undefined, 76 | }; 77 | 78 | const [users, count] = await prisma.$transaction([ 79 | prisma.user.findMany({ 80 | skip: pagination?.skip, 81 | take: pagination?.take, 82 | where: prismaQuery, 83 | }), 84 | prisma.user.count({ 85 | where: prismaQuery, 86 | }), 87 | ]); 88 | 89 | return { 90 | data: users, 91 | count, 92 | }; 93 | }, 94 | }); 95 | -------------------------------------------------------------------------------- /api/src/apollo/User/type.ts: -------------------------------------------------------------------------------- 1 | import { objectType } from 'nexus'; 2 | 3 | export const User = objectType({ 4 | name: 'User', 5 | description: 'Registered user', 6 | definition(t) { 7 | t.nonNull.string('id'); 8 | t.nonNull.string('email'); 9 | t.nonNull.string('uid'); 10 | t.string('name'); 11 | t.string('photo'); 12 | t.gender('gender'); 13 | t.date('dob'); 14 | t.string('state'); 15 | t.string('city'); 16 | t.string('college'); 17 | t.string('idCard'); 18 | t.string('stream'); 19 | t.string('mobile'); 20 | t.string('selfID'); 21 | t.string('referredBy'); 22 | t.boolean('hasPaid'); 23 | t.string('receipt'); 24 | t.string('rollNumber'); 25 | t.date('createdAt'); 26 | t.string('transactionID'); 27 | t.nonNull.list.nonNull.id('ca'); 28 | 29 | t.nonNull.list.nonNull.id('festID'); 30 | /* 31 | t.nonNull.list.field('fests', { 32 | type: nonNull('Org'), 33 | resolve(parent, _args, { prisma }) { 34 | return prisma.org.findMany({ 35 | where: { 36 | festID: { 37 | in: parent.festID, 38 | }, 39 | }, 40 | }); 41 | }, 42 | }); */ 43 | }, 44 | }); 45 | -------------------------------------------------------------------------------- /api/src/apollo/index.ts: -------------------------------------------------------------------------------- 1 | // export * from './scalers'; 2 | export * from './Scalars'; 3 | export * from './User'; 4 | export * from './Org'; 5 | export * from './Event'; 6 | export * from './Team'; 7 | export * from './Transaction'; 8 | export * from './EventRegistration'; 9 | export * from './Story'; 10 | export * from './Location'; 11 | export * from './DeveloperInfo'; 12 | -------------------------------------------------------------------------------- /api/src/apollo/server.ts: -------------------------------------------------------------------------------- 1 | import { ApolloServer } from '@apollo/server'; 2 | import { expressMiddleware } from '@apollo/server/express4'; 3 | import { ApolloServerPluginDrainHttpServer } from '@apollo/server/plugin/drainHttpServer'; 4 | import { schema, winston } from '@config'; 5 | import { PORT } from '@constants'; 6 | import { Context, context } from '@utils'; 7 | 8 | import { Application } from 'express'; 9 | import http from 'http'; 10 | 11 | export const initializeApollo = async (app: Application) => { 12 | const logger = winston('server'); 13 | 14 | const httpServer = http.createServer(app); 15 | 16 | const server = new ApolloServer({ 17 | schema, 18 | plugins: [ApolloServerPluginDrainHttpServer({ httpServer })], 19 | }); 20 | await server.start(); 21 | 22 | app.use( 23 | '/graphql', 24 | expressMiddleware(server, { 25 | context, 26 | }), 27 | ); 28 | 29 | httpServer.listen(PORT, () => 30 | logger.info(`server started at: http://localhost:${PORT}`), 31 | ); 32 | }; 33 | -------------------------------------------------------------------------------- /api/src/config/firebase.ts: -------------------------------------------------------------------------------- 1 | import admin from 'firebase-admin'; 2 | 3 | import { 4 | AUTH_PROVIDER, 5 | AUTH_URI, 6 | CERT_URL, 7 | CLIENT_EMAIL, 8 | CLIENT_ID, 9 | PRIVATE_KEY, 10 | PRIVATE_KEY_ID, 11 | PROJECT_ID, 12 | TOKEN_URI, 13 | } from '@constants'; 14 | 15 | const serviceAccount = { 16 | type: 'service_account', 17 | project_id: PROJECT_ID, 18 | private_key_id: PRIVATE_KEY_ID, 19 | private_key: PRIVATE_KEY, 20 | client_email: CLIENT_EMAIL, 21 | client_id: CLIENT_ID, 22 | auth_uri: AUTH_URI, 23 | token_uri: TOKEN_URI, 24 | auth_provider_x509_cert_url: AUTH_PROVIDER, 25 | client_x509_cert_url: CERT_URL, 26 | }; 27 | 28 | export const firebaseApp = admin.initializeApp({ 29 | credential: admin.credential.cert(serviceAccount as unknown as string), 30 | }); 31 | -------------------------------------------------------------------------------- /api/src/config/index.ts: -------------------------------------------------------------------------------- 1 | export * from './winston'; 2 | export * from './nexus'; 3 | export * from './firebase'; 4 | export * from './mongoose'; 5 | -------------------------------------------------------------------------------- /api/src/config/mongoose.ts: -------------------------------------------------------------------------------- 1 | import { connect } from 'mongoose'; 2 | 3 | import { MONGO_AUTH_DB } from '@constants'; 4 | 5 | import { winston } from './winston'; 6 | 7 | export const mongoAuthDb = async () => { 8 | const logger = winston('authDb'); 9 | try { 10 | await connect(MONGO_AUTH_DB as string); 11 | logger.info('connected to auth db'); 12 | } catch (error) { 13 | logger.error(error); 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /api/src/config/nexus.ts: -------------------------------------------------------------------------------- 1 | import { fieldAuthorizePlugin, makeSchema } from 'nexus'; 2 | import { join } from 'path'; 3 | 4 | import * as types from '../apollo'; 5 | 6 | export const schema = makeSchema({ 7 | types, 8 | outputs: { 9 | schema: join(process.cwd(), '/src/nexus_generated/schema.graphql'), 10 | typegen: join(process.cwd(), '/src/nexus_generated/nexus-typegen.ts'), 11 | }, 12 | contextType: { 13 | module: join(process.cwd(), './src/utils/context.ts'), 14 | export: 'Context', 15 | }, 16 | plugins: [fieldAuthorizePlugin()], 17 | }); 18 | -------------------------------------------------------------------------------- /api/src/config/winston.ts: -------------------------------------------------------------------------------- 1 | import originalWinston from 'winston'; 2 | 3 | const { createLogger, format, transports } = originalWinston; 4 | const { combine, timestamp, label, printf, colorize } = format; 5 | 6 | export type IWinston = originalWinston.Logger; 7 | 8 | export const winston = (logModule: string): originalWinston.Logger => { 9 | const logFormat = combine( 10 | colorize({ all: true }), 11 | label({ label: 'avenue-api' }), 12 | timestamp({ format: 'DD-MM-YY HH:MM:SS' }), 13 | printf( 14 | ({ 15 | level: printLevel, 16 | message: printMessage, 17 | label: printLabel, 18 | timestamp: printTimestamp, 19 | }) => 20 | `[${printTimestamp}] [${printLabel}] | ${logModule} | ${printLevel} : ${printMessage}`, 21 | ), 22 | ); 23 | 24 | const options = { 25 | console: { 26 | handleExceptions: true, 27 | json: false, 28 | format: logFormat, 29 | }, 30 | }; 31 | 32 | return createLogger({ 33 | level: 'debug', 34 | transports: [new transports.Console(options.console)], 35 | exitOnError: false, 36 | }); 37 | }; 38 | -------------------------------------------------------------------------------- /api/src/constants/auth.ts: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-shadow 2 | export enum PERMISSIONS { 3 | SUPER_ADMIN = 'superAdmin', 4 | SUPER_EDITOR = 'superEditor', 5 | SUPER_VIEWER = 'superViewer', 6 | ORG_ADMIN = 'orgAdmin', 7 | ORG_EDITOR = 'orgEditor', 8 | ORG_VIEWER = 'orgViewer', 9 | } 10 | -------------------------------------------------------------------------------- /api/src/constants/env.ts: -------------------------------------------------------------------------------- 1 | import 'dotenv/config'; 2 | 3 | export const { 4 | PORT, 5 | MONGO_AUTH_DB, 6 | PROJECT_ID, 7 | PRIVATE_KEY_ID, 8 | PRIVATE_KEY, 9 | CLIENT_EMAIL, 10 | CLIENT_ID, 11 | AUTH_URI, 12 | TOKEN_URI, 13 | AUTH_PROVIDER, 14 | CERT_URL, 15 | INSTAMOJO_CLIENT_ID, 16 | INSTAMOJO_CLIENT_SECRET, 17 | INSTAMOJO_BASE_URL, 18 | ALLOWED_CLIENT_URL, 19 | } = process.env; 20 | -------------------------------------------------------------------------------- /api/src/constants/index.ts: -------------------------------------------------------------------------------- 1 | export * from './env'; 2 | export * from './auth'; 3 | -------------------------------------------------------------------------------- /api/src/helpers/auth/checkPermisionLegacy.ts: -------------------------------------------------------------------------------- 1 | // /* eslint-disable @typescript-eslint/no-explicit-any */ 2 | // /* eslint-disable consistent-return */ 3 | // import { 4 | // Request, 5 | // Response, 6 | // } from 'express'; 7 | // import { Permission } from 'rest/model'; 8 | 9 | // import { PERMISSIONS } from '@constants'; 10 | 11 | // import { verifyUser } from './verify'; 12 | 13 | // export type CustomNextFunction = ( 14 | // req: Request, 15 | // res: Response, 16 | // ) => Promise>>; 17 | 18 | // export const checkRestPermissions = 19 | // ( 20 | // next: CustomNextFunction, 21 | // requiredPermissions?: [PERMISSIONS?], 22 | // id?: string, 23 | // ) => 24 | // async (req: Request, res: Response) => { 25 | // if (!req.headers || !req.headers.authorization) { 26 | // return res.status(400).send('Bad Request: Token not found'); 27 | // } 28 | 29 | // const token = req.headers.authorization.split(' ')[1]; 30 | // if (!token) { 31 | // return res.status(403).send('Permission Denied'); 32 | // } 33 | 34 | // try { 35 | // const decodedToken = await verifyUser(token); 36 | // if (!decodedToken) { 37 | // return res.status(403).send('Permission Denied'); 38 | // } 39 | 40 | // if (!requiredPermissions || requiredPermissions.length === 0) { 41 | // return next(req, res); 42 | // } 43 | 44 | // const permissions = await Permission.findOne({ 45 | // uid: decodedToken.uid, 46 | // }); 47 | 48 | // if (!permissions) { 49 | // return res.status(403).send('Permission Denied'); 50 | // } 51 | 52 | // for (let i = 0; i < requiredPermissions.length; i += 1) { 53 | // const permission = requiredPermissions[i]; 54 | // if ( 55 | // (permission === PERMISSIONS.SUPER_ADMIN && permissions.superAdmin) || 56 | // (permission === PERMISSIONS.SUPER_EDITOR && 57 | // permissions.superEditor) || 58 | // (permission === PERMISSIONS.SUPER_VIEWER && permissions.superViewer) 59 | // ) { 60 | // return next(req, res); 61 | // } 62 | 63 | // if ( 64 | // (permission === PERMISSIONS.ORG_ADMIN && 65 | // permissions.orgAdmin.length > 0 && 66 | // id && 67 | // permissions.orgAdmin.includes(id)) || 68 | // (permission === PERMISSIONS.ORG_EDITOR && 69 | // permissions.orgEditor.length > 0 && 70 | // id && 71 | // permissions.orgEditor.includes(id)) || 72 | // (permission === PERMISSIONS.SUPER_VIEWER && 73 | // permissions.orgViewer.length > 0 && 74 | // id && 75 | // permissions.orgViewer.includes(id)) 76 | // ) { 77 | // return next(req, res); 78 | // } 79 | // } 80 | 81 | // return res.status(403).send('Permission Denied'); 82 | // } catch (error) { 83 | // return res.status(403).send('Permission Denied'); 84 | // } 85 | // }; 86 | 87 | // export const checkGraphQLPermissions = async ( 88 | // context: any, 89 | // requiredPermissions?: [PERMISSIONS?], 90 | // id?: string, 91 | // ) => { 92 | // if (!context.req.headers || !context.req.headers.authorization) { 93 | // return false; 94 | // } 95 | 96 | // const token = context.req.headers.authorization.split(' ')[1]; 97 | // if (!token) { 98 | // return false; 99 | // } 100 | 101 | // try { 102 | // const decodedToken = await verifyUser(token); 103 | // if (!decodedToken) { 104 | // return false; 105 | // } 106 | 107 | // if (!requiredPermissions || requiredPermissions.length === 0) { 108 | // return true; 109 | // } 110 | 111 | // const permissions = await Permission.findOne({ 112 | // uid: decodedToken.uid, 113 | // }); 114 | 115 | // if (!permissions) { 116 | // return false; 117 | // } 118 | 119 | // for (let i = 0; i < requiredPermissions.length; i += 1) { 120 | // const permission = requiredPermissions[i]; 121 | // if ( 122 | // (permission === PERMISSIONS.SUPER_ADMIN && permissions.superAdmin) || 123 | // (permission === PERMISSIONS.SUPER_EDITOR && permissions.superEditor) || 124 | // (permission === PERMISSIONS.SUPER_VIEWER && permissions.superViewer) 125 | // ) { 126 | // return true; 127 | // } 128 | 129 | // if ( 130 | // (permission === PERMISSIONS.ORG_ADMIN && 131 | // permissions.orgAdmin.length > 0 && 132 | // id && 133 | // permissions.orgAdmin.includes(id)) || 134 | // (permission === PERMISSIONS.ORG_EDITOR && 135 | // permissions.orgEditor.length > 0 && 136 | // id && 137 | // permissions.orgEditor.includes(id)) || 138 | // (permission === PERMISSIONS.SUPER_VIEWER && 139 | // permissions.orgViewer.length > 0 && 140 | // id && 141 | // permissions.orgViewer.includes(id)) 142 | // ) { 143 | // return true; 144 | // } 145 | // } 146 | 147 | // return false; 148 | // } catch (error) { 149 | // return false; 150 | // } 151 | // }; 152 | -------------------------------------------------------------------------------- /api/src/helpers/auth/checkPermissions.ts: -------------------------------------------------------------------------------- 1 | import { PERMISSIONS } from '@constants'; 2 | import { Context } from '@utils'; 3 | 4 | import { Request, Response } from 'express'; 5 | import { Permission as PermissionModel } from 'rest/model'; 6 | 7 | import { verifyUser } from './verify'; 8 | 9 | export const ERRORS = { 10 | UNAUTHORIZED: { 11 | message: 'Unauthorized: Token not found', 12 | code: 401, 13 | }, 14 | FORBIDDEN: { 15 | message: 'Permission Denied', 16 | code: 403, 17 | }, 18 | BAD_REQUEST: { 19 | message: 'Bad Request', 20 | code: 400, 21 | }, 22 | INTERNAL_SERVER: { 23 | message: 'Internal Server Error', 24 | code: 500, 25 | }, 26 | }; 27 | 28 | export class CustomError extends Error { 29 | code = 0; 30 | 31 | constructor(props: { code: number; message: string }) { 32 | super(props.message); 33 | this.code = props.code; 34 | } 35 | } 36 | 37 | export type CustomNextFunction = ( 38 | req: Request, 39 | res: Response, 40 | ) => Promise>>; 41 | 42 | // eslint-disable-next-line no-shadow 43 | export enum API_TYPE { 44 | GRAPHQL = 'graphql', 45 | REST = 'rest', 46 | } 47 | 48 | export type ErrorParam = { 49 | message: string; 50 | code: number; 51 | }; 52 | 53 | export const restErrorHandler = (res: Response) => (error: ErrorParam) => 54 | res.status(error.code).send(error.message); 55 | 56 | export const gqlErrorHandler = (error: ErrorParam) => new CustomError(error); 57 | 58 | export type CheckPermissionsType = { 59 | req: Request; 60 | successHandler: 61 | | (() => Promise>>) 62 | | (() => boolean); 63 | errorHandler: ( 64 | error: ErrorParam, 65 | ) => Response> | Error; 66 | requiredPermissions?: PERMISSIONS[]; 67 | id?: string; 68 | }; 69 | 70 | const checkPermissions = async ({ 71 | req, 72 | successHandler, 73 | errorHandler, 74 | requiredPermissions, 75 | id, 76 | }: CheckPermissionsType) => { 77 | if (!req.headers || !req.headers.authorization) { 78 | return errorHandler(ERRORS.UNAUTHORIZED); 79 | } 80 | 81 | const token = req.headers.authorization.split(' ')[1]; 82 | if (!token) { 83 | return errorHandler(ERRORS.FORBIDDEN); 84 | } 85 | 86 | try { 87 | const decodedToken = await verifyUser(token); 88 | if (!decodedToken) { 89 | return errorHandler(ERRORS.FORBIDDEN); 90 | } 91 | 92 | if (!requiredPermissions || requiredPermissions.length === 0) { 93 | return successHandler(); 94 | } 95 | 96 | const permissions = await PermissionModel.findOne({ 97 | uid: decodedToken.uid, 98 | }); 99 | 100 | if (!permissions) { 101 | return errorHandler(ERRORS.FORBIDDEN); 102 | } 103 | 104 | for (let i = 0; i < requiredPermissions.length; i += 1) { 105 | const permission = requiredPermissions[i]; 106 | if ( 107 | (permission === PERMISSIONS.SUPER_ADMIN && permissions.superAdmin) || 108 | (permission === PERMISSIONS.SUPER_EDITOR && permissions.superEditor) || 109 | (permission === PERMISSIONS.SUPER_VIEWER && permissions.superViewer) 110 | ) { 111 | return successHandler(); 112 | } 113 | 114 | if ( 115 | (permission === PERMISSIONS.ORG_ADMIN && 116 | permissions.orgAdmin.length > 0 && 117 | id && 118 | permissions.orgAdmin.includes(id)) || 119 | (permission === PERMISSIONS.ORG_EDITOR && 120 | permissions.orgEditor.length > 0 && 121 | id && 122 | permissions.orgEditor.includes(id)) || 123 | (permission === PERMISSIONS.SUPER_VIEWER && 124 | permissions.orgViewer.length > 0 && 125 | id && 126 | permissions.orgViewer.includes(id)) 127 | ) { 128 | return successHandler(); 129 | } 130 | } 131 | 132 | return errorHandler(ERRORS.FORBIDDEN); 133 | } catch (error) { 134 | // eslint-disable-next-line no-console 135 | console.error(error); 136 | return errorHandler(ERRORS.FORBIDDEN); 137 | } 138 | }; 139 | 140 | export const checkRestPermissions = 141 | ( 142 | next: CustomNextFunction, 143 | requiredPermissions?: PERMISSIONS[], 144 | id?: string, 145 | ) => 146 | async (req: Request, res: Response) => { 147 | const successHandler = () => next(req, res); 148 | const errorHandler = restErrorHandler(res); 149 | 150 | return checkPermissions({ 151 | req, 152 | successHandler, 153 | errorHandler, 154 | requiredPermissions, 155 | id, 156 | }); 157 | }; 158 | 159 | export const checkGqlPermissions = ( 160 | context: Context, 161 | requiredPermissions?: PERMISSIONS[], 162 | id?: string, 163 | ): Promise => { 164 | const successHandler = () => true; 165 | 166 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 167 | // @ts-ignore 168 | return checkPermissions({ 169 | req: context.req, 170 | successHandler, 171 | errorHandler: gqlErrorHandler, 172 | requiredPermissions, 173 | id, 174 | }); 175 | }; 176 | -------------------------------------------------------------------------------- /api/src/helpers/auth/index.ts: -------------------------------------------------------------------------------- 1 | export * from './verify'; 2 | -------------------------------------------------------------------------------- /api/src/helpers/auth/verify.ts: -------------------------------------------------------------------------------- 1 | import { firebaseApp } from 'config/firebase'; 2 | 3 | export const verifyUser = async (token: string) => { 4 | const decoded = await firebaseApp.auth().verifyIdToken(token); 5 | return decoded; 6 | }; 7 | -------------------------------------------------------------------------------- /api/src/helpers/errorClass/authError.ts: -------------------------------------------------------------------------------- 1 | import { GraphQLError } from 'graphql'; 2 | 3 | export const AuthenticationError = new GraphQLError( 4 | 'You are not authorized to perform this action.', 5 | { 6 | extensions: { 7 | code: 'FORBIDDEN', 8 | }, 9 | }, 10 | ); 11 | -------------------------------------------------------------------------------- /api/src/helpers/errorClass/index.ts: -------------------------------------------------------------------------------- 1 | export * from './authError'; 2 | -------------------------------------------------------------------------------- /api/src/helpers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './auth'; 2 | export * from './errorClass'; 3 | -------------------------------------------------------------------------------- /api/src/index.ts: -------------------------------------------------------------------------------- 1 | import 'dotenv/config'; 2 | import 'nexus_generated/nexus-typegen'; 3 | 4 | import { app } from 'rest/server'; 5 | 6 | import { initializeApollo } from '@app/server'; 7 | 8 | initializeApollo(app); 9 | -------------------------------------------------------------------------------- /api/src/prisma/schema.prisma: -------------------------------------------------------------------------------- 1 | // ================== CONFIG START ================== 2 | generator client { 3 | provider = "prisma-client-js" 4 | } 5 | 6 | datasource db { 7 | provider = "mongodb" 8 | url = env("DATABASE_URL") 9 | } 10 | 11 | // ================== CONFIG END ================== 12 | 13 | // ================== ENUMS START ================== 14 | enum GENDER { 15 | MALE 16 | FEMALE 17 | OTHERS 18 | } 19 | 20 | enum STATUS { 21 | ACTIVE 22 | DRAFT 23 | EXPIRED 24 | } 25 | 26 | enum COLLEGE_STATUS { 27 | BLACKLISTED 28 | ALLOWED 29 | OTHER 30 | } 31 | 32 | enum ORG_SUB_TYPE { 33 | TECHNICAL 34 | CULTURAL 35 | SPORTS 36 | HACKATHON 37 | LITERARY 38 | FMS 39 | } 40 | 41 | enum ORG_TYPE { 42 | CLUB 43 | HOSTEL 44 | INSTITUTE 45 | BRANCH 46 | FEST 47 | BRANCH_SEM 48 | MESS 49 | } 50 | 51 | enum REPEAT_TYPE { 52 | SUNDAY 53 | MONDAY 54 | TUESDAY 55 | WEDNESDAY 56 | THURSDAY 57 | FRIDAY 58 | SATURDAY 59 | } 60 | 61 | enum TRANSACTION_TYPE { 62 | REGISTRATION 63 | MERCH 64 | EVENT 65 | } 66 | 67 | // ================== ENUMS END ================== 68 | 69 | // ================== MODELS START ================== 70 | model User { 71 | id String @id @default(auto()) @map("_id") @db.ObjectId 72 | email String @unique 73 | name String? 74 | photo String? 75 | gender GENDER? 76 | dob DateTime? 77 | state String? 78 | city String? 79 | college String? @db.ObjectId 80 | idCard String? 81 | stream String? 82 | mobile String @unique 83 | selfID String? 84 | festID String[] @default([""]) 85 | ca String[] @default([]) 86 | referredBy String? 87 | rollNumber String? 88 | uid String @unique 89 | hasPaid Boolean? 90 | receipt String? 91 | transactionID String? 92 | createdAt DateTime @default(now()) 93 | updatedAt DateTime @updatedAt 94 | hall String? 95 | } 96 | 97 | model Org { 98 | id String @id @default(auto()) @map("_id") @db.ObjectId 99 | name String 100 | description String? 101 | logo String? @unique 102 | coverImg String? 103 | tagline String? 104 | theme String? 105 | festID String? 106 | registrationFee Int? @default(0) 107 | registrations Int? 108 | startDate DateTime? 109 | endDate DateTime? 110 | status STATUS? @default(value: ACTIVE) 111 | collegeStatus COLLEGE_STATUS? @default(value: ALLOWED) 112 | orgSubType ORG_SUB_TYPE? 113 | orgType ORG_TYPE @default(value: INSTITUTE) 114 | locationID String? @db.ObjectId 115 | createdAt DateTime? @default(now()) 116 | updatedAt DateTime? @updatedAt 117 | } 118 | 119 | model Institute { 120 | id String @id @default(auto()) @map("_id") @db.ObjectId 121 | name String 122 | description String 123 | locationID String? @db.ObjectId 124 | registrations Int? 125 | collegeStatus COLLEGE_STATUS? 126 | createdAt DateTime? @default(now()) 127 | updatedAt DateTime? @updatedAt 128 | } 129 | 130 | model Event { 131 | id String @id @default(auto()) @map("_id") @db.ObjectId 132 | name String 133 | subHeading String? 134 | prizeMoney String? 135 | type String? 136 | description String 137 | poster String 138 | rules String? 139 | locationID String? 140 | startDate DateTime 141 | endDate DateTime? 142 | orgID String[] @default([]) @db.ObjectId 143 | orgType ORG_TYPE? 144 | contact String[] @default([]) 145 | pocID String[] @default([]) @db.ObjectId 146 | notes String[] @default([]) 147 | weekly Boolean? @default(false) 148 | repeatDay REPEAT_TYPE? 149 | priority Int? @default(0) 150 | status STATUS? @default(value: DRAFT) 151 | createdAt DateTime @default(now()) 152 | updatedAt DateTime? @updatedAt 153 | } 154 | 155 | model Team { 156 | id String @id @default(auto()) @map("_id") @db.ObjectId 157 | position String? 158 | team String? 159 | userID String @db.ObjectId 160 | orgID String @db.ObjectId 161 | priority Int? @default(0) 162 | createdAt DateTime @default(now()) 163 | updatedAt DateTime @updatedAt 164 | } 165 | 166 | model Transaction { 167 | id String @id @default(auto()) @map("_id") @db.ObjectId 168 | amount Int 169 | userID String @db.ObjectId 170 | transactionID String 171 | type TRANSACTION_TYPE 172 | timestamp DateTime 173 | orgID String @db.ObjectId 174 | comment String? 175 | createdAt DateTime @default(now()) 176 | updatedAt DateTime @updatedAt 177 | } 178 | 179 | model EventRegistration { 180 | id String @id @default(auto()) @map("_id") @db.ObjectId 181 | eventID String @db.ObjectId 182 | userID String @db.ObjectId 183 | createdAt DateTime @default(now()) 184 | updatedAt DateTime @updatedAt 185 | } 186 | 187 | model Story { 188 | id String @id @default(auto()) @map("_id") @db.ObjectId 189 | orgID String @db.ObjectId 190 | image String 191 | linkTo String? 192 | createdAt DateTime @default(now()) 193 | updatedAt DateTime @updatedAt 194 | } 195 | 196 | model Location { 197 | id String @id @default(auto()) @map("_id") @db.ObjectId 198 | name String 199 | description String 200 | lat Float? 201 | long Float? 202 | createdAt DateTime @default(now()) 203 | updatedAt DateTime @updatedAt 204 | } 205 | 206 | model DeveloperInfo { 207 | id String @id @default(auto()) @map("_id") @db.ObjectId 208 | name String 209 | github String @db.ObjectId 210 | createdAt DateTime @default(now()) 211 | updatedAt DateTime @updatedAt 212 | } 213 | 214 | // ================== MODELS END ================== 215 | -------------------------------------------------------------------------------- /api/src/rest/controller/auth/get.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from 'express'; 2 | import { verifyUser } from 'helpers'; 3 | import { Permission } from 'rest/model'; 4 | 5 | export const getUserAuth = async (req: Request, res: Response) => { 6 | if (req.headers && req.headers.authorization) { 7 | const token = req.headers.authorization.split(' ')[1]; 8 | try { 9 | const decodedToken = await verifyUser(token as string); 10 | if (decodedToken) { 11 | const permissions = await Permission.findOne({ uid: decodedToken.uid }); 12 | return res.json({ 13 | authenticated: true, 14 | user: decodedToken, 15 | permissions, 16 | }); 17 | } 18 | } catch (error) { 19 | return res.status(401).json({ authenticated: false, error }); 20 | } 21 | } 22 | return res.status(401).json({ authenticated: false, user: null }); 23 | }; 24 | -------------------------------------------------------------------------------- /api/src/rest/controller/auth/index.ts: -------------------------------------------------------------------------------- 1 | export * from './get'; 2 | export * from './update'; 3 | -------------------------------------------------------------------------------- /api/src/rest/controller/auth/update.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from 'express'; 2 | import { Permission } from 'rest/model'; 3 | 4 | export const updatePermissions = async (req: Request, res: Response) => { 5 | try { 6 | const { 7 | uid, 8 | superAdmin, 9 | superEditor, 10 | superViewer, 11 | orgAdmin, 12 | orgEditor, 13 | orgViewer, 14 | orgID, 15 | remove, 16 | } = req.body; 17 | let permissions; 18 | if (!uid) return res.status(400).json({ error: 'uid is required' }); 19 | if ( 20 | ![undefined, null].includes(superAdmin) || 21 | ![undefined, null].includes(superEditor) || 22 | ![undefined, null].includes(superViewer) 23 | ) { 24 | permissions = await Permission.findOneAndUpdate( 25 | { uid }, 26 | { superAdmin, superEditor, superViewer }, 27 | { upsert: true, runValidators: true, omitUndefined: true, new: true }, 28 | ); 29 | } else if ( 30 | ![undefined, null].includes(orgAdmin) || 31 | ![undefined, null].includes(orgEditor) || 32 | ![undefined, null].includes(orgViewer) 33 | ) { 34 | if (!orgID) return res.status(400).json({ error: 'orgID is required' }); 35 | let updateField; 36 | if (orgAdmin) updateField = 'orgAdmin'; 37 | else if (orgEditor) updateField = 'orgEditor'; 38 | else if (orgViewer) updateField = 'orgViewer'; 39 | if (remove) { 40 | permissions = await Permission.findOneAndUpdate( 41 | { uid }, 42 | { $pull: { [updateField as string]: orgID } }, 43 | { upsert: true, runValidators: true, omitUndefined: true, new: true }, 44 | ); 45 | } else { 46 | permissions = await Permission.findOneAndUpdate( 47 | { uid }, 48 | { $push: { [updateField as string]: orgID } }, 49 | { upsert: true, runValidators: true, omitUndefined: true, new: true }, 50 | ); 51 | } 52 | } 53 | return res.json({ permissions }); 54 | } catch (error) { 55 | return res.status(500).send(error); 56 | } 57 | }; 58 | -------------------------------------------------------------------------------- /api/src/rest/controller/base/event.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from 'express'; 2 | 3 | import { prisma } from '@utils'; 4 | 5 | type Empty = Record; 6 | 7 | export const createEvent = async (req: Request, res: Response) => { 8 | try { 9 | const { 10 | name, 11 | description, 12 | poster, 13 | startDate, 14 | endDate, 15 | priority, 16 | type, 17 | subHeading, 18 | prizeMoney, 19 | contact = [], 20 | } = req.body; 21 | 22 | const event = await prisma.event.create({ 23 | data: { 24 | name, 25 | subHeading, 26 | prizeMoney, 27 | contact, 28 | description, 29 | poster, 30 | locationID: '635e1c662e3082fe09bc498e', 31 | startDate, 32 | endDate, 33 | orgID: '65133eb72c5708eb84bf53d6', 34 | orgType: 'FEST', 35 | priority, 36 | status: 'ACTIVE', 37 | type: type.toUpperCase(), 38 | }, 39 | }); 40 | 41 | return res.status(200).send(event); 42 | } catch (error) { 43 | return res.status(500).send(error); 44 | } 45 | }; 46 | 47 | export const getEvents = async ( 48 | req: Request< 49 | Empty, 50 | Empty, 51 | Empty, 52 | { 53 | type: string; 54 | orgID: string; 55 | } 56 | >, 57 | res: Response, 58 | ) => { 59 | try { 60 | const { type, orgID } = req.query; 61 | 62 | if (!type) { 63 | const events = await prisma.event.findMany({ 64 | where: { 65 | orgID: { 66 | has: orgID, 67 | }, 68 | }, 69 | }); 70 | return res.status(200).send(events); 71 | } 72 | 73 | if ( 74 | ![ 75 | 'TECHNICAL', 76 | 'FLAGSHIP', 77 | 'MAIN', 78 | 'FUN', 79 | 'PRO', 80 | 'EXHIBITIONS', 81 | 'WORKSHOP', 82 | 'GUEST-LECTURES', 83 | 'OTHER', 84 | ].includes(type.toUpperCase()) 85 | ) { 86 | return res.status(400).send('invalid type query parameter value'); 87 | } 88 | 89 | const events = await prisma.event.findMany({ 90 | where: { 91 | AND: [ 92 | { 93 | type: type.toUpperCase(), 94 | orgID: { 95 | has: orgID, 96 | }, 97 | }, 98 | ], 99 | }, 100 | }); 101 | 102 | return res.status(200).send(events); 103 | } catch (error) { 104 | return res.status(500).send('internal server error'); 105 | } 106 | }; 107 | 108 | export const registerUserForEvent = async ( 109 | req: Request, 110 | res: Response, 111 | ) => { 112 | try { 113 | const { userID, eventID } = req.body; 114 | 115 | if (!userID || !eventID) { 116 | return res.status(400).send('userID and eventID are required parameters'); 117 | } 118 | 119 | const existingRegistration = await prisma.eventRegistration.findMany({ 120 | where: { 121 | AND: [{ eventID }, { userID }], 122 | }, 123 | }); 124 | 125 | if (existingRegistration.length > 0) { 126 | return res.status(400).send('user already registered for this event'); 127 | } 128 | 129 | const eventRegistration = await prisma.eventRegistration.create({ 130 | data: { 131 | eventID, 132 | userID, 133 | }, 134 | }); 135 | 136 | return res.status(200).send(eventRegistration); 137 | } catch (error) { 138 | return res.status(500).send('internal server error'); 139 | } 140 | }; 141 | 142 | export const getUserRegistrations = async ( 143 | req: Request, 144 | res: Response, 145 | ) => { 146 | try { 147 | const { userID } = req.query; 148 | 149 | if (!userID) { 150 | return res.status(400).send('userID is a required parameter'); 151 | } 152 | 153 | const registrationIDs = await prisma.eventRegistration.findMany({ 154 | where: { 155 | userID, 156 | }, 157 | }); 158 | 159 | const promiseList = registrationIDs.map(({ eventID }) => 160 | prisma.event.findUnique({ 161 | where: { 162 | id: eventID, 163 | }, 164 | }), 165 | ); 166 | 167 | const registrations = await Promise.all(promiseList); 168 | 169 | return res.status(200).send(registrations); 170 | } catch (error) { 171 | return res.status(500).send('internal server error'); 172 | } 173 | }; 174 | -------------------------------------------------------------------------------- /api/src/rest/controller/base/health.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from 'express'; 2 | 3 | export const healthController = (_: Request, res: Response) => 4 | res.json({ health: 'ok', message: 'Hello from Server' }); 5 | -------------------------------------------------------------------------------- /api/src/rest/controller/base/index.ts: -------------------------------------------------------------------------------- 1 | export * from './health'; 2 | export * from './user'; 3 | export * from './zimbra'; 4 | export * from './event'; 5 | export * from './transaction'; 6 | -------------------------------------------------------------------------------- /api/src/rest/controller/base/transaction.ts: -------------------------------------------------------------------------------- 1 | import { prisma } from '@utils'; 2 | 3 | import { Request, Response } from 'express'; 4 | 5 | type Empty = Record; 6 | 7 | export const getTransaction = ( 8 | req: Request, 9 | res: Response, 10 | ) => { 11 | try { 12 | const { userID } = req.query; 13 | 14 | if (!userID) { 15 | return res.status(400).send('userID is a required parameter'); 16 | } 17 | 18 | const transaction = prisma.transaction.findMany({ 19 | where: { 20 | userID, 21 | }, 22 | }); 23 | 24 | return res.status(200).send(transaction); 25 | } catch (error) { 26 | return res.status(500).send('internal server error'); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /api/src/rest/controller/base/user.ts: -------------------------------------------------------------------------------- 1 | import { prisma } from '@utils'; 2 | 3 | /* eslint-disable consistent-return */ 4 | import { Request, Response } from 'express'; 5 | 6 | export const getUserController = async (req: Request, res: Response) => { 7 | try { 8 | const { uid } = req.query; 9 | 10 | if (!uid) { 11 | return res 12 | .status(400) 13 | .send('Missing Parameter: uid is a required parameter'); 14 | } 15 | 16 | const user = await prisma.user.findUnique({ 17 | where: { 18 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 19 | // @ts-ignore 20 | uid, 21 | }, 22 | }); 23 | 24 | if (!user) { 25 | return res.status(200).send(null); 26 | } 27 | 28 | return res.status(200).send(user); 29 | } catch (error) { 30 | return res.status(500).send('Internal Server Error'); 31 | } 32 | }; 33 | 34 | export const createUserController = async (req: Request, res: Response) => { 35 | try { 36 | const { 37 | name, 38 | email, 39 | gender, 40 | dob, 41 | state, 42 | city, 43 | college, 44 | stream, 45 | mobile, 46 | referredBy, 47 | rollNumber, 48 | uid, 49 | } = req.body; 50 | 51 | if (!email || !uid) { 52 | return res 53 | .status(403) 54 | .send('Missing Parameters: email and UID are required parameters'); 55 | } 56 | 57 | if (email) { 58 | const user = await prisma.user.findUnique({ 59 | where: { 60 | email, 61 | }, 62 | }); 63 | 64 | if (user) { 65 | return res.status(400).send('User with this email already registered'); 66 | } 67 | } 68 | 69 | if (rollNumber) { 70 | const users = await prisma.user.findMany({ 71 | where: { 72 | rollNumber, 73 | }, 74 | }); 75 | 76 | if (users.length > 0) { 77 | return res 78 | .status(400) 79 | .send('User with this roll number already registered'); 80 | } 81 | } 82 | 83 | if (mobile) { 84 | const user = await prisma.user.findUnique({ 85 | where: { 86 | mobile, 87 | }, 88 | }); 89 | 90 | if (user) { 91 | return res.status(400).send('User with this mobile already registered'); 92 | } 93 | } 94 | 95 | const user = await prisma.user.create({ 96 | data: { 97 | email, 98 | uid, 99 | name, 100 | photo: '', 101 | gender, 102 | dob, 103 | state, 104 | city, 105 | college, 106 | stream, 107 | mobile, 108 | referredBy, 109 | rollNumber, 110 | selfID: mobile, 111 | festID: rollNumber ? ['innovision-2023'] : [], 112 | }, 113 | }); 114 | 115 | return res.status(200).send(user); 116 | } catch (error) { 117 | // eslint-disable-next-line no-console 118 | console.error(error); 119 | return res.status(400).send('Internal Server Error'); 120 | } 121 | }; 122 | -------------------------------------------------------------------------------- /api/src/rest/controller/base/zimbra.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import { Request, Response } from 'express'; 3 | 4 | export const zimbraController = async (req: Request, res: Response) => { 5 | const { username, password } = req.query; 6 | if (!username || !password) 7 | return res.status(400).send('Missing username or password'); 8 | try { 9 | await axios.get('https://mail.nitrkl.ac.in/home/~/?auth=sc', { 10 | auth: { 11 | username: `${username}@nitrkl.ac.in`, 12 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 13 | // @ts-ignore 14 | password, 15 | }, 16 | }); 17 | return res.status(401).send('invalid credentials'); 18 | } catch (error) { 19 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 20 | // @ts-ignore 21 | const cookie = error?.response.headers['set-cookie']; 22 | if (cookie) return res.status(200).send('success'); 23 | return res.status(401).send('invalid credentials'); 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /api/src/rest/controller/index.ts: -------------------------------------------------------------------------------- 1 | export * from './base/health'; 2 | export * from './auth'; 3 | export * from './instamojo'; 4 | export * from './base'; 5 | -------------------------------------------------------------------------------- /api/src/rest/controller/instamojo/index.ts: -------------------------------------------------------------------------------- 1 | export * from './payment'; 2 | export * from './webhook'; 3 | -------------------------------------------------------------------------------- /api/src/rest/controller/instamojo/payment.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import { Request, Response } from 'express'; 3 | 4 | import { 5 | INSTAMOJO_BASE_URL, 6 | INSTAMOJO_CLIENT_ID, 7 | INSTAMOJO_CLIENT_SECRET, 8 | } from '@constants'; 9 | 10 | const generateToken = async (): Promise => { 11 | const encodedParams = new URLSearchParams(); 12 | encodedParams.set('grant_type', 'client_credentials'); 13 | encodedParams.set('client_id', INSTAMOJO_CLIENT_ID as string); 14 | encodedParams.set('client_secret', INSTAMOJO_CLIENT_SECRET as string); 15 | 16 | const options = { 17 | method: 'POST', 18 | url: `${INSTAMOJO_BASE_URL}/oauth2/token/`, 19 | headers: { 20 | accept: 'application/json', 21 | 'content-type': 'application/x-www-form-urlencoded', 22 | }, 23 | data: encodedParams, 24 | }; 25 | 26 | const response = await axios.request(options); 27 | return response.data.access_token; 28 | }; 29 | 30 | export const generatePaymentLink = async (req: Request, res: Response) => { 31 | const { amount, purpose, redirectUrl, webhook, buyerName, email, phone } = 32 | req.body; 33 | if (!amount || !purpose || !redirectUrl) 34 | return res.status(400).json({ error: 'Missing Arguments' }); 35 | try { 36 | const token = await generateToken(); 37 | if (!token) 38 | return res.status(500).json({ error: 'Could not generate token' }); 39 | 40 | const encodedParams = new URLSearchParams(); 41 | encodedParams.set('allow_repeated_payments', 'false'); 42 | encodedParams.set('amount', amount); 43 | encodedParams.set('purpose', purpose); 44 | encodedParams.set('redirect_url', redirectUrl); 45 | encodedParams.set('buyer_name', buyerName); 46 | encodedParams.set('email', email); 47 | encodedParams.set('phone', phone); 48 | encodedParams.set('webhook', webhook); 49 | 50 | const options = { 51 | method: 'POST', 52 | url: `${INSTAMOJO_BASE_URL}/v2/payment_requests/`, 53 | headers: { 54 | accept: 'application/json', 55 | Authorization: `Bearer ${token}`, 56 | 'content-type': 'application/x-www-form-urlencoded', 57 | }, 58 | data: encodedParams, 59 | }; 60 | 61 | const paymentLink = await axios.request(options); 62 | 63 | return res.status(200).send(paymentLink.data.longurl); 64 | } catch (error) { 65 | return res.status(500).send(error); 66 | } 67 | }; 68 | -------------------------------------------------------------------------------- /api/src/rest/controller/instamojo/webhook.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase */ 2 | import { Request, Response } from 'express'; 3 | import { prisma } from 'utils/context'; 4 | 5 | export const instaMojowebhook = async (req: Request, res: Response) => { 6 | const { buyer, payment_id, amount, purpose, status } = req.body; 7 | 8 | try { 9 | if (status === 'Credit') { 10 | const user = await prisma.user.update({ 11 | where: { 12 | email: buyer, 13 | }, 14 | data: { 15 | festID: { 16 | push: 'innovision-2023', 17 | }, 18 | }, 19 | }); 20 | 21 | await prisma.transaction.create({ 22 | data: { 23 | amount: parseInt(amount, 10), 24 | userID: user.id, 25 | transactionID: payment_id, 26 | type: 'REGISTRATION', 27 | timestamp: new Date(), 28 | orgID: '65133eb72c5708eb84bf53d6', 29 | comment: purpose, 30 | }, 31 | }); 32 | 33 | return res.status(200).send('ok'); 34 | } 35 | 36 | return res.send(400).send('Not Credit Type'); 37 | } catch (error) { 38 | return res.status(500).send(error); 39 | } 40 | }; 41 | -------------------------------------------------------------------------------- /api/src/rest/index.ts: -------------------------------------------------------------------------------- 1 | export * from './routes'; 2 | -------------------------------------------------------------------------------- /api/src/rest/model/index.ts: -------------------------------------------------------------------------------- 1 | export * from './permissions'; 2 | -------------------------------------------------------------------------------- /api/src/rest/model/permissions.ts: -------------------------------------------------------------------------------- 1 | import { model, Schema } from 'mongoose'; 2 | 3 | interface IPermission { 4 | uid: string; 5 | umid: string; 6 | superAdmin: boolean; 7 | superEditor: boolean; 8 | superViewer: boolean; 9 | orgAdmin: string[]; 10 | orgEditor: string[]; 11 | orgViewer: string[]; 12 | } 13 | 14 | /* 15 | This is an Independent permission collections 16 | 1. uid: user id 17 | 2. umid: user mongo id 18 | 3. super[Admin/Editor/Viewer]: To check if user has super access. 19 | 4. org[Admin/Editor/Viewer]: List of org IDs, to check if user has access to specific org. 20 | */ 21 | const permissionSchema = new Schema( 22 | { 23 | uid: { 24 | type: String, 25 | required: true, 26 | unique: true, 27 | }, 28 | umid: { 29 | type: String, 30 | }, 31 | superAdmin: { 32 | type: Boolean, 33 | default: false, 34 | }, 35 | superEditor: { 36 | type: Boolean, 37 | default: false, 38 | }, 39 | superViewer: { 40 | type: Boolean, 41 | default: false, 42 | }, 43 | orgAdmin: { 44 | type: [String], 45 | default: [], 46 | }, 47 | orgEditor: { 48 | type: [String], 49 | default: [], 50 | }, 51 | orgViewer: { 52 | type: [String], 53 | default: [], 54 | }, 55 | }, 56 | { timestamps: true }, 57 | ); 58 | 59 | export const Permission = model('Permission', permissionSchema); 60 | -------------------------------------------------------------------------------- /api/src/rest/routes/auth.ts: -------------------------------------------------------------------------------- 1 | import { PERMISSIONS } from '@constants'; 2 | 3 | import express from 'express'; 4 | import { checkRestPermissions } from 'helpers/auth/checkPermissions'; 5 | import { getUserAuth, updatePermissions } from 'rest/controller'; 6 | 7 | export const authRouter = express.Router(); 8 | 9 | authRouter.get('/', getUserAuth); 10 | authRouter.post( 11 | '/', 12 | checkRestPermissions(updatePermissions, [PERMISSIONS.SUPER_ADMIN]), 13 | // checkRestPermissions(updatePermissions, []), 14 | ); 15 | -------------------------------------------------------------------------------- /api/src/rest/routes/health.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/ban-ts-comment */ 2 | import express from 'express'; 3 | import { checkRestPermissions } from 'helpers/auth/checkPermissions'; 4 | import { 5 | createEvent, 6 | createUserController, 7 | getEvents, 8 | getTransaction, 9 | getUserController, 10 | getUserRegistrations, 11 | healthController, 12 | registerUserForEvent, 13 | zimbraController, 14 | } from 'rest/controller'; 15 | 16 | export const healthRouter = express.Router(); 17 | 18 | healthRouter.get('/', healthController); 19 | 20 | healthRouter.get('/zimbra-login', zimbraController); 21 | 22 | healthRouter.get('/user', checkRestPermissions(getUserController, [])); 23 | 24 | healthRouter.post('/user', checkRestPermissions(createUserController, [])); 25 | 26 | healthRouter.get( 27 | '/user/registration', 28 | // @ts-ignore 29 | checkRestPermissions(getUserRegistrations, []), 30 | ); 31 | 32 | healthRouter.post( 33 | '/user/registration', 34 | checkRestPermissions(registerUserForEvent, []), 35 | ); 36 | 37 | // @ts-ignore 38 | healthRouter.get('/user/transaction', checkRestPermissions(getTransaction, [])); 39 | 40 | healthRouter.get('/events', getEvents); 41 | 42 | healthRouter.post('/events/create', checkRestPermissions(createEvent, [])); 43 | -------------------------------------------------------------------------------- /api/src/rest/routes/index.ts: -------------------------------------------------------------------------------- 1 | export * from './health'; 2 | export * from './instamojo'; 3 | -------------------------------------------------------------------------------- /api/src/rest/routes/instamojo.ts: -------------------------------------------------------------------------------- 1 | import express from 'express'; 2 | import { checkRestPermissions } from 'helpers/auth/checkPermissions'; 3 | import { generatePaymentLink, instaMojowebhook } from 'rest/controller'; 4 | 5 | export const paymentRouter = express.Router(); 6 | 7 | paymentRouter.post('/instamojo', checkRestPermissions(generatePaymentLink, [])); 8 | paymentRouter.post('/webhook', instaMojowebhook); 9 | -------------------------------------------------------------------------------- /api/src/rest/server.ts: -------------------------------------------------------------------------------- 1 | import cors from 'cors'; 2 | import express from 'express'; 3 | 4 | import { mongoAuthDb } from '@config'; 5 | import { ALLOWED_CLIENT_URL } from '@constants'; 6 | 7 | import { healthRouter, paymentRouter } from './routes'; 8 | import { authRouter } from './routes/auth'; 9 | 10 | export const app = express(); 11 | 12 | const corsOptions = { 13 | origin(origin: any, callback: any) { 14 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 15 | // @ts-ignore 16 | if (ALLOWED_CLIENT_URL.indexOf(origin) !== -1 || !origin) { 17 | callback(null, true); 18 | } else { 19 | callback(new Error('Not allowed by CORS')); 20 | } 21 | }, 22 | }; 23 | 24 | app.use(cors(corsOptions)); 25 | 26 | app.use(express.json()); 27 | 28 | app.use(express.urlencoded({ extended: true })); 29 | 30 | app.use('/', healthRouter); 31 | 32 | app.use('/auth', authRouter); 33 | 34 | app.use('/payment', paymentRouter); 35 | 36 | mongoAuthDb(); 37 | -------------------------------------------------------------------------------- /api/src/types/env.d.ts: -------------------------------------------------------------------------------- 1 | declare global { 2 | namespace NodeJS { 3 | interface ProcessEnv { 4 | PORT: number; 5 | } 6 | } 7 | } 8 | 9 | // If this file has no import/export statements (i.e. is a script) 10 | // convert it into a module by adding an empty export statement. 11 | export {}; 12 | -------------------------------------------------------------------------------- /api/src/types/modules.d.ts: -------------------------------------------------------------------------------- 1 | declare module '@.*'; 2 | -------------------------------------------------------------------------------- /api/src/utils/context.ts: -------------------------------------------------------------------------------- 1 | import { Request } from 'express'; 2 | 3 | import { PrismaClient } from '@prisma/client'; 4 | 5 | export const prisma = new PrismaClient(); 6 | 7 | export interface Context { 8 | prisma: PrismaClient; 9 | req: Request; 10 | } 11 | 12 | export const context = async ({ req }: { req: Request }): Promise => ({ 13 | prisma, 14 | req, 15 | }); 16 | -------------------------------------------------------------------------------- /api/src/utils/getUnique.ts: -------------------------------------------------------------------------------- 1 | function onlyUnique(value: unknown, index: number, self: unknown[]) { 2 | return self.indexOf(value) === index; 3 | } 4 | 5 | export const getUnique = (arr: unknown[]): unknown[] => arr.filter(onlyUnique); 6 | -------------------------------------------------------------------------------- /api/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './context'; 2 | -------------------------------------------------------------------------------- /api/tsconfig.eslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": [ 4 | // repeated from base config's "include" setting 5 | "src/**/*.ts", 6 | "src/types/**/*.d.ts", 7 | 8 | // these are the eslint-only inclusions 9 | ".eslintrc" 10 | ], 11 | "exclude": ["node_modules"] 12 | } 13 | -------------------------------------------------------------------------------- /api/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Language and Environment */ 4 | "target": "es2016", 5 | "lib": ["dom", "es6", "es2017", "esnext.asynciterable"], 6 | "experimentalDecorators": true, 7 | "emitDecoratorMetadata": true, 8 | 9 | /* Modules */ 10 | "module": "commonjs", 11 | "moduleResolution": "node", 12 | "baseUrl": "./src/", 13 | "paths": { 14 | "@config": ["config"], 15 | "@constants": ["constants"], 16 | "@types": ["types"], 17 | "@utils": ["utils"], 18 | "@nexus/*": ["nexus_generated/*"], 19 | "@app/*": ["apollo/*"], 20 | "*": ["*"] 21 | }, 22 | "resolveJsonModule": true, 23 | "sourceMap": true, 24 | "outDir": "./dist", 25 | "removeComments": true, 26 | "allowSyntheticDefaultImports": true, 27 | "esModuleInterop": true, 28 | "forceConsistentCasingInFileNames": true, 29 | 30 | /* Type Checking */ 31 | "strict": true, 32 | "noImplicitAny": true, 33 | "strictNullChecks": true, 34 | "strictFunctionTypes": true, 35 | "noImplicitThis": true, 36 | "noUnusedLocals": true, 37 | "noUnusedParameters": true, 38 | "noImplicitReturns": true, 39 | "noFallthroughCasesInSwitch": true, 40 | 41 | /* Completeness */ 42 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 43 | }, 44 | "include": ["./src/**/*.ts", "./src/types/**/*.d.ts"], 45 | "exclude": ["node_modules", "dist", "./src/**/*.prisma"] 46 | } 47 | --------------------------------------------------------------------------------