diff --git a/app/scenes/Login/components/Notices.tsx b/app/scenes/Login/components/Notices.tsx
index 5b91caf0e..3dd564f85 100644
--- a/app/scenes/Login/components/Notices.tsx
+++ b/app/scenes/Login/components/Notices.tsx
@@ -84,12 +84,18 @@ export default function Notices() {
requesting another.
)}
- {(notice === "suspended" || notice === "user-suspended") && (
+ {notice === "user-suspended" && (
Your account has been suspended. To re-activate your account, please
contact a workspace admin.
)}
+ {notice === "team-suspended" && (
+
+ This workspace has been suspended. Please contact support to restore
+ access.
+
+ )}
{notice === "authentication-provider-disabled" && (
Authentication failed – this login method was disabled by a team
diff --git a/server/migrations/20231123022323-add-suspended-at-teams.js b/server/migrations/20231123022323-add-suspended-at-teams.js
new file mode 100644
index 000000000..d0b4e2e39
--- /dev/null
+++ b/server/migrations/20231123022323-add-suspended-at-teams.js
@@ -0,0 +1,13 @@
+"use strict";
+
+module.exports = {
+ async up(queryInterface, Sequelize) {
+ await queryInterface.addColumn("teams", "suspendedAt", {
+ type: Sequelize.DATE,
+ allowNull: true,
+ });
+ },
+ async down(queryInterface) {
+ await queryInterface.removeColumn("teams", "suspendedAt");
+ },
+};
diff --git a/server/models/Team.ts b/server/models/Team.ts
index 7c46ed606..77d05306b 100644
--- a/server/models/Team.ts
+++ b/server/models/Team.ts
@@ -13,6 +13,7 @@ import {
Table,
Unique,
IsIn,
+ IsDate,
HasMany,
Scopes,
Is,
@@ -151,8 +152,19 @@ class Team extends ParanoidModel {
@Column(DataType.JSONB)
preferences: TeamPreferences | null;
+ @IsDate
+ @Column
+ suspendedAt: Date | null;
+
// getters
+ /**
+ * Returns whether the team has been suspended and is no longer accessible.
+ */
+ get isSuspended(): boolean {
+ return !!this.suspendedAt;
+ }
+
/**
* Returns whether the team has email login enabled. For self-hosted installs
* this also considers whether SMTP connection details have been configured.
diff --git a/server/models/User.ts b/server/models/User.ts
index 913ecb09b..e067f0c2e 100644
--- a/server/models/User.ts
+++ b/server/models/User.ts
@@ -227,7 +227,7 @@ class User extends ParanoidModel {
// getters
get isSuspended(): boolean {
- return !!this.suspendedAt;
+ return !!this.suspendedAt || this.team?.isSuspended;
}
get isInvited() {
diff --git a/server/utils/authentication.ts b/server/utils/authentication.ts
index c9b85fbe2..59961d6f0 100644
--- a/server/utils/authentication.ts
+++ b/server/utils/authentication.ts
@@ -32,8 +32,11 @@ export async function signIn(
service: string,
{ user, team, client, isNewTeam }: AuthenticationResult
) {
+ if (team.isSuspended) {
+ return ctx.redirect("/?notice=team-suspended");
+ }
if (user.isSuspended) {
- return ctx.redirect("/?notice=suspended");
+ return ctx.redirect("/?notice=user-suspended");
}
if (isNewTeam) {
diff --git a/shared/i18n/locales/en_US/translation.json b/shared/i18n/locales/en_US/translation.json
index ec1f8c4ce..dcf73680b 100644
--- a/shared/i18n/locales/en_US/translation.json
+++ b/shared/i18n/locales/en_US/translation.json
@@ -686,6 +686,7 @@
"Authentication failed – you do not have permission to access this workspace.": "Authentication failed – you do not have permission to access this workspace.",
"Sorry, it looks like that sign-in link is no longer valid, please try requesting another.": "Sorry, it looks like that sign-in link is no longer valid, please try requesting another.",
"Your account has been suspended. To re-activate your account, please contact a workspace admin.": "Your account has been suspended. To re-activate your account, please contact a workspace admin.",
+ "This workspace has been suspended. Please contact support to restore access.": "This workspace has been suspended. Please contact support to restore access.",
"Authentication failed – this login method was disabled by a team admin.": "Authentication failed – this login method was disabled by a team admin.",
"The workspace you are trying to join requires an invite before you can create an account.<1>1>Please request an invite from your workspace admin and try again.": "The workspace you are trying to join requires an invite before you can create an account.<1>1>Please request an invite from your workspace admin and try again.",
"Sorry, your domain is not allowed. Please try again with an allowed workspace domain.": "Sorry, your domain is not allowed. Please try again with an allowed workspace domain.",