Кастомный порлет редактирования профиля пользователя

У Liferay есть одна проблема (вернее, проблем-то много, но сегодня мы будем говорить об одной из них) - у него есть мощная панель управления, часть которой является и управление профилем пользователя (Account Settings). Проблема в том - что она слишком мощная.

В половине проектов, где пользоваталю позволяется редактировать свои данные, нас просят полностью закрыть пользоателю доступ в панель управления, а так же кардинально упростить портлет пользовательских настроек.

Тут есть несколько вариантов - можно чисто настройками попробовать отрегулировать набор табов в портлете "Account Settings" - но это чаще всего не спасает - все равно "слишком" сложно.

Можно хуками попробовать поменять стандартный портлет - но тоже не лучший вариант. Хуки хороши кода надо немного что-то подправить  но не когда кардинально переделать.

Вариант который рассмотрим сегодня - подсунуть свой портлет.

Вопрос написания самого портлета тут затрагивать не будет - там все достаточно просто - JSP в формой и полями и портлетный класс с обработкой Action-а. Рассмотрим внимательно именно как сделать так, что бы наш портлет показывался вместо Account Settings, например когда пользователь кликает "My Account" даже в теме по умолчанию.

Добавление портлета в Control Panel

Первое что надо сделать - это добавить портлет в Control Panel - в секцию "my", причем вес проставить меньше чем 1.0  - чтобы он был первым (1.0 - это вес стандартного портлета My Account). Для этого в liferay-portlet.xml добавляем

<control-panel-entry-category>my</control-panel-entry-category>
<control-panel-entry-weight>0.5</control-panel-entry-weight> 

Фикс баги для версии Liferay ниже 6.2.2

К сожалению как минимум в Liferay 6.2.1 (подозреваю что и более ранних) есть бага (в 6.2.2 уже исправлена), в результате которой неправильно формируется ссылка MyAccountURL (которая и используется для открытия popup-а с портлетом пользовальского профиля). Ошибка в строке 1206 класса ServicePreAction: https://github.com/liferay/liferay-portal/blob/6.2.1-ga2/portal-impl/src/com/liferay/portal/events/ServicePreAction.java#L1206 - если сравнить с аналогичным местом в 6.2.2 - https://github.com/liferay/liferay-portal/blob/6.2.2-ga3/portal-impl/src/com/liferay/portal/events/ServicePreAction.java#L1215 - то видно - что необходимо использовать не метод getPortletName() а метод getPortletId().
Если апгрейд до 6.2.2 не ваш вариант - то можно исправить эту ошибку написанием своего класса ServicePreAction:
1. В liferay-hook.xml добавляем
<portal-properties>portal-ext.properties</portal-properties>
2. Создаем файл (в корне src) portal-ext.properties:
servlet.service.events.pre=ru.emdev.events.ServicePreAction
3. Создаем свой класс ServicePreAction со следующим кодом (мы формируем правильный URLMyAccount:
public class ServicePreAction extends Action {
    private static Log _log = LogFactoryUtil.getLog(ServicePreAction.class);

    @Override
    public void run(HttpServletRequest request, HttpServletResponse response)
                throws ActionException {
        try {
            ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(WebKeys.THEME_DISPLAY);
            Portlet myAccountPortlet = PortalUtil.getFirstMyAccountPortlet(themeDisplay);

            if (myAccountPortlet != null) {
                long controlPanelPlid = PortalUtil.getControlPanelPlid(themeDisplay.getCompanyId());
                long scopeGroupId = PortalUtil.getScopeGroupId(request);

                long refererPlid = ParamUtil.getLong(request, "refererPlid");
                if (LayoutLocalServiceUtil.fetchLayout(refererPlid) == null) {
                    refererPlid = 0;
                }

                long plid = ParamUtil.getLong(request, "p_l_id");

                LiferayPortletURL myAccountURL = PortletURLFactoryUtil.create(request,  myAccountPortlet.getPortletId(), controlPanelPlid, PortletRequest.RENDER_PHASE);

                if (scopeGroupId > 0) {
                    myAccountURL.setDoAsGroupId(scopeGroupId);
                }

                if (refererPlid > 0) {
                    myAccountURL.setRefererPlid(refererPlid);
                } else {
                    myAccountURL.setRefererPlid(plid);
                }

                myAccountURL.setWindowState(WindowState.MAXIMIZED);

                themeDisplay.setURLMyAccount(myAccountURL);
            }
        }  catch (Exception ex) {
            _log.warn("Cannot fix my account url", ex);
        }
    }
}
 

Настройка прав доступа к портлетам

После этого для роли User необходимо дать право "Access in My Account" для нашего портлета (Control Panel -> Roles -> User -> Define Permissions -> находим наш портлет -> включаем галку Access in My Account)

Для того, что бы убрать из верхнего меню другие портлеты (My Account, My Submissions, My Workflow Tasks) - для соотвествующих портлатов аналогичным образом надо будет убрать этот Permission.

Как результат - получаем popup только с нашим портлетом настроек профиля пользователя.