Use browser router for Account Console (#22192)
Closes #27442 Signed-off-by: Jon Koops <jonkoops@gmail.com>
This commit is contained in:
parent
be3e2fabc4
commit
7afd75ba08
14 changed files with 152 additions and 115 deletions
|
@ -1,4 +1,5 @@
|
|||
import { defineConfig, devices } from "@playwright/test";
|
||||
import { getRootPath } from "./src/utils/getRootPath";
|
||||
|
||||
/**
|
||||
* See https://playwright.dev/docs/test-configuration.
|
||||
|
@ -11,9 +12,7 @@ export default defineConfig({
|
|||
workers: 1,
|
||||
reporter: process.env.CI ? [["github"], ["html"]] : "list",
|
||||
use: {
|
||||
baseURL: process.env.CI
|
||||
? "http://localhost:8080/realms/master/account/"
|
||||
: "http://localhost:8080/",
|
||||
baseURL: `http://localhost:8080${getRootPath()}`,
|
||||
trace: "on-first-retry",
|
||||
},
|
||||
|
||||
|
|
2
js/apps/account-ui/src/constants.ts
Normal file
2
js/apps/account-ui/src/constants.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
export const DEFAULT_REALM = "master";
|
||||
export const ROOT_PATH = "/realms/:realm/account";
|
|
@ -1,3 +1,6 @@
|
|||
import { matchPath } from "react-router-dom";
|
||||
import { DEFAULT_REALM, ROOT_PATH } from "./constants";
|
||||
|
||||
export type Feature = {
|
||||
isRegistrationEmailAsUsername: boolean;
|
||||
isEditUserNameAllowed: boolean;
|
||||
|
@ -31,11 +34,12 @@ export type Environment = {
|
|||
features: Feature;
|
||||
};
|
||||
|
||||
// The default environment, used during development.
|
||||
const realm = new URLSearchParams(window.location.search).get("realm");
|
||||
// Detect the current realm from the URL.
|
||||
const match = matchPath(ROOT_PATH, location.pathname);
|
||||
|
||||
const defaultEnvironment: Environment = {
|
||||
authUrl: "http://localhost:8180",
|
||||
realm: realm || "master",
|
||||
realm: match?.params.realm ?? DEFAULT_REALM,
|
||||
clientId: "security-admin-console-v2",
|
||||
resourceUrl: "http://localhost:8080",
|
||||
logo: "/logo.svg",
|
||||
|
|
|
@ -3,18 +3,22 @@ import "@patternfly/patternfly/patternfly-addons.css";
|
|||
|
||||
import { StrictMode } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import { createHashRouter, RouterProvider } from "react-router-dom";
|
||||
import { createBrowserRouter, RouterProvider } from "react-router-dom";
|
||||
|
||||
import { environment } from "./environment";
|
||||
import { i18n } from "./i18n";
|
||||
import { routes } from "./routes";
|
||||
import { getRootPath } from "./utils/getRootPath";
|
||||
|
||||
// Initialize required components before rendering app.
|
||||
await i18n.init();
|
||||
|
||||
const router = createHashRouter(routes);
|
||||
const container = document.getElementById("app");
|
||||
const root = createRoot(container!);
|
||||
|
||||
const basename = getRootPath(environment.realm);
|
||||
const router = createBrowserRouter(routes, { basename });
|
||||
|
||||
root.render(
|
||||
<StrictMode>
|
||||
<RouterProvider router={router} />
|
||||
|
|
5
js/apps/account-ui/src/utils/getRootPath.ts
Normal file
5
js/apps/account-ui/src/utils/getRootPath.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
import { generatePath } from "react-router-dom";
|
||||
import { DEFAULT_REALM, ROOT_PATH } from "../constants";
|
||||
|
||||
export const getRootPath = (realm = DEFAULT_REALM) =>
|
||||
generatePath(ROOT_PATH, { realm });
|
|
@ -1,18 +1,20 @@
|
|||
import { expect, test } from "@playwright/test";
|
||||
import {
|
||||
createIdentityProvider,
|
||||
deleteIdentityProvider,
|
||||
createClient,
|
||||
deleteClient,
|
||||
inRealm,
|
||||
findClientByClientId,
|
||||
createRandomUserWithPassword,
|
||||
deleteUser,
|
||||
} from "../admin-client";
|
||||
import groupsIdPClient from "../realms/groups-idp.json" assert { type: "json" };
|
||||
import ClientRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientRepresentation";
|
||||
import IdentityProviderRepresentation from "@keycloak/keycloak-admin-client/lib/defs/identityProviderRepresentation";
|
||||
import { randomUUID } from "crypto";
|
||||
import { expect, test } from "@playwright/test";
|
||||
import { randomUUID } from "node:crypto";
|
||||
|
||||
import {
|
||||
createClient,
|
||||
createIdentityProvider,
|
||||
createRandomUserWithPassword,
|
||||
deleteClient,
|
||||
deleteIdentityProvider,
|
||||
deleteUser,
|
||||
findClientByClientId,
|
||||
inRealm,
|
||||
} from "../admin-client";
|
||||
import groupsIdPClient from "../realms/groups-idp.json" assert { type: "json" };
|
||||
import { getBaseUrl } from "../utils";
|
||||
|
||||
const realm = "groups";
|
||||
|
||||
|
@ -30,7 +32,7 @@ test.describe("Account linking", () => {
|
|||
groupIdPClientId = await createClient(
|
||||
groupsIdPClient as ClientRepresentation,
|
||||
);
|
||||
const kc = process.env.KEYCLOAK_SERVER || "http://localhost:8080";
|
||||
const baseUrl = getBaseUrl();
|
||||
const idp: IdentityProviderRepresentation = {
|
||||
alias: "master-idp",
|
||||
providerId: "oidc",
|
||||
|
@ -39,12 +41,12 @@ test.describe("Account linking", () => {
|
|||
clientId: "groups-idp",
|
||||
clientSecret: "H0JaTc7VBu3HJR26vrzMxgidfJmgI5Dw",
|
||||
validateSignature: "false",
|
||||
tokenUrl: `${kc}/realms/master/protocol/openid-connect/token`,
|
||||
jwksUrl: `${kc}/realms/master/protocol/openid-connect/certs`,
|
||||
issuer: `${kc}/realms/master`,
|
||||
authorizationUrl: `${kc}/realms/master/protocol/openid-connect/auth`,
|
||||
logoutUrl: `${kc}/realms/master/protocol/openid-connect/logout`,
|
||||
userInfoUrl: `${kc}/realms/master/protocol/openid-connect/userinfo`,
|
||||
tokenUrl: `${baseUrl}/realms/master/protocol/openid-connect/token`,
|
||||
jwksUrl: `${baseUrl}/realms/master/protocol/openid-connect/certs`,
|
||||
issuer: `${baseUrl}/realms/master`,
|
||||
authorizationUrl: `${baseUrl}/realms/master/protocol/openid-connect/auth`,
|
||||
logoutUrl: `${baseUrl}/realms/master/protocol/openid-connect/logout`,
|
||||
userInfoUrl: `${baseUrl}/realms/master/protocol/openid-connect/userinfo`,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -5,9 +5,12 @@ import RealmRepresentation from "@keycloak/keycloak-admin-client/lib/defs/realmR
|
|||
import type { UserProfileConfig } from "@keycloak/keycloak-admin-client/lib/defs/userProfileMetadata";
|
||||
import UserRepresentation from "@keycloak/keycloak-admin-client/lib/defs/userRepresentation";
|
||||
|
||||
import { DEFAULT_REALM } from "../src/constants";
|
||||
import { getBaseUrl } from "./utils";
|
||||
|
||||
const adminClient = new KeycloakAdminClient({
|
||||
baseUrl: process.env.KEYCLOAK_SERVER || "http://127.0.0.1:8080",
|
||||
realmName: "master",
|
||||
baseUrl: getBaseUrl(),
|
||||
realmName: DEFAULT_REALM,
|
||||
});
|
||||
|
||||
await adminClient.auth({
|
||||
|
@ -18,9 +21,12 @@ await adminClient.auth({
|
|||
});
|
||||
|
||||
export async function useTheme() {
|
||||
const masterRealm = await adminClient.realms.findOne({ realm: "master" });
|
||||
const masterRealm = await adminClient.realms.findOne({
|
||||
realm: DEFAULT_REALM,
|
||||
});
|
||||
|
||||
await adminClient.realms.update(
|
||||
{ realm: "master" },
|
||||
{ realm: DEFAULT_REALM },
|
||||
{ ...masterRealm, accountTheme: "keycloak.v3" },
|
||||
);
|
||||
}
|
||||
|
@ -76,7 +82,7 @@ export async function importUserProfile(
|
|||
await adminClient.users.updateProfile({ ...userProfile, realm });
|
||||
}
|
||||
|
||||
export async function enableLocalization(realm: string) {
|
||||
export async function enableLocalization(realm = DEFAULT_REALM) {
|
||||
const realmRepresentation = await adminClient.realms.findOne({ realm });
|
||||
await adminClient.realms.update(
|
||||
{ realm },
|
||||
|
@ -121,9 +127,9 @@ export async function getUserByUsername(username: string, realm: string) {
|
|||
|
||||
export async function deleteUser(username: string) {
|
||||
try {
|
||||
const users = await adminClient.users.find({ username, realm });
|
||||
const users = await adminClient.users.find({ username });
|
||||
const { id } = users[0];
|
||||
await adminClient.users.del({ id: id!, realm });
|
||||
await adminClient.users.del({ id: id! });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
import { expect, test } from "@playwright/test";
|
||||
import { getRootPath } from "../src/utils/getRootPath";
|
||||
import { login } from "./login";
|
||||
import { getAccountUrl, getAdminUrl } from "./utils";
|
||||
|
||||
test.describe("Applications test", () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
// Sign out all devices before each test
|
||||
await login(page, "admin", "admin", "master");
|
||||
await login(page, "admin", "admin");
|
||||
await page.getByTestId("accountSecurity").click();
|
||||
await page.getByTestId("account-security/device-activity").click();
|
||||
|
||||
|
@ -19,7 +21,7 @@ test.describe("Applications test", () => {
|
|||
});
|
||||
|
||||
test("Single application", async ({ page }) => {
|
||||
await login(page, "admin", "admin", "master");
|
||||
await login(page, "admin", "admin");
|
||||
|
||||
await page.getByTestId("applications").click();
|
||||
|
||||
|
@ -39,8 +41,8 @@ test.describe("Applications test", () => {
|
|||
const page1 = await context1.newPage();
|
||||
const page2 = await context2.newPage();
|
||||
|
||||
await login(page1, "admin", "admin", "master");
|
||||
await login(page2, "admin", "admin", "master");
|
||||
await login(page1, "admin", "admin");
|
||||
await login(page2, "admin", "admin");
|
||||
|
||||
await page1.getByTestId("applications").click();
|
||||
|
||||
|
@ -62,15 +64,15 @@ test.describe("Applications test", () => {
|
|||
"Skip this test if not running with regular Keycloak",
|
||||
);
|
||||
|
||||
await login(page, "admin", "admin", "master");
|
||||
await login(page, "admin", "admin");
|
||||
|
||||
// go to admin console
|
||||
await page.goto("/");
|
||||
await expect(page).toHaveURL("http://localhost:8080/admin/master/console/");
|
||||
await page.waitForURL("http://localhost:8080/admin/master/console/");
|
||||
await expect(page).toHaveURL(getAdminUrl());
|
||||
await page.waitForURL(getAdminUrl());
|
||||
|
||||
await page.goto("/realms/master/account");
|
||||
await page.waitForURL("http://localhost:8080/realms/master/account/");
|
||||
await page.goto(getRootPath());
|
||||
await page.waitForURL(getAccountUrl());
|
||||
|
||||
await page.getByTestId("applications").click();
|
||||
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
import { Page } from "@playwright/test";
|
||||
import { DEFAULT_REALM } from "../src/constants";
|
||||
import { getRootPath } from "../src/utils/getRootPath";
|
||||
|
||||
export const login = async (
|
||||
page: Page,
|
||||
username: string,
|
||||
password: string,
|
||||
realm?: string,
|
||||
realm = DEFAULT_REALM,
|
||||
) => {
|
||||
if (realm)
|
||||
await page.goto(
|
||||
process.env.CI ? `/realms/${realm}/account` : `/?realm=${realm}`,
|
||||
);
|
||||
const rootPath = getRootPath(realm);
|
||||
|
||||
await page.goto(rootPath);
|
||||
await page.getByLabel("Username").fill(username);
|
||||
await page.getByLabel("Password", { exact: true }).fill(password);
|
||||
await page.getByRole("button", { name: "Sign In" }).click();
|
||||
|
|
|
@ -18,7 +18,7 @@ test.describe("Personal info page", () => {
|
|||
test("sets basic information", async ({ page }) => {
|
||||
user = await createRandomUserWithPassword("user-" + randomUUID(), "pwd");
|
||||
|
||||
await login(page, user, "pwd", "master");
|
||||
await login(page, user, "pwd");
|
||||
|
||||
await page.getByTestId("email").fill(`${user}@somewhere.com`);
|
||||
await page.getByTestId("firstName").fill("Erik");
|
||||
|
@ -84,7 +84,7 @@ test.describe("Personal info with userprofile enabled", async () => {
|
|||
|
||||
// skip currently the locale is not part of the response
|
||||
test.describe.skip("Realm localization", async () => {
|
||||
test.beforeAll(() => enableLocalization("master"));
|
||||
test.beforeAll(() => enableLocalization());
|
||||
|
||||
test("change locale", async ({ page }) => {
|
||||
const user = await createRandomUserWithPassword(
|
||||
|
@ -92,7 +92,7 @@ test.describe.skip("Realm localization", async () => {
|
|||
"pwd",
|
||||
);
|
||||
|
||||
await login(page, user, "pwd", "master");
|
||||
await login(page, user, "pwd");
|
||||
await page
|
||||
.locator("div")
|
||||
.filter({ hasText: /^Deutsch$/ })
|
||||
|
|
13
js/apps/account-ui/test/utils.ts
Normal file
13
js/apps/account-ui/test/utils.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
import { getRootPath } from "../src/utils/getRootPath";
|
||||
|
||||
export function getBaseUrl(): string {
|
||||
return process.env.KEYCLOAK_SERVER ?? "http://localhost:8080";
|
||||
}
|
||||
|
||||
export function getAccountUrl() {
|
||||
return getBaseUrl() + getRootPath();
|
||||
}
|
||||
|
||||
export function getAdminUrl() {
|
||||
return getBaseUrl() + "/admin/master/console/";
|
||||
}
|
|
@ -4,6 +4,8 @@ import { defineConfig, loadEnv } from "vite";
|
|||
import { checker } from "vite-plugin-checker";
|
||||
import dts from "vite-plugin-dts";
|
||||
|
||||
import { getRootPath } from "./src/utils/getRootPath";
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig(({ mode }) => {
|
||||
const env = loadEnv(mode, process.cwd(), "");
|
||||
|
@ -26,6 +28,7 @@ export default defineConfig(({ mode }) => {
|
|||
base: "",
|
||||
server: {
|
||||
port: 8080,
|
||||
open: getRootPath(),
|
||||
},
|
||||
build: {
|
||||
...lib,
|
||||
|
|
|
@ -18,7 +18,7 @@ describe("Masthead tests", () => {
|
|||
it("Go to account console and back to admin console", () => {
|
||||
sidebarPage.waitForPageLoad();
|
||||
masthead.accountManagement();
|
||||
cy.url().should("contain", "/realms/master/account/");
|
||||
cy.url().should("contain", "/realms/master/account");
|
||||
});
|
||||
|
||||
it("Sign out reachs to log in screen", () => {
|
||||
|
|
|
@ -92,76 +92,72 @@ public class AccountConsole implements AccountResourceProvider {
|
|||
|
||||
@GET
|
||||
@NoCache
|
||||
@Path("{any:.*}")
|
||||
public Response getMainPage() throws IOException, FreeMarkerException {
|
||||
UriInfo uriInfo = session.getContext().getUri(UrlType.FRONTEND);
|
||||
URI accountBaseUrl = uriInfo.getBaseUriBuilder().path(RealmsResource.class).path(realm.getName())
|
||||
.path(Constants.ACCOUNT_MANAGEMENT_CLIENT_ID).path("/").build(realm);
|
||||
|
||||
if (!session.getContext().getUri().getRequestUri().getPath().endsWith("/")) {
|
||||
UriBuilder redirectUri = session.getContext().getUri().getRequestUriBuilder().uri(accountBaseUrl);
|
||||
return Response.status(302).location(redirectUri.build()).build();
|
||||
} else {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
|
||||
URI adminBaseUri = session.getContext().getUri(UrlType.ADMIN).getBaseUri();
|
||||
URI authUrl = uriInfo.getBaseUri();
|
||||
map.put("authUrl", authUrl.getPath().endsWith("/") ? authUrl : authUrl + "/");
|
||||
map.put("baseUrl", accountBaseUrl);
|
||||
map.put("realm", realm);
|
||||
map.put("clientId", Constants.ACCOUNT_CONSOLE_CLIENT_ID);
|
||||
map.put("resourceUrl", Urls.themeRoot(authUrl).getPath() + "/" + Constants.ACCOUNT_MANAGEMENT_CLIENT_ID + "/" + theme.getName());
|
||||
map.put("resourceCommonUrl", Urls.themeRoot(adminBaseUri).getPath() + "/common/keycloak");
|
||||
map.put("resourceVersion", Version.RESOURCES_VERSION);
|
||||
|
||||
String[] referrer = getReferrer();
|
||||
if (referrer != null) {
|
||||
map.put("referrer", referrer[0]);
|
||||
map.put("referrerName", referrer[1]);
|
||||
map.put("referrer_uri", referrer[2]);
|
||||
}
|
||||
|
||||
UserModel user = null;
|
||||
if (auth != null) user = auth.getUser();
|
||||
Locale locale = session.getContext().resolveLocale(user);
|
||||
map.put("locale", locale.toLanguageTag());
|
||||
Properties messages = theme.getEnhancedMessages(realm, locale);
|
||||
map.put("msg", new MessageFormatterMethod(locale, messages));
|
||||
map.put("msgJSON", messagesToJsonString(messages));
|
||||
map.put("supportedLocales", supportedLocales(messages));
|
||||
map.put("properties", theme.getProperties());
|
||||
map.put("theme", (Function<String, String>) file -> {
|
||||
try {
|
||||
final InputStream resource = theme.getResourceAsStream(file);
|
||||
return new Scanner(resource, "UTF-8").useDelimiter("\\A").next();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("could not load file", e);
|
||||
}
|
||||
});
|
||||
URI adminBaseUri = session.getContext().getUri(UrlType.ADMIN).getBaseUri();
|
||||
URI authUrl = uriInfo.getBaseUri();
|
||||
map.put("authUrl", authUrl.getPath().endsWith("/") ? authUrl : authUrl + "/");
|
||||
map.put("baseUrl", accountBaseUrl);
|
||||
map.put("realm", realm);
|
||||
map.put("clientId", Constants.ACCOUNT_CONSOLE_CLIENT_ID);
|
||||
map.put("resourceUrl", Urls.themeRoot(authUrl).getPath() + "/" + Constants.ACCOUNT_MANAGEMENT_CLIENT_ID + "/" + theme.getName());
|
||||
map.put("resourceCommonUrl", Urls.themeRoot(adminBaseUri).getPath() + "/common/keycloak");
|
||||
map.put("resourceVersion", Version.RESOURCES_VERSION);
|
||||
|
||||
map.put("isAuthorizationEnabled", Profile.isFeatureEnabled(Profile.Feature.AUTHORIZATION));
|
||||
|
||||
boolean deleteAccountAllowed = false;
|
||||
boolean isViewGroupsEnabled= false;
|
||||
if (user != null) {
|
||||
RoleModel deleteAccountRole = realm.getClientByClientId(Constants.ACCOUNT_MANAGEMENT_CLIENT_ID).getRole(AccountRoles.DELETE_ACCOUNT);
|
||||
deleteAccountAllowed = deleteAccountRole != null && user.hasRole(deleteAccountRole) && realm.getRequiredActionProviderByAlias(DeleteAccount.PROVIDER_ID).isEnabled();
|
||||
RoleModel viewGrouRole = realm.getClientByClientId(Constants.ACCOUNT_MANAGEMENT_CLIENT_ID).getRole(AccountRoles.VIEW_GROUPS);
|
||||
isViewGroupsEnabled = viewGrouRole != null && user.hasRole(viewGrouRole);
|
||||
}
|
||||
|
||||
map.put("deleteAccountAllowed", deleteAccountAllowed);
|
||||
|
||||
map.put("isViewGroupsEnabled", isViewGroupsEnabled);
|
||||
|
||||
map.put("updateEmailFeatureEnabled", Profile.isFeatureEnabled(Profile.Feature.UPDATE_EMAIL));
|
||||
RequiredActionProviderModel updateEmailActionProvider = realm.getRequiredActionProviderByAlias(UserModel.RequiredAction.UPDATE_EMAIL.name());
|
||||
map.put("updateEmailActionEnabled", updateEmailActionProvider != null && updateEmailActionProvider.isEnabled());
|
||||
|
||||
FreeMarkerProvider freeMarkerUtil = session.getProvider(FreeMarkerProvider.class);
|
||||
String result = freeMarkerUtil.processTemplate(map, "index.ftl", theme);
|
||||
Response.ResponseBuilder builder = Response.status(Response.Status.OK).type(MediaType.TEXT_HTML_UTF_8).language(Locale.ENGLISH).entity(result);
|
||||
return builder.build();
|
||||
String[] referrer = getReferrer();
|
||||
if (referrer != null) {
|
||||
map.put("referrer", referrer[0]);
|
||||
map.put("referrerName", referrer[1]);
|
||||
map.put("referrer_uri", referrer[2]);
|
||||
}
|
||||
|
||||
UserModel user = null;
|
||||
if (auth != null) user = auth.getUser();
|
||||
Locale locale = session.getContext().resolveLocale(user);
|
||||
map.put("locale", locale.toLanguageTag());
|
||||
Properties messages = theme.getEnhancedMessages(realm, locale);
|
||||
map.put("msg", new MessageFormatterMethod(locale, messages));
|
||||
map.put("msgJSON", messagesToJsonString(messages));
|
||||
map.put("supportedLocales", supportedLocales(messages));
|
||||
map.put("properties", theme.getProperties());
|
||||
map.put("theme", (Function<String, String>) file -> {
|
||||
try {
|
||||
final InputStream resource = theme.getResourceAsStream(file);
|
||||
return new Scanner(resource, "UTF-8").useDelimiter("\\A").next();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("could not load file", e);
|
||||
}
|
||||
});
|
||||
|
||||
map.put("isAuthorizationEnabled", Profile.isFeatureEnabled(Profile.Feature.AUTHORIZATION));
|
||||
|
||||
boolean deleteAccountAllowed = false;
|
||||
boolean isViewGroupsEnabled= false;
|
||||
if (user != null) {
|
||||
RoleModel deleteAccountRole = realm.getClientByClientId(Constants.ACCOUNT_MANAGEMENT_CLIENT_ID).getRole(AccountRoles.DELETE_ACCOUNT);
|
||||
deleteAccountAllowed = deleteAccountRole != null && user.hasRole(deleteAccountRole) && realm.getRequiredActionProviderByAlias(DeleteAccount.PROVIDER_ID).isEnabled();
|
||||
RoleModel viewGrouRole = realm.getClientByClientId(Constants.ACCOUNT_MANAGEMENT_CLIENT_ID).getRole(AccountRoles.VIEW_GROUPS);
|
||||
isViewGroupsEnabled = viewGrouRole != null && user.hasRole(viewGrouRole);
|
||||
}
|
||||
|
||||
map.put("deleteAccountAllowed", deleteAccountAllowed);
|
||||
|
||||
map.put("isViewGroupsEnabled", isViewGroupsEnabled);
|
||||
|
||||
map.put("updateEmailFeatureEnabled", Profile.isFeatureEnabled(Profile.Feature.UPDATE_EMAIL));
|
||||
RequiredActionProviderModel updateEmailActionProvider = realm.getRequiredActionProviderByAlias(UserModel.RequiredAction.UPDATE_EMAIL.name());
|
||||
map.put("updateEmailActionEnabled", updateEmailActionProvider != null && updateEmailActionProvider.isEnabled());
|
||||
|
||||
FreeMarkerProvider freeMarkerUtil = session.getProvider(FreeMarkerProvider.class);
|
||||
String result = freeMarkerUtil.processTemplate(map, "index.ftl", theme);
|
||||
Response.ResponseBuilder builder = Response.status(Response.Status.OK).type(MediaType.TEXT_HTML_UTF_8).language(Locale.ENGLISH).entity(result);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private Map<String, String> supportedLocales(Properties messages) {
|
||||
|
|
Loading…
Reference in a new issue