mirror of
https://github.com/hcengineering/platform.git
synced 2025-05-17 21:12:43 +00:00
UBERF-9606: Limit a number of workspaces per user (#8192)
* UBERF-9606: Limit workspaces per user Signed-off-by: Andrey Sobolev <haiodo@gmail.com> * Revert limit check for system account or admin Signed-off-by: Andrey Sobolev <haiodo@gmail.com> * Fix review comment Signed-off-by: Andrey Sobolev <haiodo@gmail.com> --------- Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
parent
1d9ed50a35
commit
6a51d96abe
@ -85,6 +85,7 @@ services:
|
||||
environment:
|
||||
- ACCOUNT_PORT=3000
|
||||
- SERVER_SECRET=secret
|
||||
- WORKSPACE_LIMIT_PER_USER=10000
|
||||
- STATS_URL=http://host.docker.internal:4900
|
||||
# - DB_URL=postgresql://postgres:example@postgres:5432
|
||||
- DB_URL=${MONGO_URL}
|
||||
|
@ -74,7 +74,7 @@ const devProxy = {
|
||||
|
||||
const devProxyTest = {
|
||||
'/account': {
|
||||
target: 'http://localhost:3003',
|
||||
target: 'http://huly.local:3003',
|
||||
changeOrigin: true,
|
||||
pathRewrite: { '^/account': '' },
|
||||
logLevel: 'debug'
|
||||
|
@ -19,6 +19,7 @@
|
||||
"AccountAlreadyConfirmed": "Účet již byl potvrzen",
|
||||
"WorkspaceAlreadyExists": "Pracovní prostor již existuje",
|
||||
"InvalidOtp": "Neplatný kód",
|
||||
"InviteNotFound": "Pozvánka s email:{email} nebyla nalezena."
|
||||
"InviteNotFound": "Pozvánka s email:{email} nebyla nalezena.",
|
||||
"WorkspaceLimitReached": "Dosáhli jste limitu pracovních prostorů. Kontaktujte nás..."
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
"AccountAlreadyConfirmed": "Konto wurde bereits bestätigt",
|
||||
"WorkspaceAlreadyExists": "Arbeitsbereich existiert bereits",
|
||||
"InvalidOtp": "Ungültiger Code",
|
||||
"InviteNotFound": "Einladung mit E-Mail: {email} nicht gefunden."
|
||||
"InviteNotFound": "Einladung mit E-Mail: {email} nicht gefunden.",
|
||||
"WorkspaceLimitReached": "Sie haben das Arbeitsbereichslimit erreicht. Bitte kontaktieren Sie uns..."
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
"AccountAlreadyConfirmed": "Account already confirmed",
|
||||
"WorkspaceAlreadyExists": "Workspace already exists",
|
||||
"InvalidOtp": "Invalid code",
|
||||
"InviteNotFound": "Invitation with email:{email} not found."
|
||||
"InviteNotFound": "Invitation with email:{email} not found.",
|
||||
"WorkspaceLimitReached": "You have reached the workspace limit. Please contact us..."
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
"AccountAlreadyConfirmed": "La cuenta ya está confirmada",
|
||||
"WorkspaceAlreadyExists": "El espacio de trabajo ya existe",
|
||||
"InvalidOtp": "Código no válido",
|
||||
"InviteNotFound": "No se encontró la invitación con email:{email}."
|
||||
"InviteNotFound": "No se encontró la invitación con email:{email}.",
|
||||
"WorkspaceLimitReached": "Ha alcanzado el límite de espacios de trabajo. Póngase en contacto con nosotros..."
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
"AccountAlreadyConfirmed": "Compte déjà confirmé",
|
||||
"WorkspaceAlreadyExists": "L'espace de travail existe déjà",
|
||||
"InvalidOtp": "Code invalide",
|
||||
"InviteNotFound": "Invitation avec l'email:{email} introuvable."
|
||||
"InviteNotFound": "Invitation avec l'email:{email} introuvable.",
|
||||
"WorkspaceLimitReached": "Vous avez atteint la limite d'espace de travail. Veuillez contacter nous..."
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
"AccountAlreadyConfirmed": "Account già confermato",
|
||||
"WorkspaceAlreadyExists": "Spazio di lavoro già esistente",
|
||||
"InvalidOtp": "Codice non valido",
|
||||
"InviteNotFound": "Invito con email:{email} non trovato."
|
||||
"InviteNotFound": "Invito con email:{email} non trovato.",
|
||||
"WorkspaceLimitReached": "Hai raggiunto il limite di spazi di lavoro. Contattaci..."
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
"AccountAlreadyConfirmed": "Conta já confirmada",
|
||||
"WorkspaceAlreadyExists": "Espaço de trabalho já existe",
|
||||
"InvalidOtp": "Código inválido",
|
||||
"InviteNotFound": "Convite com email:{email} não encontrado."
|
||||
"InviteNotFound": "Convite com email:{email} não encontrado.",
|
||||
"WorkspaceLimitReached": "Você atingiu o limite de espaço de trabalho. Entre em contato conosco..."
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
"AccountAlreadyConfirmed": "Аккаунт уже подтвержден",
|
||||
"WorkspaceAlreadyExists": "Рабочее пространство уже существует",
|
||||
"InvalidOtp": "Неверный код",
|
||||
"InviteNotFound": "Приглашение с email:{email} не найдено."
|
||||
"InviteNotFound": "Приглашение с email:{email} не найдено.",
|
||||
"WorkspaceLimitReached": "Вы достигли лимита рабочих пространств. Свяжитесь с нами..."
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
"AccountAlreadyConfirmed": "账户已确认",
|
||||
"WorkspaceAlreadyExists": "工作区已存在",
|
||||
"InvalidOtp": "无效的代码",
|
||||
"InviteNotFound": "未找到 id 为 {email} 的邀请。"
|
||||
"InviteNotFound": "未找到 id 为 {email} 的邀请。",
|
||||
"WorkspaceLimitReached": "您已达到工作区限制。请联系我们..."
|
||||
}
|
||||
}
|
||||
|
@ -156,6 +156,7 @@ export default plugin(platformId, {
|
||||
AccountAlreadyConfirmed: '' as StatusCode<{ account: string }>,
|
||||
WorkspaceAlreadyExists: '' as StatusCode<{ workspace: string }>,
|
||||
WorkspaceRateLimit: '' as StatusCode<{ workspace: string }>,
|
||||
WorkspaceLimitReached: '' as StatusCode<{ workspace: string }>,
|
||||
InvalidOtp: '' as StatusCode,
|
||||
InviteNotFound: '' as StatusCode<{ email: string }>
|
||||
},
|
||||
|
@ -3,7 +3,7 @@
|
||||
"RequiredField": "Required field {field}",
|
||||
"FieldsDoNotMatch": "{field} don't match {field2}",
|
||||
"ConnectingToServer": "Connecting to server....",
|
||||
"IncorrectValue": "Incorrect value {field}"
|
||||
"IncorrectValue": "Incorrect value {field}"
|
||||
},
|
||||
"string": {
|
||||
"LogIn": "Log In",
|
||||
|
@ -3,7 +3,7 @@
|
||||
"RequiredField": "Campo obligatorio: {field}",
|
||||
"FieldsDoNotMatch": "{field} no coincide con {field2}",
|
||||
"ConnectingToServer": "Conectando al servidor...",
|
||||
"IncorrectValue": "Valor incorrecto para {field}"
|
||||
"IncorrectValue": "Valor incorrecto para {field}"
|
||||
},
|
||||
"string": {
|
||||
"LogIn": "Iniciar sesión",
|
||||
|
@ -17,7 +17,7 @@
|
||||
import { OK, Severity, Status, getEmbeddedLabel } from '@hcengineering/platform'
|
||||
|
||||
import { LoginInfo } from '@hcengineering/login'
|
||||
import { ButtonMenu, DropdownLabels, getCurrentLocation, navigate } from '@hcengineering/ui'
|
||||
import { ButtonMenu, getCurrentLocation, navigate } from '@hcengineering/ui'
|
||||
import { workbenchId } from '@hcengineering/workbench'
|
||||
import { onMount } from 'svelte'
|
||||
import login from '../plugin'
|
||||
|
@ -53,6 +53,7 @@ services:
|
||||
environment:
|
||||
- ACCOUNT_PORT=3003
|
||||
- SERVER_SECRET=secret
|
||||
- WORKSPACE_LIMIT_PER_USER=100
|
||||
- DB_URL=mongodb://mongodb:27018
|
||||
- TRANSACTOR_URL=ws://transactor:3334;ws://host.docker.internal:3334
|
||||
- STORAGE_CONFIG=${STORAGE_CONFIG}
|
||||
|
@ -94,6 +94,10 @@ import {
|
||||
} from './utils'
|
||||
|
||||
import MD5 from 'crypto-js/md5'
|
||||
|
||||
const workspaceLimitPerUser =
|
||||
process.env.WORKSPACE_LIMIT_PER_USER != null ? parseInt(process.env.WORKSPACE_LIMIT_PER_USER) : 10
|
||||
|
||||
function buildGravatarId (email: string): string {
|
||||
return MD5(email.trim().toLowerCase()).toString()
|
||||
}
|
||||
@ -1566,6 +1570,16 @@ export async function createUserWorkspace (
|
||||
throw new PlatformError(new Status(Severity.ERROR, platform.status.AccountNotConfirmed, { account: email }))
|
||||
}
|
||||
|
||||
// Get a list of created workspaces
|
||||
const created = (await db.workspace.find({ createdBy: email })).length
|
||||
|
||||
if (created >= (userAccount.workspaceLimit ?? workspaceLimitPerUser)) {
|
||||
ctx.warn('created-by-limit', { email, workspace: workspaceName, limit: userAccount.workspaceLimit })
|
||||
throw new PlatformError(
|
||||
new Status(Severity.ERROR, platform.status.WorkspaceLimitReached, { workspace: workspaceName })
|
||||
)
|
||||
}
|
||||
|
||||
if (userAccount.lastWorkspace !== undefined && userAccount.admin === false) {
|
||||
if (Date.now() - userAccount.lastWorkspace < 60 * 1000) {
|
||||
throw new PlatformError(
|
||||
|
@ -49,6 +49,8 @@ export interface Account {
|
||||
githubId?: string
|
||||
githubUser?: string
|
||||
openId?: string
|
||||
|
||||
workspaceLimit?: number
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -58,6 +58,7 @@ services:
|
||||
environment:
|
||||
- ACCOUNT_PORT=3003
|
||||
- SERVER_SECRET=secret
|
||||
- WORKSPACE_LIMIT_PER_USER=100
|
||||
- DB_URL=mongodb://mongodb:27018
|
||||
- TRANSACTOR_URL=ws://transactor:3334;ws://localhost:3334
|
||||
- STORAGE_CONFIG=${STORAGE_CONFIG}
|
||||
|
@ -63,6 +63,7 @@ services:
|
||||
- REGION_INFO=|America;europe| # Europe without name will not be available for creation of new workspaces.
|
||||
# - REGION_INFO=|America;europe|Europe
|
||||
- ADMIN_EMAILS=admin
|
||||
- WORKSPACE_LIMIT_PER_USER=100
|
||||
- ACCOUNT_PORT=3003
|
||||
- SERVER_SECRET=secret
|
||||
- DB_URL=mongodb://huly.local:27018
|
||||
|
Loading…
Reference in New Issue
Block a user