chore: Move signup_disabled and form_login_enabled from envs to DB (#39882)
## Description > [!TIP] > _Add a TL;DR when the description is longer than 500 words or extremely technical (helps the content, marketing, and DevRel team)._ > > _Please also include relevant motivation and context. List any dependencies that are required for this change. Add links to Notion, Figma or any other documents that might be relevant to the PR._ /test Settings ### 🔍 Cypress test results <!-- This is an auto-generated comment: Cypress test results --> > [!TIP] > 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉 > Workflow run: <https://github.com/appsmithorg/appsmith/actions/runs/14058953075> > Commit: 80445acc542f201c01a40a09323097a946959e50 > <a href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=14058953075&attempt=1" target="_blank">Cypress dashboard</a>. > Tags: `@tag.Settings` > Spec: > <hr>Tue, 25 Mar 2025 12:19:59 UTC <!-- end of auto-generated comment: Cypress test results --> ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [ ] No <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Organizations now control form login and signup behavior with updated, clearer configuration flags. - **Refactor** - Renamed settings to reflect an enabled state for form login and a disabled state for signup. - Removed deprecated restart functionality and reorganized utility classes for improved maintainability. - **Chores/Tests** - Updated tests and environment examples to align with the new configuration settings and ensure consistent behavior. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
parent
93fdfc967d
commit
73e239b9f8
|
|
@ -83,8 +83,8 @@ describe("Form Login test functionality", function () {
|
||||||
cy.get(adminSettings.formloginButton).click();
|
cy.get(adminSettings.formloginButton).click();
|
||||||
cy.wait(2000);
|
cy.wait(2000);
|
||||||
// disable form signup
|
// disable form signup
|
||||||
cy.get(adminSettings.formLoginDisabled).should("have.value", "on");
|
cy.get(adminSettings.formLoginEnabled).should("have.value", "on");
|
||||||
cy.get(adminSettings.formLoginDisabled).click({ force: true });
|
cy.get(adminSettings.formLoginEnabled).click({ force: true });
|
||||||
cy.wait(2000);
|
cy.wait(2000);
|
||||||
// assert server is restarting
|
// assert server is restarting
|
||||||
cy.get(adminSettings.saveButton).should("be.visible");
|
cy.get(adminSettings.saveButton).should("be.visible");
|
||||||
|
|
@ -109,7 +109,7 @@ describe("Form Login test functionality", function () {
|
||||||
.should("be.visible")
|
.should("be.visible")
|
||||||
.should("contain", "Enable");
|
.should("contain", "Enable");
|
||||||
cy.get(adminSettings.formloginButton).click();
|
cy.get(adminSettings.formloginButton).click();
|
||||||
cy.get(adminSettings.formLoginDisabled).click({ force: true });
|
cy.get(adminSettings.formLoginEnabled).click({ force: true });
|
||||||
cy.wait(2000);
|
cy.wait(2000);
|
||||||
// assert server is restarting
|
// assert server is restarting
|
||||||
cy.get(adminSettings.saveButton).should("be.visible");
|
cy.get(adminSettings.saveButton).should("be.visible");
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,8 @@ export default {
|
||||||
loginWithGoogle: "[data-testid='login-with-Google']",
|
loginWithGoogle: "[data-testid='login-with-Google']",
|
||||||
loginWithGithub: "[data-testid='login-with-Github']",
|
loginWithGithub: "[data-testid='login-with-Github']",
|
||||||
disconnectBtn: "[data-testid='disconnect-service-button']",
|
disconnectBtn: "[data-testid='disconnect-service-button']",
|
||||||
formSignupDisabled: "[data-testid='APPSMITH_SIGNUP_DISABLED']",
|
formSignupDisabled: "[data-testid='isSignupDisabled']",
|
||||||
formLoginDisabled: "[data-testid='APPSMITH_FORM_LOGIN_DISABLED']",
|
formLoginEnabled: "[data-testid='isFormLoginEnabled']",
|
||||||
embedSettings: ".t--admin-settings-APPSMITH_ALLOWED_FRAME_ANCESTORS",
|
embedSettings: ".t--admin-settings-APPSMITH_ALLOWED_FRAME_ANCESTORS",
|
||||||
upgrade: "[data-testid='t--button-upgrade']",
|
upgrade: "[data-testid='t--button-upgrade']",
|
||||||
accessControl: ".t--settings-category-access-control",
|
accessControl: ".t--settings-category-access-control",
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@ export const organizationConfigConnection: string[] = [
|
||||||
"hideWatermark",
|
"hideWatermark",
|
||||||
"userSessionTimeoutInMinutes",
|
"userSessionTimeoutInMinutes",
|
||||||
"isAtomicPushAllowed",
|
"isAtomicPushAllowed",
|
||||||
|
"isFormLoginEnabled",
|
||||||
|
"isSignupDisabled",
|
||||||
];
|
];
|
||||||
|
|
||||||
export const RESTART_POLL_TIMEOUT = 2 * 150 * 1000;
|
export const RESTART_POLL_TIMEOUT = 2 * 150 * 1000;
|
||||||
|
|
|
||||||
|
|
@ -48,13 +48,13 @@ const FormAuth: AdminConfigType = {
|
||||||
canSave: true,
|
canSave: true,
|
||||||
settings: [
|
settings: [
|
||||||
{
|
{
|
||||||
id: "APPSMITH_FORM_LOGIN_DISABLED",
|
id: "isFormLoginEnabled",
|
||||||
category: SettingCategories.FORM_AUTH,
|
category: SettingCategories.FORM_AUTH,
|
||||||
controlType: SettingTypes.TOGGLE,
|
controlType: SettingTypes.TOGGLE,
|
||||||
label: "form login",
|
label: "form login",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "APPSMITH_SIGNUP_DISABLED",
|
id: "isSignupDisabled",
|
||||||
category: SettingCategories.FORM_AUTH,
|
category: SettingCategories.FORM_AUTH,
|
||||||
controlType: SettingTypes.TOGGLE,
|
controlType: SettingTypes.TOGGLE,
|
||||||
label: "Form signup",
|
label: "Form signup",
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,10 @@ export function* updateOrganizationConfigSaga(
|
||||||
"emailVerificationEnabled",
|
"emailVerificationEnabled",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const hasFormLoginSetting = settings.hasOwnProperty("isFormLoginEnabled");
|
||||||
|
const hasSignupDisabledSetting =
|
||||||
|
settings.hasOwnProperty("isSignupDisabled");
|
||||||
|
|
||||||
const response: ApiResponse = yield call(
|
const response: ApiResponse = yield call(
|
||||||
OrganizationApi.updateOrganizationConfig,
|
OrganizationApi.updateOrganizationConfig,
|
||||||
action.payload,
|
action.payload,
|
||||||
|
|
@ -94,6 +98,18 @@ export function* updateOrganizationConfigSaga(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hasFormLoginSetting) {
|
||||||
|
AnalyticsUtil.logEvent("GENERAL_SETTINGS_UPDATE", {
|
||||||
|
enabled: settings["isFormLoginEnabled"],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasSignupDisabledSetting) {
|
||||||
|
AnalyticsUtil.logEvent("GENERAL_SETTINGS_UPDATE", {
|
||||||
|
enabled: settings["isSignupDisabled"],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (hasEmailVerificationSetting) {
|
if (hasEmailVerificationSetting) {
|
||||||
AnalyticsUtil.logEvent("EMAIL_VERIFICATION_SETTING_UPDATE", {
|
AnalyticsUtil.logEvent("EMAIL_VERIFICATION_SETTING_UPDATE", {
|
||||||
enabled: settings["emailVerificationEnabled"],
|
enabled: settings["emailVerificationEnabled"],
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,9 @@ export const getThirdPartyAuths = (state: AppState): string[] =>
|
||||||
export const getIsFormLoginEnabled = (state: AppState): boolean =>
|
export const getIsFormLoginEnabled = (state: AppState): boolean =>
|
||||||
state.organization?.organizationConfiguration?.isFormLoginEnabled ?? true;
|
state.organization?.organizationConfiguration?.isFormLoginEnabled ?? true;
|
||||||
|
|
||||||
|
export const getIsSignupDisabled = (state: AppState): boolean =>
|
||||||
|
state.organization?.organizationConfiguration?.isSignupDisabled ?? false;
|
||||||
|
|
||||||
export const getInstanceId = (state: AppState): string =>
|
export const getInstanceId = (state: AppState): string =>
|
||||||
state.organization?.instanceId;
|
state.organization?.instanceId;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,7 @@ export const saveAllowed = (
|
||||||
socialLoginList.length + (isFormLoginEnabled ? 1 : 0);
|
socialLoginList.length + (isFormLoginEnabled ? 1 : 0);
|
||||||
|
|
||||||
if (connectedMethodsCount === 1) {
|
if (connectedMethodsCount === 1) {
|
||||||
const checkFormLogin =
|
const checkFormLogin = isFormLoginEnabled,
|
||||||
!("APPSMITH_FORM_LOGIN_DISABLED" in settings) && isFormLoginEnabled,
|
|
||||||
checkGoogleAuth =
|
checkGoogleAuth =
|
||||||
settings["APPSMITH_OAUTH2_GOOGLE_CLIENT_ID"] !== "" &&
|
settings["APPSMITH_OAUTH2_GOOGLE_CLIENT_ID"] !== "" &&
|
||||||
socialLoginList.includes("google"),
|
socialLoginList.includes("google"),
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useCallback, useEffect, useMemo } from "react";
|
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
||||||
import { saveSettings } from "ee/actions/settingsAction";
|
import { saveSettings } from "ee/actions/settingsAction";
|
||||||
import { SETTINGS_FORM_NAME } from "ee/constants/forms";
|
import { SETTINGS_FORM_NAME } from "ee/constants/forms";
|
||||||
import { ReduxActionTypes } from "ee/constants/ReduxActionConstants";
|
import { ReduxActionTypes } from "ee/constants/ReduxActionConstants";
|
||||||
|
|
@ -89,6 +89,8 @@ export function SettingsForm(
|
||||||
);
|
);
|
||||||
const isFormLoginEnabled = useSelector(getIsFormLoginEnabled);
|
const isFormLoginEnabled = useSelector(getIsFormLoginEnabled);
|
||||||
const socialLoginList = useSelector(getThirdPartyAuths);
|
const socialLoginList = useSelector(getThirdPartyAuths);
|
||||||
|
const [initialFormLoginEnabled, setInitialFormLoginEnabled] =
|
||||||
|
useState(isFormLoginEnabled);
|
||||||
|
|
||||||
const updatedOrganizationSettings = useMemo(
|
const updatedOrganizationSettings = useMemo(
|
||||||
() => Object.keys(props.settings).filter((s) => isOrganizationConfig(s)),
|
() => Object.keys(props.settings).filter((s) => isOrganizationConfig(s)),
|
||||||
|
|
@ -103,6 +105,11 @@ export function SettingsForm(
|
||||||
!isOrganizationConfig(s.id),
|
!isOrganizationConfig(s.id),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Store the initial value of isFormLoginEnabled on component mount
|
||||||
|
useEffect(() => {
|
||||||
|
setInitialFormLoginEnabled(isFormLoginEnabled);
|
||||||
|
}, [category, subCategory]);
|
||||||
|
|
||||||
const saveChangedSettings = () => {
|
const saveChangedSettings = () => {
|
||||||
const settingsKeyLength = Object.keys(props.settings).length;
|
const settingsKeyLength = Object.keys(props.settings).length;
|
||||||
const isOnlyEnvSettings =
|
const isOnlyEnvSettings =
|
||||||
|
|
@ -151,7 +158,23 @@ export function SettingsForm(
|
||||||
|
|
||||||
const onSave = () => {
|
const onSave = () => {
|
||||||
if (checkMandatoryFileds()) {
|
if (checkMandatoryFileds()) {
|
||||||
if (saveAllowed(props.settings, isFormLoginEnabled, socialLoginList)) {
|
// Use initialFormLoginEnabled instead of the current state value for the check
|
||||||
|
let effectiveFormLoginEnabled = initialFormLoginEnabled;
|
||||||
|
|
||||||
|
// Check if isFormLoginEnabled is being updated in the current form
|
||||||
|
if (props.settings["isFormLoginEnabled"] !== undefined) {
|
||||||
|
// Convert to boolean if it's a string, otherwise use as is since we expect a boolean
|
||||||
|
const settingValue = props.settings["isFormLoginEnabled"];
|
||||||
|
|
||||||
|
effectiveFormLoginEnabled =
|
||||||
|
typeof settingValue === "string"
|
||||||
|
? settingValue === "true"
|
||||||
|
: Boolean(settingValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
saveAllowed(props.settings, effectiveFormLoginEnabled, socialLoginList)
|
||||||
|
) {
|
||||||
AnalyticsUtil.logEvent("ADMIN_SETTINGS_SAVE", {
|
AnalyticsUtil.logEvent("ADMIN_SETTINGS_SAVE", {
|
||||||
method: pageTitle,
|
method: pageTitle,
|
||||||
});
|
});
|
||||||
|
|
@ -224,6 +247,13 @@ export function SettingsForm(
|
||||||
|
|
||||||
useEffect(onClear, [subCategory]);
|
useEffect(onClear, [subCategory]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Reset the initialFormLoginEnabled value when navigating to a different category
|
||||||
|
return () => {
|
||||||
|
setInitialFormLoginEnabled(isFormLoginEnabled);
|
||||||
|
};
|
||||||
|
}, [category, subCategory]);
|
||||||
|
|
||||||
const onReleaseNotesClose = useCallback(() => {
|
const onReleaseNotesClose = useCallback(() => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ReduxActionTypes.TOGGLE_RELEASE_NOTES,
|
type: ReduxActionTypes.TOGGLE_RELEASE_NOTES,
|
||||||
|
|
@ -244,8 +274,9 @@ export function SettingsForm(
|
||||||
// TODO: Fix this the next time the file is edited
|
// TODO: Fix this the next time the file is edited
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const updatedSettings: any = {};
|
const updatedSettings: any = {};
|
||||||
|
// Use the initial value to determine if there are enough login methods
|
||||||
const connectedMethodsCount =
|
const connectedMethodsCount =
|
||||||
socialLoginList.length + (isFormLoginEnabled ? 1 : 0);
|
socialLoginList.length + (initialFormLoginEnabled ? 1 : 0);
|
||||||
|
|
||||||
if (connectedMethodsCount >= 2) {
|
if (connectedMethodsCount >= 2) {
|
||||||
_.forEach(currentSettings, (setting: Setting) => {
|
_.forEach(currentSettings, (setting: Setting) => {
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
package com.appsmith.server.authentication.handlers;
|
package com.appsmith.server.authentication.handlers;
|
||||||
|
|
||||||
import com.appsmith.server.authentication.handlers.ce.AuthenticationSuccessHandlerCE;
|
import com.appsmith.server.authentication.handlers.ce.AuthenticationSuccessHandlerCE;
|
||||||
import com.appsmith.server.helpers.InstanceVariablesHelper;
|
|
||||||
import com.appsmith.server.helpers.RedirectHelper;
|
import com.appsmith.server.helpers.RedirectHelper;
|
||||||
import com.appsmith.server.helpers.WorkspaceServiceHelper;
|
import com.appsmith.server.helpers.WorkspaceServiceHelper;
|
||||||
|
import com.appsmith.server.instanceconfigs.helpers.InstanceVariablesHelper;
|
||||||
import com.appsmith.server.ratelimiting.RateLimitService;
|
import com.appsmith.server.ratelimiting.RateLimitService;
|
||||||
import com.appsmith.server.repositories.UserRepository;
|
import com.appsmith.server.repositories.UserRepository;
|
||||||
import com.appsmith.server.repositories.WorkspaceRepository;
|
import com.appsmith.server.repositories.WorkspaceRepository;
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,9 @@ import com.appsmith.server.domains.LoginSource;
|
||||||
import com.appsmith.server.domains.User;
|
import com.appsmith.server.domains.User;
|
||||||
import com.appsmith.server.domains.Workspace;
|
import com.appsmith.server.domains.Workspace;
|
||||||
import com.appsmith.server.dtos.ResendEmailVerificationDTO;
|
import com.appsmith.server.dtos.ResendEmailVerificationDTO;
|
||||||
import com.appsmith.server.helpers.InstanceVariablesHelper;
|
|
||||||
import com.appsmith.server.helpers.RedirectHelper;
|
import com.appsmith.server.helpers.RedirectHelper;
|
||||||
import com.appsmith.server.helpers.WorkspaceServiceHelper;
|
import com.appsmith.server.helpers.WorkspaceServiceHelper;
|
||||||
|
import com.appsmith.server.instanceconfigs.helpers.InstanceVariablesHelper;
|
||||||
import com.appsmith.server.ratelimiting.RateLimitService;
|
import com.appsmith.server.ratelimiting.RateLimitService;
|
||||||
import com.appsmith.server.repositories.UserRepository;
|
import com.appsmith.server.repositories.UserRepository;
|
||||||
import com.appsmith.server.repositories.WorkspaceRepository;
|
import com.appsmith.server.repositories.WorkspaceRepository;
|
||||||
|
|
@ -103,13 +103,13 @@ public class AuthenticationSuccessHandlerCE implements ServerAuthenticationSucce
|
||||||
return Mono.just(FALSE);
|
return Mono.just(FALSE);
|
||||||
} else {
|
} else {
|
||||||
return emailVerificationEnabledMono.flatMap(emailVerificationEnabled -> {
|
return emailVerificationEnabledMono.flatMap(emailVerificationEnabled -> {
|
||||||
// email verification not enabled at the org
|
// email verification not enabled
|
||||||
if (!TRUE.equals(emailVerificationEnabled)) {
|
if (!TRUE.equals(emailVerificationEnabled)) {
|
||||||
user.setEmailVerificationRequired(FALSE);
|
user.setEmailVerificationRequired(FALSE);
|
||||||
return userRepository.save(user).then(Mono.just(FALSE));
|
return userRepository.save(user).then(Mono.just(FALSE));
|
||||||
} else {
|
} else {
|
||||||
// scenario when at the time of signup, the email verification was disabled at the org
|
// scenario when at the time of signup, the email verification was disabled but later on
|
||||||
// but later on turned on, now when this user logs in, it will not be prompted to verify
|
// turned on, now when this user logs in, it will not be prompted to verify
|
||||||
// as the configuration at time of signup is considered for any user.
|
// as the configuration at time of signup is considered for any user.
|
||||||
// for old users, the login works as expected, without the need to verify
|
// for old users, the login works as expected, without the need to verify
|
||||||
if (!TRUE.equals(user.getEmailVerificationRequired())) {
|
if (!TRUE.equals(user.getEmailVerificationRequired())) {
|
||||||
|
|
|
||||||
|
|
@ -36,9 +36,6 @@ public class CommonConfig {
|
||||||
|
|
||||||
public static final Integer LATEST_INSTANCE_SCHEMA_VERSION = 2;
|
public static final Integer LATEST_INSTANCE_SCHEMA_VERSION = 2;
|
||||||
|
|
||||||
@Setter(AccessLevel.NONE)
|
|
||||||
private boolean isSignupDisabled = false;
|
|
||||||
|
|
||||||
@Setter(AccessLevel.NONE)
|
@Setter(AccessLevel.NONE)
|
||||||
private Set<String> adminEmails = Collections.emptySet();
|
private Set<String> adminEmails = Collections.emptySet();
|
||||||
|
|
||||||
|
|
@ -129,12 +126,6 @@ public class CommonConfig {
|
||||||
adminEmails = Set.of(value.trim().split("\\s*,\\s*"));
|
adminEmails = Set.of(value.trim().split("\\s*,\\s*"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Autowired
|
|
||||||
public void setSignupDisabled(@Value("${signup.disabled}") String value) {
|
|
||||||
// If `true`, then disable signup. If anything else, including empty string, then signups will be enabled.
|
|
||||||
isSignupDisabled = "true".equalsIgnoreCase(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Long getCurrentTimeInstantEpochMilli() {
|
public Long getCurrentTimeInstantEpochMilli() {
|
||||||
return Instant.now().toEpochMilli();
|
return Instant.now().toEpochMilli();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@ public enum EnvVariables {
|
||||||
APPSMITH_MAIL_USERNAME,
|
APPSMITH_MAIL_USERNAME,
|
||||||
APPSMITH_MAIL_PASSWORD,
|
APPSMITH_MAIL_PASSWORD,
|
||||||
APPSMITH_MAIL_SMTP_TLS_ENABLED,
|
APPSMITH_MAIL_SMTP_TLS_ENABLED,
|
||||||
APPSMITH_SIGNUP_DISABLED,
|
|
||||||
APPSMITH_SIGNUP_ALLOWED_DOMAINS,
|
APPSMITH_SIGNUP_ALLOWED_DOMAINS,
|
||||||
APPSMITH_ADMIN_EMAILS,
|
APPSMITH_ADMIN_EMAILS,
|
||||||
APPSMITH_RECAPTCHA_SITE_KEY,
|
APPSMITH_RECAPTCHA_SITE_KEY,
|
||||||
|
|
@ -24,7 +23,6 @@ public enum EnvVariables {
|
||||||
APPSMITH_OAUTH2_GITHUB_CLIENT_ID,
|
APPSMITH_OAUTH2_GITHUB_CLIENT_ID,
|
||||||
APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET,
|
APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET,
|
||||||
APPSMITH_CUSTOM_DOMAIN,
|
APPSMITH_CUSTOM_DOMAIN,
|
||||||
APPSMITH_FORM_LOGIN_DISABLED,
|
|
||||||
APPSMITH_ALLOWED_FRAME_ANCESTORS,
|
APPSMITH_ALLOWED_FRAME_ANCESTORS,
|
||||||
APPSMITH_DISABLE_IFRAME_WIDGET_SANDBOX,
|
APPSMITH_DISABLE_IFRAME_WIDGET_SANDBOX,
|
||||||
APPSMITH_NEW_RELIC_ACCOUNT_ENABLE,
|
APPSMITH_NEW_RELIC_ACCOUNT_ENABLE,
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,6 @@ import org.springframework.data.mongodb.core.mapping.Document;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
import static com.appsmith.external.helpers.StringUtils.dotted;
|
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
@ToString
|
@ToString
|
||||||
|
|
@ -38,8 +36,5 @@ public class Organization extends BaseDomain implements Serializable {
|
||||||
|
|
||||||
// TODO add SSO and other configurations here after migrating from environment variables to database configuration
|
// TODO add SSO and other configurations here after migrating from environment variables to database configuration
|
||||||
|
|
||||||
public static class Fields extends BaseDomain.Fields {
|
public static class Fields extends BaseDomain.Fields {}
|
||||||
public static final String organizationConfiguration_isRestartRequired =
|
|
||||||
dotted(organizationConfiguration, OrganizationConfiguration.Fields.isRestartRequired);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,8 @@ public class OrganizationConfigurationCE implements Serializable {
|
||||||
|
|
||||||
private Boolean isFormLoginEnabled;
|
private Boolean isFormLoginEnabled;
|
||||||
|
|
||||||
|
private Boolean isSignupDisabled;
|
||||||
|
|
||||||
@Transient
|
@Transient
|
||||||
@Deprecated(forRemoval = true, since = "v1.65")
|
@Deprecated(forRemoval = true, since = "v1.65")
|
||||||
private String instanceName;
|
private String instanceName;
|
||||||
|
|
@ -58,10 +60,6 @@ public class OrganizationConfigurationCE implements Serializable {
|
||||||
// 2. Because of grandfathering via cron where organization level feature flags are fetched
|
// 2. Because of grandfathering via cron where organization level feature flags are fetched
|
||||||
Map<FeatureFlagEnum, FeatureMigrationType> featuresWithPendingMigration;
|
Map<FeatureFlagEnum, FeatureMigrationType> featuresWithPendingMigration;
|
||||||
|
|
||||||
// This variable is used to indicate if the server needs to be restarted after the migration based on feature flags
|
|
||||||
// is complete.
|
|
||||||
Boolean isRestartRequired;
|
|
||||||
|
|
||||||
Boolean isStrongPasswordPolicyEnabled;
|
Boolean isStrongPasswordPolicyEnabled;
|
||||||
|
|
||||||
private Boolean isAtomicPushAllowed = false;
|
private Boolean isAtomicPushAllowed = false;
|
||||||
|
|
@ -84,6 +82,7 @@ public class OrganizationConfigurationCE implements Serializable {
|
||||||
googleMapsKey = ObjectUtils.defaultIfNull(organizationConfiguration.getGoogleMapsKey(), googleMapsKey);
|
googleMapsKey = ObjectUtils.defaultIfNull(organizationConfiguration.getGoogleMapsKey(), googleMapsKey);
|
||||||
isFormLoginEnabled =
|
isFormLoginEnabled =
|
||||||
ObjectUtils.defaultIfNull(organizationConfiguration.getIsFormLoginEnabled(), isFormLoginEnabled);
|
ObjectUtils.defaultIfNull(organizationConfiguration.getIsFormLoginEnabled(), isFormLoginEnabled);
|
||||||
|
isSignupDisabled = ObjectUtils.defaultIfNull(organizationConfiguration.getIsSignupDisabled(), isSignupDisabled);
|
||||||
instanceName = ObjectUtils.defaultIfNull(organizationConfiguration.getInstanceName(), instanceName);
|
instanceName = ObjectUtils.defaultIfNull(organizationConfiguration.getInstanceName(), instanceName);
|
||||||
emailVerificationEnabled = ObjectUtils.defaultIfNull(
|
emailVerificationEnabled = ObjectUtils.defaultIfNull(
|
||||||
organizationConfiguration.getEmailVerificationEnabled(), emailVerificationEnabled);
|
organizationConfiguration.getEmailVerificationEnabled(), emailVerificationEnabled);
|
||||||
|
|
|
||||||
|
|
@ -912,9 +912,9 @@ public enum AppsmithError {
|
||||||
ErrorType.INTERNAL_ERROR,
|
ErrorType.INTERNAL_ERROR,
|
||||||
null),
|
null),
|
||||||
|
|
||||||
ORGANIZATION_EMAIL_VERIFICATION_NOT_ENABLED(
|
EMAIL_VERIFICATION_NOT_ENABLED(
|
||||||
400,
|
400,
|
||||||
AppsmithErrorCode.ORGANIZATION_EMAIL_VERIFICATION_NOT_ENABLED.getCode(),
|
AppsmithErrorCode.EMAIL_VERIFICATION_NOT_ENABLED.getCode(),
|
||||||
"Email verification is not enabled. Please contact your admin",
|
"Email verification is not enabled. Please contact your admin",
|
||||||
AppsmithErrorAction.DEFAULT,
|
AppsmithErrorAction.DEFAULT,
|
||||||
"Email verification not enabled",
|
"Email verification not enabled",
|
||||||
|
|
|
||||||
|
|
@ -123,7 +123,7 @@ public enum AppsmithErrorCode {
|
||||||
USER_EMAIL_ALREADY_VERIFIED("AE-EMV-4095", "User email already verified"),
|
USER_EMAIL_ALREADY_VERIFIED("AE-EMV-4095", "User email already verified"),
|
||||||
|
|
||||||
EMAIL_VERIFICATION_TOKEN_EXPIRED("AE-EMV-4096", "Email Verification Token expired"),
|
EMAIL_VERIFICATION_TOKEN_EXPIRED("AE-EMV-4096", "Email Verification Token expired"),
|
||||||
ORGANIZATION_EMAIL_VERIFICATION_NOT_ENABLED("AE-EMV-4097", "Email Verification not enabled"),
|
EMAIL_VERIFICATION_NOT_ENABLED("AE-EMV-4097", "Email Verification not enabled"),
|
||||||
|
|
||||||
INVALID_EMAIL_VERIFICATION("AE-EMV-4098", "Invalid email verification request"),
|
INVALID_EMAIL_VERIFICATION("AE-EMV-4098", "Invalid email verification request"),
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
package com.appsmith.server.instanceconfigs.constants;
|
||||||
|
|
||||||
|
public interface AllowedInstanceVariables extends AllowedInstanceVariablesCE {}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
package com.appsmith.server.instanceconfigs.constants;
|
||||||
|
|
||||||
|
public interface AllowedInstanceVariablesCE {
|
||||||
|
String INSTANCE_NAME = "instanceName";
|
||||||
|
String EMAIL_VERIFICATION_ENABLED = "emailVerificationEnabled";
|
||||||
|
String GOOGLE_MAPS_KEY = "googleMapsKey";
|
||||||
|
}
|
||||||
|
|
@ -1,17 +1,12 @@
|
||||||
package com.appsmith.server.helpers;
|
package com.appsmith.server.instanceconfigs.helpers;
|
||||||
|
|
||||||
import com.appsmith.server.helpers.ce.InstanceVariablesHelperCE;
|
|
||||||
import com.appsmith.server.services.ConfigService;
|
import com.appsmith.server.services.ConfigService;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper class for accessing instance variables from the instance config
|
|
||||||
*/
|
|
||||||
@Component
|
@Component
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class InstanceVariablesHelper extends InstanceVariablesHelperCE {
|
public class InstanceVariablesHelper extends InstanceVariablesHelperCE {
|
||||||
|
|
||||||
public InstanceVariablesHelper(ConfigService configService) {
|
public InstanceVariablesHelper(ConfigService configService) {
|
||||||
super(configService);
|
super(configService);
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.appsmith.server.helpers.ce;
|
package com.appsmith.server.instanceconfigs.helpers;
|
||||||
|
|
||||||
import com.appsmith.server.constants.Appsmith;
|
import com.appsmith.server.constants.Appsmith;
|
||||||
import com.appsmith.server.domains.OrganizationConfiguration;
|
import com.appsmith.server.domains.OrganizationConfiguration;
|
||||||
|
|
@ -10,6 +10,10 @@ import reactor.core.publisher.Mono;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static com.appsmith.server.instanceconfigs.constants.AllowedInstanceVariables.EMAIL_VERIFICATION_ENABLED;
|
||||||
|
import static com.appsmith.server.instanceconfigs.constants.AllowedInstanceVariables.GOOGLE_MAPS_KEY;
|
||||||
|
import static com.appsmith.server.instanceconfigs.constants.AllowedInstanceVariables.INSTANCE_NAME;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class for accessing instance variables from the instance config
|
* Helper class for accessing instance variables from the instance config
|
||||||
*/
|
*/
|
||||||
|
|
@ -23,7 +27,7 @@ public class InstanceVariablesHelperCE {
|
||||||
*/
|
*/
|
||||||
public Mono<String> getInstanceName() {
|
public Mono<String> getInstanceName() {
|
||||||
return configService.getInstanceVariables().map(instanceVariables -> {
|
return configService.getInstanceVariables().map(instanceVariables -> {
|
||||||
Object value = instanceVariables.getOrDefault("instanceName", Appsmith.DEFAULT_INSTANCE_NAME);
|
Object value = instanceVariables.getOrDefault(INSTANCE_NAME, Appsmith.DEFAULT_INSTANCE_NAME);
|
||||||
return value != null ? value.toString() : Appsmith.DEFAULT_INSTANCE_NAME;
|
return value != null ? value.toString() : Appsmith.DEFAULT_INSTANCE_NAME;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -34,7 +38,7 @@ public class InstanceVariablesHelperCE {
|
||||||
*/
|
*/
|
||||||
public Mono<Boolean> isEmailVerificationEnabled() {
|
public Mono<Boolean> isEmailVerificationEnabled() {
|
||||||
return configService.getInstanceVariables().map(instanceVariables -> {
|
return configService.getInstanceVariables().map(instanceVariables -> {
|
||||||
Object value = instanceVariables.getOrDefault("emailVerificationEnabled", false);
|
Object value = instanceVariables.getOrDefault(EMAIL_VERIFICATION_ENABLED, false);
|
||||||
if (value instanceof Boolean) {
|
if (value instanceof Boolean) {
|
||||||
return (Boolean) value;
|
return (Boolean) value;
|
||||||
}
|
}
|
||||||
|
|
@ -48,24 +52,24 @@ public class InstanceVariablesHelperCE {
|
||||||
*/
|
*/
|
||||||
public Mono<String> getGoogleMapsKey() {
|
public Mono<String> getGoogleMapsKey() {
|
||||||
return configService.getInstanceVariables().map(instanceVariables -> {
|
return configService.getInstanceVariables().map(instanceVariables -> {
|
||||||
Object value = instanceVariables.getOrDefault("googleMapsKey", "");
|
Object value = instanceVariables.getOrDefault(GOOGLE_MAPS_KEY, "");
|
||||||
return value != null ? value.toString() : "";
|
return value != null ? value.toString() : "";
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public OrganizationConfiguration populateOrgConfigWithInstanceVariables(
|
public OrganizationConfiguration populateOrgConfigWithInstanceVariables(
|
||||||
Map<String, Object> instanceVariables, OrganizationConfiguration organizationConfiguration) {
|
Map<String, Object> instanceVariables, OrganizationConfiguration organizationConfiguration) {
|
||||||
Object value = instanceVariables.getOrDefault("instanceName", Appsmith.DEFAULT_INSTANCE_NAME);
|
Object value = instanceVariables.getOrDefault(INSTANCE_NAME, Appsmith.DEFAULT_INSTANCE_NAME);
|
||||||
organizationConfiguration.setInstanceName(value != null ? value.toString() : Appsmith.DEFAULT_INSTANCE_NAME);
|
organizationConfiguration.setInstanceName(value != null ? value.toString() : Appsmith.DEFAULT_INSTANCE_NAME);
|
||||||
|
|
||||||
value = instanceVariables.getOrDefault("emailVerificationEnabled", false);
|
value = instanceVariables.getOrDefault(EMAIL_VERIFICATION_ENABLED, false);
|
||||||
if (value instanceof Boolean) {
|
if (value instanceof Boolean) {
|
||||||
organizationConfiguration.setEmailVerificationEnabled((Boolean) value);
|
organizationConfiguration.setEmailVerificationEnabled((Boolean) value);
|
||||||
} else {
|
} else {
|
||||||
organizationConfiguration.setEmailVerificationEnabled(Boolean.FALSE);
|
organizationConfiguration.setEmailVerificationEnabled(Boolean.FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
value = instanceVariables.getOrDefault("googleMapsKey", "");
|
value = instanceVariables.getOrDefault(GOOGLE_MAPS_KEY, "");
|
||||||
organizationConfiguration.setGoogleMapsKey(value != null ? value.toString() : "");
|
organizationConfiguration.setGoogleMapsKey(value != null ? value.toString() : "");
|
||||||
|
|
||||||
return organizationConfiguration;
|
return organizationConfiguration;
|
||||||
|
|
@ -85,13 +89,13 @@ public class InstanceVariablesHelperCE {
|
||||||
protected Map<String, Object> updateAllowedInstanceVariables(OrganizationConfiguration orgConfig) {
|
protected Map<String, Object> updateAllowedInstanceVariables(OrganizationConfiguration orgConfig) {
|
||||||
Map<String, Object> instanceVariables = new HashMap<>();
|
Map<String, Object> instanceVariables = new HashMap<>();
|
||||||
if (StringUtils.hasLength(orgConfig.getInstanceName())) {
|
if (StringUtils.hasLength(orgConfig.getInstanceName())) {
|
||||||
instanceVariables.put("instanceName", orgConfig.getInstanceName());
|
instanceVariables.put(INSTANCE_NAME, orgConfig.getInstanceName());
|
||||||
}
|
}
|
||||||
if (orgConfig.getEmailVerificationEnabled() != null) {
|
if (orgConfig.getEmailVerificationEnabled() != null) {
|
||||||
instanceVariables.put("emailVerificationEnabled", orgConfig.getEmailVerificationEnabled());
|
instanceVariables.put(EMAIL_VERIFICATION_ENABLED, orgConfig.getEmailVerificationEnabled());
|
||||||
}
|
}
|
||||||
if (StringUtils.hasLength(orgConfig.getGoogleMapsKey())) {
|
if (StringUtils.hasLength(orgConfig.getGoogleMapsKey())) {
|
||||||
instanceVariables.put("googleMapsKey", orgConfig.getGoogleMapsKey());
|
instanceVariables.put(GOOGLE_MAPS_KEY, orgConfig.getGoogleMapsKey());
|
||||||
}
|
}
|
||||||
return instanceVariables;
|
return instanceVariables;
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
package com.appsmith.server.migrations.db.ce;
|
||||||
|
|
||||||
|
import com.appsmith.server.configurations.CommonConfig;
|
||||||
|
import com.appsmith.server.domains.Organization;
|
||||||
|
import io.mongock.api.annotations.ChangeUnit;
|
||||||
|
import io.mongock.api.annotations.Execution;
|
||||||
|
import io.mongock.api.annotations.RollbackExecution;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||||
|
import org.springframework.data.mongodb.core.query.Query;
|
||||||
|
import org.springframework.data.mongodb.core.query.Update;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import static com.appsmith.server.migrations.db.ce.Migration021MoveGoogleMapsKeyToTenantConfiguration.commentEnvInFile;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@ChangeUnit(order = "071", id = "move-form-login-disabled-to-organization-configuration")
|
||||||
|
public class Migration071MoveFormLoginDisabledToOrganizationConfiguration {
|
||||||
|
private final MongoTemplate mongoTemplate;
|
||||||
|
private final CommonConfig commonConfig;
|
||||||
|
|
||||||
|
@RollbackExecution
|
||||||
|
public void rollbackExecution() {}
|
||||||
|
|
||||||
|
@Execution
|
||||||
|
public void executeMigration() throws IOException {
|
||||||
|
final String envName = "APPSMITH_FORM_LOGIN_DISABLED";
|
||||||
|
final String formLoginDisabledValue = System.getenv(envName);
|
||||||
|
|
||||||
|
// Default to false if the environment variable is not present or empty
|
||||||
|
boolean formLoginDisabled = false;
|
||||||
|
|
||||||
|
if (StringUtils.isNotEmpty(formLoginDisabledValue)) {
|
||||||
|
// Convert the string value to a boolean if env is present
|
||||||
|
formLoginDisabled = Boolean.parseBoolean(formLoginDisabledValue);
|
||||||
|
// Comment out the environment variable in the .env file
|
||||||
|
commentEnvInFile(envName, commonConfig.getEnvFilePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update all organizations to set the form login disabled configuration
|
||||||
|
// This happens whether the env var is present or not, defaulting to false
|
||||||
|
mongoTemplate.updateMulti(
|
||||||
|
new Query(),
|
||||||
|
new Update().set("organizationConfiguration.isFormLoginEnabled", !formLoginDisabled),
|
||||||
|
Organization.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
package com.appsmith.server.migrations.db.ce;
|
||||||
|
|
||||||
|
import com.appsmith.server.configurations.CommonConfig;
|
||||||
|
import com.appsmith.server.domains.Organization;
|
||||||
|
import io.mongock.api.annotations.ChangeUnit;
|
||||||
|
import io.mongock.api.annotations.Execution;
|
||||||
|
import io.mongock.api.annotations.RollbackExecution;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||||
|
import org.springframework.data.mongodb.core.query.Query;
|
||||||
|
import org.springframework.data.mongodb.core.query.Update;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import static com.appsmith.server.migrations.db.ce.Migration021MoveGoogleMapsKeyToTenantConfiguration.commentEnvInFile;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@ChangeUnit(order = "072", id = "move-signup-disabled-to-organization-configuration")
|
||||||
|
public class Migration072MoveSignupDisabledToOrganizationConfiguration {
|
||||||
|
private final MongoTemplate mongoTemplate;
|
||||||
|
private final CommonConfig commonConfig;
|
||||||
|
|
||||||
|
@RollbackExecution
|
||||||
|
public void rollbackExecution() {}
|
||||||
|
|
||||||
|
@Execution
|
||||||
|
public void executeMigration() throws IOException {
|
||||||
|
final String envName = "APPSMITH_SIGNUP_DISABLED";
|
||||||
|
final String signupDisabledValue = System.getenv(envName);
|
||||||
|
|
||||||
|
// Default to false if the environment variable is not present or empty
|
||||||
|
boolean signupDisabled = false;
|
||||||
|
|
||||||
|
if (StringUtils.isNotEmpty(signupDisabledValue)) {
|
||||||
|
// Convert the string value to a boolean if env is present
|
||||||
|
signupDisabled = Boolean.parseBoolean(signupDisabledValue);
|
||||||
|
|
||||||
|
// Comment out the environment variable in the .env file
|
||||||
|
commentEnvInFile(envName, commonConfig.getEnvFilePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update all organizations to set the signup disabled configuration
|
||||||
|
// This happens whether the env var is present or not, defaulting to false
|
||||||
|
mongoTemplate.updateMulti(
|
||||||
|
new Query(),
|
||||||
|
new Update().set("organizationConfiguration.isSignupDisabled", signupDisabled),
|
||||||
|
Organization.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -7,7 +7,6 @@ import com.appsmith.server.repositories.AppsmithRepository;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
public interface CustomOrganizationRepositoryCE extends AppsmithRepository<Organization> {
|
public interface CustomOrganizationRepositoryCE extends AppsmithRepository<Organization> {
|
||||||
Mono<Integer> disableRestartForAllOrganizations();
|
|
||||||
|
|
||||||
Mono<Organization> findByIdAsUser(User user, String id, AclPermission permission);
|
Mono<Organization> findByIdAsUser(User user, String id, AclPermission permission);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,20 +9,10 @@ import com.appsmith.server.repositories.BaseAppsmithRepositoryImpl;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
import static com.appsmith.server.domains.Organization.Fields.organizationConfiguration_isRestartRequired;
|
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class CustomOrganizationRepositoryCEImpl extends BaseAppsmithRepositoryImpl<Organization>
|
public class CustomOrganizationRepositoryCEImpl extends BaseAppsmithRepositoryImpl<Organization>
|
||||||
implements CustomOrganizationRepositoryCE {
|
implements CustomOrganizationRepositoryCE {
|
||||||
|
|
||||||
@Override
|
|
||||||
public Mono<Integer> disableRestartForAllOrganizations() {
|
|
||||||
log.info("Disabling restart for all organizations");
|
|
||||||
return queryBuilder()
|
|
||||||
.criteria(Bridge.isTrue(organizationConfiguration_isRestartRequired))
|
|
||||||
.updateAll(Bridge.update().set(organizationConfiguration_isRestartRequired, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<Organization> findByIdAsUser(User user, String id, AclPermission permission) {
|
public Mono<Organization> findByIdAsUser(User user, String id, AclPermission permission) {
|
||||||
return getAllPermissionGroupsForUser(user).flatMap(permissionGroups -> queryBuilder()
|
return getAllPermissionGroupsForUser(user).flatMap(permissionGroups -> queryBuilder()
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@ package com.appsmith.server.services;
|
||||||
|
|
||||||
import com.appsmith.server.configurations.CommonConfig;
|
import com.appsmith.server.configurations.CommonConfig;
|
||||||
import com.appsmith.server.helpers.FeatureFlagMigrationHelper;
|
import com.appsmith.server.helpers.FeatureFlagMigrationHelper;
|
||||||
import com.appsmith.server.helpers.InstanceVariablesHelper;
|
|
||||||
import com.appsmith.server.helpers.UserOrganizationHelper;
|
import com.appsmith.server.helpers.UserOrganizationHelper;
|
||||||
|
import com.appsmith.server.instanceconfigs.helpers.InstanceVariablesHelper;
|
||||||
import com.appsmith.server.repositories.CacheableRepositoryHelper;
|
import com.appsmith.server.repositories.CacheableRepositoryHelper;
|
||||||
import com.appsmith.server.repositories.OrganizationRepository;
|
import com.appsmith.server.repositories.OrganizationRepository;
|
||||||
import com.appsmith.server.services.ce.OrganizationServiceCEImpl;
|
import com.appsmith.server.services.ce.OrganizationServiceCEImpl;
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,9 @@ package com.appsmith.server.services;
|
||||||
|
|
||||||
import com.appsmith.server.configurations.CommonConfig;
|
import com.appsmith.server.configurations.CommonConfig;
|
||||||
import com.appsmith.server.configurations.EmailConfig;
|
import com.appsmith.server.configurations.EmailConfig;
|
||||||
import com.appsmith.server.helpers.InstanceVariablesHelper;
|
|
||||||
import com.appsmith.server.helpers.UserServiceHelper;
|
import com.appsmith.server.helpers.UserServiceHelper;
|
||||||
import com.appsmith.server.helpers.UserUtils;
|
import com.appsmith.server.helpers.UserUtils;
|
||||||
|
import com.appsmith.server.instanceconfigs.helpers.InstanceVariablesHelper;
|
||||||
import com.appsmith.server.notifications.EmailSender;
|
import com.appsmith.server.notifications.EmailSender;
|
||||||
import com.appsmith.server.ratelimiting.RateLimitService;
|
import com.appsmith.server.ratelimiting.RateLimitService;
|
||||||
import com.appsmith.server.repositories.ApplicationRepository;
|
import com.appsmith.server.repositories.ApplicationRepository;
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,5 @@ public interface OrganizationServiceCE extends CrudService<Organization, String>
|
||||||
|
|
||||||
Mono<Organization> retrieveById(String id);
|
Mono<Organization> retrieveById(String id);
|
||||||
|
|
||||||
Mono<Void> restartOrganization();
|
|
||||||
|
|
||||||
Flux<Organization> retrieveAll();
|
Flux<Organization> retrieveAll();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,8 @@ import com.appsmith.server.exceptions.AppsmithError;
|
||||||
import com.appsmith.server.exceptions.AppsmithException;
|
import com.appsmith.server.exceptions.AppsmithException;
|
||||||
import com.appsmith.server.helpers.CollectionUtils;
|
import com.appsmith.server.helpers.CollectionUtils;
|
||||||
import com.appsmith.server.helpers.FeatureFlagMigrationHelper;
|
import com.appsmith.server.helpers.FeatureFlagMigrationHelper;
|
||||||
import com.appsmith.server.helpers.InstanceVariablesHelper;
|
|
||||||
import com.appsmith.server.helpers.UserOrganizationHelper;
|
import com.appsmith.server.helpers.UserOrganizationHelper;
|
||||||
|
import com.appsmith.server.instanceconfigs.helpers.InstanceVariablesHelper;
|
||||||
import com.appsmith.server.repositories.CacheableRepositoryHelper;
|
import com.appsmith.server.repositories.CacheableRepositoryHelper;
|
||||||
import com.appsmith.server.repositories.OrganizationRepository;
|
import com.appsmith.server.repositories.OrganizationRepository;
|
||||||
import com.appsmith.server.services.AnalyticsService;
|
import com.appsmith.server.services.AnalyticsService;
|
||||||
|
|
@ -175,8 +175,6 @@ public class OrganizationServiceCEImpl extends BaseService<OrganizationRepositor
|
||||||
config.addThirdPartyAuth("github");
|
config.addThirdPartyAuth("github");
|
||||||
}
|
}
|
||||||
|
|
||||||
config.setIsFormLoginEnabled(!"true".equals(System.getenv("APPSMITH_FORM_LOGIN_DISABLED")));
|
|
||||||
|
|
||||||
return configService
|
return configService
|
||||||
.getInstanceVariables()
|
.getInstanceVariables()
|
||||||
.map(instanceVariables -> instanceVariablesHelper.populateOrgConfigWithInstanceVariables(
|
.map(instanceVariables -> instanceVariablesHelper.populateOrgConfigWithInstanceVariables(
|
||||||
|
|
@ -342,29 +340,6 @@ public class OrganizationServiceCEImpl extends BaseService<OrganizationRepositor
|
||||||
.then(updatedOrganizationMono);
|
.then(updatedOrganizationMono);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* This function checks if the organization needs to be restarted, and executes the restart after the feature flag
|
|
||||||
* migrations are completed.
|
|
||||||
*
|
|
||||||
* @return Mono<Void>
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Mono<Void> restartOrganization() {
|
|
||||||
// TODO @CloudBilling: remove this method once we move the form login env to DB variable which is currently
|
|
||||||
// required as a part of downgrade migration for SSO
|
|
||||||
return this.retrieveAll()
|
|
||||||
.filter(organization ->
|
|
||||||
TRUE.equals(organization.getOrganizationConfiguration().getIsRestartRequired()))
|
|
||||||
.take(1)
|
|
||||||
.hasElements()
|
|
||||||
.flatMap(hasElement -> {
|
|
||||||
if (hasElement) {
|
|
||||||
return repository.disableRestartForAllOrganizations().then(envManager.restartWithoutAclCheck());
|
|
||||||
}
|
|
||||||
return Mono.empty();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isMigrationRequired(Organization organization) {
|
private boolean isMigrationRequired(Organization organization) {
|
||||||
return organization.getOrganizationConfiguration() != null
|
return organization.getOrganizationConfiguration() != null
|
||||||
&& (!CollectionUtils.isNullOrEmpty(
|
&& (!CollectionUtils.isNullOrEmpty(
|
||||||
|
|
|
||||||
|
|
@ -22,9 +22,9 @@ import com.appsmith.server.dtos.UserSignupDTO;
|
||||||
import com.appsmith.server.dtos.UserUpdateDTO;
|
import com.appsmith.server.dtos.UserUpdateDTO;
|
||||||
import com.appsmith.server.exceptions.AppsmithError;
|
import com.appsmith.server.exceptions.AppsmithError;
|
||||||
import com.appsmith.server.exceptions.AppsmithException;
|
import com.appsmith.server.exceptions.AppsmithException;
|
||||||
import com.appsmith.server.helpers.InstanceVariablesHelper;
|
|
||||||
import com.appsmith.server.helpers.UserServiceHelper;
|
import com.appsmith.server.helpers.UserServiceHelper;
|
||||||
import com.appsmith.server.helpers.UserUtils;
|
import com.appsmith.server.helpers.UserUtils;
|
||||||
|
import com.appsmith.server.instanceconfigs.helpers.InstanceVariablesHelper;
|
||||||
import com.appsmith.server.ratelimiting.RateLimitService;
|
import com.appsmith.server.ratelimiting.RateLimitService;
|
||||||
import com.appsmith.server.repositories.EmailVerificationTokenRepository;
|
import com.appsmith.server.repositories.EmailVerificationTokenRepository;
|
||||||
import com.appsmith.server.repositories.PasswordResetTokenRepository;
|
import com.appsmith.server.repositories.PasswordResetTokenRepository;
|
||||||
|
|
@ -557,37 +557,42 @@ public class UserServiceCEImpl extends BaseService<UserRepository, User, String>
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Mono<User> signupIfAllowed(User user) {
|
public Mono<User> signupIfAllowed(User user) {
|
||||||
boolean isAdminUser = false;
|
Mono<Boolean> isAdminUserMono;
|
||||||
|
|
||||||
if (!commonConfig.getAdminEmails().contains(user.getEmail())) {
|
if (!commonConfig.getAdminEmails().contains(user.getEmail())) {
|
||||||
// If this is not an admin email address, only then do we check if signup should be allowed or not. Being an
|
// If this is not an admin email address, only then do we check if signup should be allowed or not. Being an
|
||||||
// explicitly set admin email address trumps all everything and signup for this email can never be disabled.
|
// explicitly set admin email address trumps all everything and signup for this email can never be disabled.
|
||||||
|
isAdminUserMono = organizationService.getCurrentUserOrganization().map(organization -> {
|
||||||
if (commonConfig.isSignupDisabled()) {
|
OrganizationConfiguration organizationConfiguration =
|
||||||
// Signing up has been globally disabled. Reject.
|
organization.getOrganizationConfiguration() == null
|
||||||
return Mono.error(new AppsmithException(AppsmithError.SIGNUP_DISABLED, user.getUsername()));
|
? new OrganizationConfiguration()
|
||||||
}
|
: organization.getOrganizationConfiguration();
|
||||||
|
if (TRUE.equals(organizationConfiguration.getIsSignupDisabled())) {
|
||||||
final List<String> allowedDomains = user.getSource() == LoginSource.FORM
|
// Signing up has been globally disabled. Reject.
|
||||||
? commonConfig.getAllowedDomains()
|
throw new AppsmithException(AppsmithError.SIGNUP_DISABLED, user.getUsername());
|
||||||
: commonConfig.getOauthAllowedDomains();
|
}
|
||||||
if (!CollectionUtils.isEmpty(allowedDomains)
|
final List<String> allowedDomains = user.getSource() == LoginSource.FORM
|
||||||
&& StringUtils.hasText(user.getEmail())
|
? commonConfig.getAllowedDomains()
|
||||||
&& user.getEmail().contains("@")
|
: commonConfig.getOauthAllowedDomains();
|
||||||
&& !allowedDomains.contains(user.getEmail().split("@")[1])) {
|
if (!CollectionUtils.isEmpty(allowedDomains)
|
||||||
// There is an explicit whitelist of email address domains that should be allowed. If the new email is
|
&& StringUtils.hasText(user.getEmail())
|
||||||
// of a different domain, reject.
|
&& user.getEmail().contains("@")
|
||||||
return Mono.error(new AppsmithException(AppsmithError.SIGNUP_DISABLED, user.getUsername()));
|
&& !allowedDomains.contains(user.getEmail().split("@")[1])) {
|
||||||
}
|
// There is an explicit whitelist of email address domains that should be allowed. If the new email
|
||||||
|
// is
|
||||||
|
// of a different domain, reject.
|
||||||
|
throw new AppsmithException(AppsmithError.SIGNUP_DISABLED, user.getUsername());
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
isAdminUser = true;
|
isAdminUserMono = Mono.just(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// First set the organization ID for the user
|
// No special configurations found, allow signup for the new user.
|
||||||
boolean finalIsAdminUser = isAdminUser;
|
|
||||||
return setOrganizationIdForUser(user)
|
return setOrganizationIdForUser(user)
|
||||||
// Then proceed with user creation
|
.zipWhen(userWithOrgId -> isAdminUserMono)
|
||||||
.flatMap(userWithOrgId -> userCreate(userWithOrgId, finalIsAdminUser))
|
.flatMap(tuple2 -> userCreate(tuple2.getT1(), tuple2.getT2()))
|
||||||
.elapsed()
|
.elapsed()
|
||||||
.map(pair -> {
|
.map(pair -> {
|
||||||
log.debug("UserServiceCEImpl::Time taken for create user: {} ms", pair.getT1());
|
log.debug("UserServiceCEImpl::Time taken for create user: {} ms", pair.getT1());
|
||||||
|
|
@ -826,8 +831,7 @@ public class UserServiceCEImpl extends BaseService<UserRepository, User, String>
|
||||||
return instanceVariablesHelper.isEmailVerificationEnabled().flatMap(emailVerificationEnabled -> {
|
return instanceVariablesHelper.isEmailVerificationEnabled().flatMap(emailVerificationEnabled -> {
|
||||||
// Email verification not enabled at instance level
|
// Email verification not enabled at instance level
|
||||||
if (!TRUE.equals(emailVerificationEnabled)) {
|
if (!TRUE.equals(emailVerificationEnabled)) {
|
||||||
return Mono.error(
|
return Mono.error(new AppsmithException(AppsmithError.EMAIL_VERIFICATION_NOT_ENABLED));
|
||||||
new AppsmithException(AppsmithError.ORGANIZATION_EMAIL_VERIFICATION_NOT_ENABLED));
|
|
||||||
}
|
}
|
||||||
return emailVerificationTokenRepository
|
return emailVerificationTokenRepository
|
||||||
.findByEmail(user.getEmail())
|
.findByEmail(user.getEmail())
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
package com.appsmith.server.services.ce_compatible;
|
package com.appsmith.server.services.ce_compatible;
|
||||||
|
|
||||||
import com.appsmith.server.configurations.CommonConfig;
|
import com.appsmith.server.configurations.CommonConfig;
|
||||||
import com.appsmith.server.helpers.InstanceVariablesHelper;
|
|
||||||
import com.appsmith.server.helpers.UserServiceHelper;
|
import com.appsmith.server.helpers.UserServiceHelper;
|
||||||
import com.appsmith.server.helpers.UserUtils;
|
import com.appsmith.server.helpers.UserUtils;
|
||||||
|
import com.appsmith.server.instanceconfigs.helpers.InstanceVariablesHelper;
|
||||||
import com.appsmith.server.ratelimiting.RateLimitService;
|
import com.appsmith.server.ratelimiting.RateLimitService;
|
||||||
import com.appsmith.server.repositories.EmailVerificationTokenRepository;
|
import com.appsmith.server.repositories.EmailVerificationTokenRepository;
|
||||||
import com.appsmith.server.repositories.PasswordResetTokenRepository;
|
import com.appsmith.server.repositories.PasswordResetTokenRepository;
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,6 @@ import static com.appsmith.server.constants.EnvVariables.APPSMITH_RECAPTCHA_SECR
|
||||||
import static com.appsmith.server.constants.EnvVariables.APPSMITH_RECAPTCHA_SITE_KEY;
|
import static com.appsmith.server.constants.EnvVariables.APPSMITH_RECAPTCHA_SITE_KEY;
|
||||||
import static com.appsmith.server.constants.EnvVariables.APPSMITH_REPLY_TO;
|
import static com.appsmith.server.constants.EnvVariables.APPSMITH_REPLY_TO;
|
||||||
import static com.appsmith.server.constants.EnvVariables.APPSMITH_SIGNUP_ALLOWED_DOMAINS;
|
import static com.appsmith.server.constants.EnvVariables.APPSMITH_SIGNUP_ALLOWED_DOMAINS;
|
||||||
import static com.appsmith.server.constants.EnvVariables.APPSMITH_SIGNUP_DISABLED;
|
|
||||||
import static java.lang.Boolean.TRUE;
|
import static java.lang.Boolean.TRUE;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
|
@ -371,10 +370,6 @@ public class EnvManagerCEImpl implements EnvManagerCE {
|
||||||
// Try and update any at runtime, that can be.
|
// Try and update any at runtime, that can be.
|
||||||
final Map<String, String> changesCopy = new HashMap<>(changes);
|
final Map<String, String> changesCopy = new HashMap<>(changes);
|
||||||
|
|
||||||
if (changesCopy.containsKey(APPSMITH_SIGNUP_DISABLED.name())) {
|
|
||||||
commonConfig.setSignupDisabled(changesCopy.remove(APPSMITH_SIGNUP_DISABLED.name()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (changesCopy.containsKey(APPSMITH_SIGNUP_ALLOWED_DOMAINS.name())) {
|
if (changesCopy.containsKey(APPSMITH_SIGNUP_ALLOWED_DOMAINS.name())) {
|
||||||
commonConfig.setAllowedDomainsString(
|
commonConfig.setAllowedDomainsString(
|
||||||
changesCopy.remove(APPSMITH_SIGNUP_ALLOWED_DOMAINS.name()));
|
changesCopy.remove(APPSMITH_SIGNUP_ALLOWED_DOMAINS.name()));
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,6 @@ public class ScheduledTaskCEImpl implements ScheduledTaskCE {
|
||||||
log.error("Error while fetching organization feature flags", error);
|
log.error("Error while fetching organization feature flags", error);
|
||||||
return Flux.empty();
|
return Flux.empty();
|
||||||
})
|
})
|
||||||
.then(organizationService.restartOrganization())
|
|
||||||
.subscribeOn(LoadShifter.elasticScheduler)
|
.subscribeOn(LoadShifter.elasticScheduler)
|
||||||
.subscribe();
|
.subscribe();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package com.appsmith.server.helpers.ce;
|
package com.appsmith.server.instanceconfigs.helpers.ce;
|
||||||
|
|
||||||
import com.appsmith.server.constants.Appsmith;
|
import com.appsmith.server.constants.Appsmith;
|
||||||
import com.appsmith.server.helpers.InstanceVariablesHelper;
|
import com.appsmith.server.instanceconfigs.helpers.InstanceVariablesHelper;
|
||||||
import com.appsmith.server.services.ConfigService;
|
import com.appsmith.server.services.ConfigService;
|
||||||
import net.minidev.json.JSONObject;
|
import net.minidev.json.JSONObject;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
|
@ -693,7 +693,7 @@ public class UserServiceTest {
|
||||||
Mono<Boolean> resultMono = userMono.then(organizationMono).then(emailVerificationMono);
|
Mono<Boolean> resultMono = userMono.then(organizationMono).then(emailVerificationMono);
|
||||||
|
|
||||||
StepVerifier.create(resultMono)
|
StepVerifier.create(resultMono)
|
||||||
.expectErrorMessage(AppsmithError.ORGANIZATION_EMAIL_VERIFICATION_NOT_ENABLED.getMessage())
|
.expectErrorMessage(AppsmithError.EMAIL_VERIFICATION_NOT_ENABLED.getMessage())
|
||||||
.verify();
|
.verify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ import com.appsmith.server.applications.base.ApplicationService;
|
||||||
import com.appsmith.server.configurations.CommonConfig;
|
import com.appsmith.server.configurations.CommonConfig;
|
||||||
import com.appsmith.server.configurations.WithMockAppsmithUser;
|
import com.appsmith.server.configurations.WithMockAppsmithUser;
|
||||||
import com.appsmith.server.domains.LoginSource;
|
import com.appsmith.server.domains.LoginSource;
|
||||||
|
import com.appsmith.server.domains.Organization;
|
||||||
|
import com.appsmith.server.domains.OrganizationConfiguration;
|
||||||
import com.appsmith.server.domains.User;
|
import com.appsmith.server.domains.User;
|
||||||
import com.appsmith.server.exceptions.AppsmithError;
|
import com.appsmith.server.exceptions.AppsmithError;
|
||||||
import com.appsmith.server.exceptions.AppsmithException;
|
import com.appsmith.server.exceptions.AppsmithException;
|
||||||
|
|
@ -12,6 +14,7 @@ import com.appsmith.server.repositories.PermissionGroupRepository;
|
||||||
import com.appsmith.server.repositories.UserRepository;
|
import com.appsmith.server.repositories.UserRepository;
|
||||||
import com.appsmith.server.repositories.WorkspaceRepository;
|
import com.appsmith.server.repositories.WorkspaceRepository;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.junit.jupiter.api.AfterAll;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
|
|
@ -54,16 +57,32 @@ public class UserServiceWithDisabledSignupTest {
|
||||||
@SpyBean
|
@SpyBean
|
||||||
CommonConfig commonConfig;
|
CommonConfig commonConfig;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
OrganizationService organizationService;
|
||||||
|
|
||||||
Mono<User> userMono;
|
Mono<User> userMono;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void setup() {
|
public void setup() {
|
||||||
userMono = userService.findByEmail("usertest@usertest.com");
|
userMono = userService.findByEmail("usertest@usertest.com");
|
||||||
Mockito.when(commonConfig.isSignupDisabled()).thenReturn(Boolean.TRUE);
|
Organization organization =
|
||||||
|
organizationService.getCurrentUserOrganization().block();
|
||||||
|
assert organization != null;
|
||||||
|
organization.getOrganizationConfiguration().setIsSignupDisabled(true);
|
||||||
|
organizationService.save(organization).block();
|
||||||
Mockito.when(commonConfig.getAdminEmails())
|
Mockito.when(commonConfig.getAdminEmails())
|
||||||
.thenReturn(Set.of("dummy_admin@appsmith.com", "dummy2@appsmith.com"));
|
.thenReturn(Set.of("dummy_admin@appsmith.com", "dummy2@appsmith.com"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@AfterAll
|
||||||
|
public static void cleanup(@Autowired OrganizationService organizationService) {
|
||||||
|
OrganizationConfiguration organizationConfiguration = new OrganizationConfiguration();
|
||||||
|
organizationConfiguration.setIsSignupDisabled(false);
|
||||||
|
Organization organization =
|
||||||
|
organizationService.getCurrentUserOrganization().block();
|
||||||
|
organizationService.save(organization).block();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@WithMockAppsmithUser
|
@WithMockAppsmithUser
|
||||||
public void createNewUserValidWhenDisabled() {
|
public void createNewUserValidWhenDisabled() {
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,6 @@ APPSMITH_CLOUD_SERVICES_BASE_URL="https://release-cs.appsmith.com"
|
||||||
#APPSMITH_OAUTH2_GITHUB_CLIENT_ID=""
|
#APPSMITH_OAUTH2_GITHUB_CLIENT_ID=""
|
||||||
#APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET=""
|
#APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET=""
|
||||||
|
|
||||||
#APPSMITH_FORM_LOGIN_DISABLED=
|
|
||||||
#APPSMITH_SIGNUP_DISABLED=
|
|
||||||
|
|
||||||
#APPSMITH_SENTRY_DSN=
|
#APPSMITH_SENTRY_DSN=
|
||||||
#APPSMITH_SENTRY_ENVIRONMENT=
|
#APPSMITH_SENTRY_ENVIRONMENT=
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,6 @@
|
||||||
# APPSMITH_OAUTH2_GOOGLE_CLIENT_SECRET=""
|
# APPSMITH_OAUTH2_GOOGLE_CLIENT_SECRET=""
|
||||||
# APPSMITH_OAUTH2_GITHUB_CLIENT_ID=""
|
# APPSMITH_OAUTH2_GITHUB_CLIENT_ID=""
|
||||||
# APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET=""
|
# APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET=""
|
||||||
# APPSMITH_FORM_LOGIN_DISABLED=
|
|
||||||
# APPSMITH_SIGNUP_DISABLED=
|
|
||||||
|
|
||||||
# APPSMITH_MAIL_ENABLED=true
|
# APPSMITH_MAIL_ENABLED=true
|
||||||
# APPSMITH_MAIL_HOST=localhost
|
# APPSMITH_MAIL_HOST=localhost
|
||||||
|
|
|
||||||
|
|
@ -22,9 +22,6 @@ APPSMITH_CLOUD_SERVICES_BASE_URL="https://release-cs.appsmith.com"
|
||||||
#APPSMITH_OAUTH2_GITHUB_CLIENT_ID=""
|
#APPSMITH_OAUTH2_GITHUB_CLIENT_ID=""
|
||||||
#APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET=""
|
#APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET=""
|
||||||
|
|
||||||
#APPSMITH_FORM_LOGIN_DISABLED=
|
|
||||||
#APPSMITH_SIGNUP_DISABLED=
|
|
||||||
|
|
||||||
#APPSMITH_SENTRY_DSN=
|
#APPSMITH_SENTRY_DSN=
|
||||||
#APPSMITH_SENTRY_ENVIRONMENT=
|
#APPSMITH_SENTRY_ENVIRONMENT=
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user