diff --git a/.all-contributorsrc b/.all-contributorsrc index e37bacbf9..d69d4da6f 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -42,6 +42,15 @@ "contributions": [ "bug" ] + }, + { + "login": "suhaibaffan", + "name": "Suhaib Affan", + "avatar_url": "https://avatars.githubusercontent.com/u/18115937?v=4", + "profile": "https://github.com/suhaibaffan", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 7, diff --git a/.env.example b/.env.example index 4978f6a78..f07f28c5f 100644 --- a/.env.example +++ b/.env.example @@ -47,3 +47,6 @@ AGENDASH_AUTH_PASSWORD=123123 SIGNUP_DISABLED=false SIGNUP_ALLOWED_DOMAINS= SIGNUP_ALLOWED_EMAILS= + +# API rate limit (points,duration,block duration). +API_RATE_LIMIT=120,60,600 \ No newline at end of file diff --git a/README.md b/README.md index 3c5186476..208d39aab 100644 --- a/README.md +++ b/README.md @@ -69,9 +69,10 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d Ahmed Bouhuolia
Ahmed Bouhuolia

💻 - ElforJani13
ElforJani13

💻 Ameir Abdeldayem
Ameir Abdeldayem

🐛 + ElforJani13
ElforJani13

💻 Lars Scheibling
Lars Scheibling

🐛 + Suhaib Affan
Suhaib Affan

💻 diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index 04c580729..b7e2e1040 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -21,10 +21,16 @@ services: depends_on: - server - webapp + deploy: + restart_policy: + condition: unless-stopped webapp: container_name: bigcapital-webapp image: ghcr.io/bigcapitalhq/webapp:latest + deploy: + restart_policy: + condition: unless-stopped server: container_name: bigcapital-server @@ -37,6 +43,9 @@ services: - mysql - mongo - redis + deploy: + restart_policy: + condition: unless-stopped environment: # Mail - MAIL_HOST=${MAIL_HOST} @@ -93,6 +102,9 @@ services: mysql: container_name: bigcapital-mysql + deploy: + restart_policy: + condition: unless-stopped build: context: ./docker/mariadb environment: @@ -106,7 +118,10 @@ services: - '3306' mongo: - container_name: bigcapital-mongo + container_name: bigcapital-mongo + deploy: + restart_policy: + condition: unless-stopped build: ./docker/mongo expose: - '27017' @@ -115,6 +130,9 @@ services: redis: container_name: bigcapital-redis + deploy: + restart_policy: + condition: unless-stopped build: context: ./docker/redis expose: diff --git a/docker-compose.yml b/docker-compose.yml index 11143c063..9563ae91e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -20,6 +20,9 @@ services: - '3306' ports: - '3306:3306' + deploy: + restart_policy: + condition: unless-stopped mongo: build: ./docker/mongo @@ -29,6 +32,9 @@ services: - mongo:/var/lib/mongodb ports: - '27017:27017' + deploy: + restart_policy: + condition: unless-stopped redis: build: @@ -37,6 +43,9 @@ services: - "6379" volumes: - redis:/data + deploy: + restart_policy: + condition: unless-stopped # Volumes volumes: diff --git a/packages/server/src/config/index.ts b/packages/server/src/config/index.ts index ff1fedb6a..bc6833130 100644 --- a/packages/server/src/config/index.ts +++ b/packages/server/src/config/index.ts @@ -1,9 +1,12 @@ import dotenv from 'dotenv'; import path from 'path'; +import { toInteger } from 'lodash'; import { castCommaListEnvVarToArray, parseBoolean } from '@/utils'; dotenv.config(); +const API_RATE_LIMIT = process.env.API_RATE_LIMIT?.split(',') || []; + module.exports = { /** * Your favorite port @@ -97,7 +100,7 @@ module.exports = { jwtSecret: process.env.JWT_SECRET, /** - * + * */ resetPasswordSeconds: 600, @@ -130,9 +133,9 @@ module.exports = { blockDuration: 60 * 15, }, requests: { - points: 60, - duration: 60, - blockDuration: 60 * 10, + points: API_RATE_LIMIT[0] ? toInteger(API_RATE_LIMIT[0]) : 120, + duration: API_RATE_LIMIT[1] ? toInteger(API_RATE_LIMIT[1]) : 60, + blockDuration: API_RATE_LIMIT[2] ? toInteger(API_RATE_LIMIT[2]) : 60 * 10, }, }, diff --git a/packages/webapp/src/containers/GlobalErrors/GlobalErrors.tsx b/packages/webapp/src/containers/GlobalErrors/GlobalErrors.tsx index 211402c0f..e972733d8 100644 --- a/packages/webapp/src/containers/GlobalErrors/GlobalErrors.tsx +++ b/packages/webapp/src/containers/GlobalErrors/GlobalErrors.tsx @@ -9,6 +9,7 @@ import { compose } from '@/utils'; let toastKeySessionExpired; let toastKeySomethingWrong; +let toastTooManyRequests; function GlobalErrors({ // #withGlobalErrors @@ -41,6 +42,18 @@ function GlobalErrors({ toastKeySomethingWrong, ); } + if (globalErrors.too_many_requests) { + toastTooManyRequests = AppToaster.show( + { + message: intl.get('global_error.too_many_requests'), + intent: Intent.DANGER, + onDismiss: () => { + globalErrorsSet({ too_many_requests: false }); + }, + }, + toastTooManyRequests, + ); + } if (globalErrors.access_denied) { toastKeySomethingWrong = AppToaster.show( { diff --git a/packages/webapp/src/hooks/useRequest.tsx b/packages/webapp/src/hooks/useRequest.tsx index c092f1faf..12635ad0a 100644 --- a/packages/webapp/src/hooks/useRequest.tsx +++ b/packages/webapp/src/hooks/useRequest.tsx @@ -60,6 +60,9 @@ export default function useApiRequest() { if (status === 403) { setGlobalErrors({ access_denied: true }); } + if (status === 429) { + setGlobalErrors({ too_many_requests: true }); + } if (status === 400) { const lockedError = data.errors.find( (error) => error.type === 'TRANSACTIONS_DATE_LOCKED', diff --git a/packages/webapp/src/lang/en/index.json b/packages/webapp/src/lang/en/index.json index 2010d32b1..6fb394354 100644 --- a/packages/webapp/src/lang/en/index.json +++ b/packages/webapp/src/lang/en/index.json @@ -2292,5 +2292,6 @@ "sidebar.projects": "Projects", "sidebar.new_project": "New Project", "sidebar.new_time_entry": "New Time Entry", - "sidebar.project_profitability_summary": "Project Profitability Summary" + "sidebar.project_profitability_summary": "Project Profitability Summary", + "global_error.too_many_requests": "Too many requests" } \ No newline at end of file diff --git a/packages/webapp/src/style/components/BigcapitalLoading.scss b/packages/webapp/src/style/components/BigcapitalLoading.scss index 2375d2a1f..c387b5b13 100644 --- a/packages/webapp/src/style/components/BigcapitalLoading.scss +++ b/packages/webapp/src/style/components/BigcapitalLoading.scss @@ -1,10 +1,12 @@ +@import '@/style/variables.scss'; + .bigcapital-loading { height: 100%; width: 100%; position: fixed; display: flex; background: #fff; - z-index: 999999; + z-index: $zindex-dashboard-splash-screen; .center { width: auto; @@ -18,4 +20,4 @@ opacity: 0.85; display: none; } -} +} \ No newline at end of file diff --git a/packages/webapp/src/style/variables.scss b/packages/webapp/src/style/variables.scss index bea903aa4..21fe0ded6 100644 --- a/packages/webapp/src/style/variables.scss +++ b/packages/webapp/src/style/variables.scss @@ -45,3 +45,7 @@ $form-check-input-checked-color: #fff; $form-check-input-checked-bg-color: $blue1; $form-check-input-checked-bg-image: url("data:image/svg+xml,") !default; $form-check-input-indeterminate-bg-image: url("data:image/svg+xml,") !default; + +// z-indexs +$zindex-dashboard-splash-screen: 39; +$zindex-toast: 40; \ No newline at end of file