Administration menu

Hello.

I’m having a try on JMIX (currently using Cuba): I was surprised to see that, by default, the admin menu is almost empty. Reading the forum, I saw how to add the Entity Inspector, but I still don’t know how to display and use the Scheduled Tasks and the User Sessions Log that I find so useful.

Any advice on how to make these things enabled ?

Many thanks.

O.

Hi.
We made the decision to stop support for our scheduled tasks engine and use https://www.quartz-scheduler.org instead.

Use https://github.com/Haulmont/jmix-sessions add-on as an alternative to User Sessions Log.

Full list of add-ons you can find here

Regards,
Natalia

Thanks.
Is there an example of using Quartz with Jmix available ?
Just a Hello world example, to see the creation of the Job would be enough.
The documentation is very light on this particular context.

Thanks.

Is there alternative add-on for CUBA Administration “Server Log” ?

OK I finally succeeded to set it up.

Any clues on how I can get the users’ session logs with this new jmix ?

Thanks in advance

Look at the authentication events. You can register login/logout events of your users, for example by defining an entity with a browse screen and creating such entities in the authentication event listeners.

Regards,
Konstantin

1 Like

Thanks @krivopustov, this helps.
However, I have a last question: this doesn’t manage logout by time out, or logout by closing the browser window (as it was handled in CUBA). Is there a way to keep control on that and not keep ghost logins?
Have a nice day.
O.

You can use the standard HttpSessionListener to catch when HTTP session is destroyed.

Below is a solution that creates a log record on user login and updates the record when the user logs out or the session expires.

The log item entity:

@JmixEntity
@Table(name = "USER_AUTHENTICATION_LOG")
@Entity
public class UserAuthenticationLog {
    @JmixGeneratedValue
    @Column(name = "ID", nullable = false)
    @Id
    private UUID id;

    @Column(name = "VERSION", nullable = false)
    @Version
    private Integer version;

    @Column(name = "USERNAME", nullable = false)
    @NotNull
    private String username;

    @Column(name = "LOGGED_IN")
    private LocalDateTime loggedIn;

    @Column(name = "LOGGED_OUT")
    private LocalDateTime loggedOut;

    @Column(name = "SESSION_ID")
    private String sessionId;

    // getters and setters
}

The listener bean:

@Component
public class AuthenticationEventListener implements HttpSessionListener {

    @Autowired
    private UnconstrainedDataManager dataManager;

    @EventListener
    public void onInteractiveAuthenticationSuccess(InteractiveAuthenticationSuccessEvent event) {
        UserAuthenticationLog logItem = dataManager.create(UserAuthenticationLog.class);
        User user = (User) event.getAuthentication().getPrincipal();
        logItem.setUsername(user.getUsername());
        logItem.setLoggedIn(LocalDateTime.now());
        // Jmix provides session ID in ClientDetails class
        logItem.setSessionId(((ClientDetails) event.getAuthentication().getDetails()).getSessionId());
        dataManager.save(logItem);
    }

    @EventListener
    public void onLogoutSuccess(LogoutSuccessEvent event) {
        // we use session ID to find matching login record
        String sessionId = ((ClientDetails) event.getAuthentication().getDetails()).getSessionId();
        UserAuthenticationLog logItem = getLogOptional(sessionId)
                .orElseGet(() -> {
                    UserAuthenticationLog newLogItem = dataManager.create(UserAuthenticationLog.class);
                    User user = (User) event.getAuthentication().getPrincipal();
                    newLogItem.setUsername(user.getUsername());
                    return newLogItem;
                });

        if (logItem.getLoggedOut() == null) {
            logItem.setLoggedOut(LocalDateTime.now());
            dataManager.save(logItem);
        }
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        // we use session ID to find matching login record
        getLogOptional(se.getSession().getId())
                .ifPresent(logItem -> {
                    if (logItem.getLoggedOut() == null) {
                        logItem.setLoggedOut(LocalDateTime.now());
                        dataManager.save(logItem);
                    }
                });
    }

    private Optional<UserAuthenticationLog> getLogOptional(String sessionId) {
        return dataManager.load(UserAuthenticationLog.class)
                .query("e.sessionId = ?1", sessionId)
                .optional();
    }
}

To test the session expiration in UI, use the following property:

# 2 minutes 
jmix.ui.http-session-expiration-timeout-sec = 120

Regards,
Konstantin

1 Like