UBERF-9606: Limit a number of workspaces per user (#8192) (#8199)

This commit is contained in:
Andrey Sobolev
2025-03-11 21:00:06 +07:00
committed by GitHub
parent cdce9db2c3
commit 633e3d8fa1
18 changed files with 44 additions and 17 deletions
+1
View File
@@ -90,6 +90,7 @@ services:
- SERVER_SECRET=secret
- ADMIN_EMAILS=admin
- STATS_URL=http://huly.local:4900
- WORKSPACE_LIMIT_PER_USER=10000
# - DB_URL=postgresql://root@huly.local:26257/defaultdb?sslmode=disable
- DB_URL=${MONGO_URL}
# - DB_NS=account-2
+1 -1
View File
@@ -74,7 +74,7 @@ const devProxy = {
const devProxyTest = {
'/account': {
target: 'http://localhost:3003',
target: 'http://huly.local:3003',
changeOrigin: true,
pathRewrite: { '^/account': '' },
logLevel: 'debug'
+2 -1
View File
@@ -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..."
}
}
+2 -1
View File
@@ -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..."
}
}
+2 -1
View File
@@ -18,6 +18,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..."
}
}
+2 -1
View File
@@ -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..."
}
}
+2 -1
View File
@@ -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..."
}
}
+2 -1
View File
@@ -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..."
}
}
+2 -1
View File
@@ -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..."
}
}
+2 -1
View File
@@ -19,6 +19,7 @@
"AccountAlreadyConfirmed": "Аккаунт уже подтвержден",
"WorkspaceAlreadyExists": "Рабочее пространство уже существует",
"InvalidOtp": "Неверный код",
"InviteNotFound": "Приглашение с email:{email} не найдено."
"InviteNotFound": "Приглашение с email:{email} не найдено.",
"WorkspaceLimitReached": "Вы достигли лимита рабочих пространств. Свяжитесь с нами..."
}
}
+2 -1
View File
@@ -19,6 +19,7 @@
"AccountAlreadyConfirmed": "账户已确认",
"WorkspaceAlreadyExists": "工作区已存在",
"InvalidOtp": "无效的代码",
"InviteNotFound": "未找到 id 为 {email} 的邀请。"
"InviteNotFound": "未找到 id 为 {email} 的邀请。",
"WorkspaceLimitReached": "您已达到工作区限制。请联系我们..."
}
}
+1
View File
@@ -159,6 +159,7 @@ export default plugin(platformId, {
AccountAlreadyExists: '' as StatusCode,
WorkspaceAlreadyExists: '' as StatusCode<{ workspace: string }>,
WorkspaceRateLimit: '' as StatusCode<{ workspace: string }>,
WorkspaceLimitReached: '' as StatusCode<{ workspace: string }>,
InvalidOtp: '' as StatusCode,
InviteNotFound: '' as StatusCode<{ email: string }>
},
+1 -1
View File
@@ -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",
+1 -1
View File
@@ -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",
+1
View File
@@ -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://huly.local:3334
- STORAGE_CONFIG=${STORAGE_CONFIG}
+18 -5
View File
@@ -101,6 +101,9 @@ import {
// Move to config?
const processingTimeoutMs = 30 * 1000
const workspaceLimitPerUser =
process.env.WORKSPACE_LIMIT_PER_USER != null ? parseInt(process.env.WORKSPACE_LIMIT_PER_USER) : 10
/* =================================== */
/* ============OPERATIONS============= */
/* =================================== */
@@ -353,6 +356,21 @@ export async function createWorkspace (
if (socialId == null) {
throw new PlatformError(new Status(Severity.ERROR, platform.status.AccountNotConfirmed, {}))
}
const person = await db.person.findOne({ uuid: socialId.personUuid })
if (person == null) {
throw new PlatformError(new Status(Severity.ERROR, platform.status.InternalServerError, {}))
}
// Get a list of created workspaces
const created = (await db.workspace.find({ createdBy: socialId.personUuid })).length
// TODO: Add support for per person limit increase
if (created >= workspaceLimitPerUser) {
ctx.warn('created-by-limit', { person: socialId.key, workspace: workspaceName })
throw new PlatformError(
new Status(Severity.ERROR, platform.status.WorkspaceLimitReached, { workspace: workspaceName })
)
}
const { workspaceUuid, workspaceUrl } = await createWorkspaceRecord(ctx, db, branding, workspaceName, account, region)
@@ -360,11 +378,6 @@ export async function createWorkspace (
ctx.info('Creating workspace record done', { workspaceName, region, account: socialId.personUuid })
const person = await db.person.findOne({ uuid: socialId.personUuid })
if (person == null) {
throw new PlatformError(new Status(Severity.ERROR, platform.status.InternalServerError, {}))
}
return {
account,
socialId: socialId.key,
+1
View File
@@ -52,6 +52,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}
+1
View File
@@ -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