Jmix version: 2.2.3
Jmix Studio plugin version: 2.2.3-241
IntelliJ IDEA 2024.1.1 (Community Edition)
Build #IC-241.15989.150, built on April 29, 2024
Runtime version: 17.0.10+1-b1207.14 x86_64
VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o.
GC: G1 Young Generation, G1 Old Generation
Kotlin: 241.15989.150-IJ
java 17.0.4 2022-07-19 LTS
Java™ SE Runtime Environment (build 17.0.4+11-LTS-179)
Java HotSpot™ 64-Bit Server VM (build 17.0.4+11-LTS-179, mixed mode, sharing)
Operating System: macOS 14.5 (23F79)
Metal Rendering: ON
File System: Case-Sensitive Journaled HFS+ (APFS)
Browser: Safari - Version 17.5 (19618.2.12.11.6)
Database: PostgreSQL 13
Hello Jmix Team
I am having problems migrating my Anonymous user functionality from Jmix 1.5.x to 2.2.x and require assistance (or maybe I am dealing with a bug).
Beginning with CUBA I implemented an anonymous MainScreen, which I then migrated to Jmix 1.5.x; it has the following functionality:
- The MainScreen has a WorkArea containing a BrowserFrameFragment that displays a static HTML Welcome message
- The SideMenu contains four screen menu items allowing the anonymous user to open these screens:
Concept (normal screen without an entity containing a BrowserFrameFragment that displays a static HTML page)
Features (normal screen without an entity containing a BrowserFrameFragment that displays a static HTML page)
Terms & Conditions (normal screen without an entity containing a BrowserFrameFragment that displays a PDF document)
Membership Options (edit screen with an entity (read-only) and various screen components)
Furthermore, my main requirement is that the anonymous user can choose his language (locale) in the anonymous MainScreen (actually done in the SideMenu) before they are presented with the locale choice in the normal LoginScreen. Gleb helped me with my initial CUBA implementation here:
This allows me to load language specific static resources for my Welcome message in the MainScreen and in my Concept, Features and Terms & Conditions screens.
When the user is anonymous, I set the UserIndicator visibilty in the SideMenu to false and replace it by a ComboBox for the locale selection. I also add a login button and set the logout button visibilty to false.
When the anonymous user selects a different locale, I reload the MainScreen with jmixApp.createTopLevelWindow()
.
If the anonymous user chooses to login normally, then after the login, I replace the locale ComboBox with the UserIndicator and the login button with the normal logout button in the SideMenu (code farther below).
My 1.5.x application.properties are:
# enable anonymous access
jmix.ui.allow-anonymous-access = true
# initial screen for anonymous user
jmix.ui.initial-screen-id= nf_MainScreen
jmix.ui.login-screen-id = nf_LoginScreen
jmix.ui.main-screen-id = nf_MainScreen
jmix.ui.default-screen-id = nf_SearchInterests.browse
jmix.ui.default-screen-can-be-closed=true
jmix.ui.menu-config = com/company/nf/menu.xml
jmix.ui.composite-menu = true
jmix.ui.app-window-mode=SINGLE
Here in the 1.5 documentation it says that two MainScreens are necessary but I have only one:
https://docs.jmix.io/1.x/jmix/1.5/ui/anonymous-access-to-screens.html
Keep in mind that you’ll have two main screens in your app. The default one will be used for authenticated users and the anonymous one for anonymous:
jmix.ui.main-screen-id=MainScreen
jmix.ui.initial-screen-id=MainScreenSideMenu
My 1.5.x MainScreen code for this is:
private boolean anonymousUser;
@Subscribe
public void onInit(InitEvent event) {
Authentication authentication = currentAuthentication.getAuthentication();
anonymousUser = (authentication instanceof AnonymousAuthenticationToken);
initLoginButtonAndLocales();
if (anonymousUser) {
return;
}
// continue with other logic for authenticated users
}
private void initLoginButtonAndLocales() {
loginButton.setVisible(anonymousUser);
logoutButton.setVisible(!anonymousUser);
userIndicator.setVisible(!anonymousUser);
localeSelect.setVisible(anonymousUser);
if (anonymousUser) {
localeSelect.setOptionsMap(messageTools.getAvailableLocalesMap());
localeSelect.setValue(jmixApp.getLocale());
localeSelect.addValueChangeListener(e -> {
Locale selectedLocale = e.getValue();
if (selectedLocale != null) {
jmixApp.setLocale(selectedLocale);
jmixApp.createTopLevelWindow();
}
});
}
}
@Subscribe("loginButton")
public void onLoginButtonClick(Button.ClickEvent event) {
String loginScreenId = uiProperties.getLoginScreenId();
Screen loginScreen = screens.create(loginScreenId, OpenMode.ROOT);
loginScreen.show();
}
THE PROBLEM(S)
I am not able to reproduce the functionality of my MainView in 2.2.x. No matter what permissions or application.properties I set; either the normal LoginView is presented together with the MainView, or I receive a strange error text covering the entire browser session.
If I use the following security configuration and application.properties…
@ResourceRole(name = AnonymousUserRole.NAME, code = AnonymousUserRole.CODE, description = "Anonymous NF role for everyone arriving at the site")
public interface AnonymousUserRole {
String NAME = "NF Anonymous User Role";
String CODE = "nf-anonymous-user-role";
@EntityAttributePolicy(entityClass = User.class, attributes = "*", action = EntityAttributePolicyAction.VIEW)
@EntityPolicy(entityClass = User.class, actions = EntityPolicyAction.READ)
void user();
@SpecificPolicy(resources = "ui.loginToUi")
void specify();
@MenuPolicy(menuIds = {"nf_MainViewMenuService#showMembershipView", "ConceptView", "FeaturesView", "LegalView"})
@ViewPolicy(viewIds = {"nf_MainViewMenuService#showMembershipView", "nf_Membership.detail", "ConceptView", "FeaturesView", "LegalView", "inputDialog", "LoginView", "MainView"})
void screens();
@EntityAttributePolicy(entityClass = Membership.class, attributes = "*", action = EntityAttributePolicyAction.VIEW)
@EntityPolicy(entityClass = Membership.class, actions = EntityPolicyAction.READ)
void membership();
@EntityPolicy(entityClass = BaseTraitsEntity.class, actions = EntityPolicyAction.READ)
@EntityAttributePolicy(entityClass = BaseTraitsEntity.class, attributes = "*", action = EntityAttributePolicyAction.VIEW)
void baseTraitsEntity();
}
jmix.ui.login-view-id = LoginView
jmix.ui.main-view-id = MainView
jmix.ui.default-view-id = nf_Search.list
jmix.ui.view.validation-notification-position = TOP_CENTER
jmix.ui.view.validation-notification-type = DEFAULT
jmix.ui.menu-config = com/company/nf/menu.xml
jmix.ui.composite-menu = true
…then opening http://localhost:8080 as an anonymous user shows the MainView but, without the IFrame content (static HTML page), but it does include my Concept, Features, Term & Conditions and Membership Options menu items, and the LoginView is also displayed on top of the MainView.
However, if I select my Concept, Features, Term & Conditions menu items, those views are not displayed, but the LoginView is reloaded and the MainView WorkArea IFrame in the background is still empty.
If I choose to login, then my MainView IFrame shows the following error message instead of the contents of my nfmain.en.html
file:
Could not navigate to 'nfmain.en.html'
Available routes:
<root>
add-condition
ambitions/:id (requires parameter)
availabilities/:id (requires parameter)
concept-view
contacts
contacts/:id (requires parameter)
covers
etc.
If I make the following modification to my application.properties (analog to jmix.ui.initial-screen-id= nf_MainScreen in CUBA and Jmix 1.5.x)…
jmix.ui.login-view-id = MainView
then I receive the following strange error text covering the entire view:
I also receive this error message if I remove the LoginView from my Anonymous role permissions…
@ViewPolicy(viewIds = {"nf_MainViewMenuService#showMembershipView", "nf_Membership.detail", "ConceptView", "FeaturesView", "LegalView", "inputDialog", "MainView"})
If I revert the application.properties back to:
jmix.ui.login-view-id = LoginView
and remove the LoginView from my Anonymous role permissions… (as in the example directly above)
@ViewPolicy(viewIds = {"nf_MainViewMenuService#showMembershipView", "nf_Membership.detail", "ConceptView", "FeaturesView", "LegalView", "inputDialog", "MainView"})
…then both the MainView and the LoginView are displayed together.
And if I also remove the MainView from the Anonymous role permissions…
@ViewPolicy(viewIds = {"nf_MainViewMenuService#showMembershipView", "nf_Membership.detail", "ConceptView", "FeaturesView", "LegalView", "inputDialog"})
…then the LoginView is still displayed.
I have also unsuccessfully tried other combinations after removing the following setting:
@SpecificPolicy(resources = "ui.loginToUi")
void specify();
How can I stop the LoginView from displaying itself? I want to open it explicitly from my MainView with the following code:
@Subscribe(id = "loginButton", subject = "clickListener")
public void onLoginButtonClick(final ClickEvent<JmixButton> event) {
viewNavigators.view(uiProperties.getLoginViewId()).navigate();
}
Why is it not possible to set jmix.ui.login-view-id = MainView
instead of LoginView
?
What can I do to migrate this functionality from 1.5.x to 2.2.x?
Thanks in advance for your support.
Best regards
Chris