Entrades amb etiqueta hook .

Minimizando conflictos de aui en nuestros Themes de Liferay

Data de publicació 28/09/16 18:03

Cuando queremos crear un Theme en Liferay en muchas ocasiones nos podemos encontrar con que los estilos aui entran en conflicto con los estilos que nosotros queremos aplicar. Un caso típico es el choque producido entre el bootstrap que utiliza aui y bootstrap 3.

¿Cómo podemos mantener los estilos Liferay para el propio Liferay sin que afecte a los estilos de nuestra web?

Pues no existe una fórmula mágica, pero podemos mitigar el impacto y que al menos desde fuera no se aprecien los conflictos.

Para ello haremos que los estilos aui no se apliquen a partir de la class "aui" (que se encuentra al inicio, en el <html>) sino a un nivel más bajo.

Esto lo podemos lograr mediante el Theme, modificando el fichero "aui.css" y añadiéndolo a "_diffs/css/":

 

_diffs\css\aui.css:

.aui .lfr-styles {
    ...
}

 

Cambiando .aui {…} por .aui .lfr-styles {…} provocamos que los estilos aui no se apliquen hasta que se encuentre algún elemento con la class lfr-styles, de este modo podemos controlar qué bloques queremos que usen estos estilos.

Como he dicho anteriormente esto sirve para mitigar los conflictos, pero no es perfecto y en el proceso podemos perder estilos genéricos (aui). Por ejemplo, si tenemos un “font-family” que antes aplicaba a “.aui body”, ahora aplicaría a “.aui .lfr-styles body”, si donde colocamos ese “.lfr-styles” está por debajo del body (que como veremos más adelante será lo más normal) ese estilo no se aplicaría.

Con este sistema algún estilo aui propio de Liferay podría verse afectado pero nuestra web y nuestros estilos custom estarían libres de conflictos.

Ahora, para poder seguir utilizando aui en lo que a Liferay se refiere (los portlets propios) podemos usar el mismo Theme y el Hook.

Desde el Theme, si queremos ahorrarnos trabajo del Hook, podemos hacer que aplique también los estilos directamente a los popup generados por Liferay donde se incluiría: el menú de configuración de los portlet, el seleccionar web contents, exportar/importar un portlet, seleccionar estructura o plantilla, etc.

Esto se puede conseguir añadiendo a la línea anterior otra class que está presente en este tipo de contenidos:

 

_diffs\css\aui.css:

.aui .lfr-styles, .aui .portal-popup{
    ...
}

 

Por otro lado, desde el Hook podemos incluir la class antes mencionada a los portlets propios de Liferay que queremos que continúen usando la clase aui. A continuación listamos los más típicos, y que archivo necesitaríamos modificar:

  • Menu Liferay (Dockbar):  \html\portlet\dockbar\view.jsp
  • Menu Liferay: add, edit, preview (Dockbar): \html\js\liferay\dockbar.js
  • Add WebContent, Edit WebContent (Journal): \html\portlet\journal\edit_article.jsp
  • Look and Feel (Portlet CSS): \html\portlet\portlet_css\view.jsp

El proceso para los jsp suele ser el mismo, usaremos uno de ejemplo:

 

\html\portlet\dockbar\view.jsp:

<%@ taglib uri="http://liferay.com/tld/util" prefix="liferay-util" %>
<%@ taglib uri="http://liferay.com/tld/theme" prefix="liferay-theme" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<liferay-theme:defineObjects />

<liferay-util:buffer var="html">
       <liferay-util:include page="/html/portlet/dockbar/view.portal.jsp" useCustomPage="false"  />
</liferay-util:buffer>

<div class="lfr-styles">
       <%= html %>
</div>

 

De esta forma incluimos un div por encima del contenido que queremos que use aui con nuestra nueva class.

En el caso del dockbar.js lo usamos por simplificar, ya que añadiendo nuestra class a tres líneas de código nos ahorramos hookear tres jsp.

 

\html\js\liferay\dockbar.js:

var TPL_ADD_CONTENT = '<div class="lfr-add-panel lfr-admin-panel lfr-styles" id="{0}" />';
var TPL_EDIT_LAYOUT_PANEL = '<div class="lfr-admin-panel lfr-edit-layout-panel lfr-styles" id="{0}" />';
var TPL_PREVIEW_PANEL = '<div class="lfr-admin-panel lfr-device-preview-panel lfr-styles" id="{0}" />';

 

Se pueden buscar atajos o simplificaciones, pero la cuestión es lograr incluir nuestra clase para que aui afecte sólo al contenido que nosotros queremos que afecte y no provoque conflictos en lo que ve el usuario, que al fin y al cabo, es para el que está pensado nuestro diseño.

Espero que os sirva de ayuda. Como he comentado al principio no es la solución perfecta, pero cuando tienes que forzar 25 estilos para que un simple botón se vea como tú quieres (estilos por defecto, estilos hover, active , focus, responsive, shadows, …) el reducir estos conflictos te pueden ahorrar mucho tiempo y dolores de cabeza.

Saludos.

Compartir la Capa de Servicios

Data de publicació 27/05/16 12:17

¡Buenas!

 

Hoy os explico diferentes maneras de compartir la capa de servicios que hayáis creado con el service builder entre diferentes portlets.

 

Primero, tenemos que contar que tenéis un portlet base base-portlet, el cuál habéis creado entidades y servicios con el service builder. Si quisieramos que un segundo portlet y un hook, por ejemplo, accedieran a estos servicios, replicarlos para cada plugin sería ineficiente y causante d’errores de inconsistencia en el futuro.

 

La mejor opción siempre es que todos los plugin accedan a la misma capa:


Untitled.png

 

 

Propondremos dos opciones:

 
  • Crear los diferentes portlets y hooks en un mismo plugin.

  • Compartir la capa de servicios a nivel de tomcat.

 

Crear los diferentes portlets y hooks en un mismo plugin

 

La idea es crear diferentes portlets en un mismo plugin de Liferay y tener unos servicios creados con el Service Builder. De esta manera, estos servicios seran disponibles y accesibles por cada portlet o hook dentro del plugin.

 

Compartir la capa de servicios a nivel de tomcat

 

Si la propuesta anterior no fuera posible, también podriamos exportar la capa de servicios mediante un archivo jar. Cuando ejecutas el service builder, este archivo se genera en: “your-portlet/docroot/WEB-INF/lib/your-portlet-service.jar”.

 

Este jar nos da acceso a los local service que hayas programado. Para que todos los plugin de tu instancia puedan usarlo este jar lo tienes que añadir en este directorio del servidor: “<<Liferay-tomcat>>tomcat-x.x.x/lib/ext”.

 

Recuerda, para cualquier actualización de los servicios, se tendrá que reemplazar el jar y, además, reiniciar el tomcat.


¡Espero que os haya ayudado!

Liferay Localización-Traducción

Data de publicació 05/12/14 08:51

Liferay ofrece la posibilidad de localizar el portal incluyendo en un mismo archivo la lista de literales a traducir mediante la utilización de keys (claves). Es posible incluir keys en el propio portlet o, a modo general, desde el Hook para que afecte a todo el portal.

 

Para las traducciones se utilizan keys a modo de key=traduccion

En función del idioma en el que estemos visitando el portal, Liferay buscará la key en el Language_xx.properties que corresponda a ese idioma, donde xx es el código identificativo del idioma.

Si no encuentra la key, la buscará en el Language.properties y si tampoco se encuentra en ese archivo la buscará en las que Liferay tiene por defecto ( https://github.com/liferay/liferay-portal/tree/master/portal-impl/src/content ).

En el caso de que la key utilizada no esté especificada en ninguno de los archivos mencionados, simplemente, no realizará el cambio y mostrará el String de la key tal cual.

*En el blog anterior se puede ver cómo configurar el Hook para que detecte los archivos con las claves y donde situar dichos archivos.

 

Para utilizar éste sistema de traducción se debe incluir la key en cada Language_xx.properties de cada uno de los idiomas a los que queramos localizar el portal junto con su respectiva traducción. Una vez hecho esto, se pueden usar dichas keys dentro de nuestro código.

La forma de utilizar éstas keys puede realizarse mediante el tag de liferay liferay-ui:message o usando la clase java LanguageUtil.

En el caso de que parte del contenido a traducir sea dinámico, Liferay también permite el paso de parámetros en las keys.

 

A continuación se muestran dos ejemplos, uno simple y otro con parámetros, así como la declaración en el Language properties y las diferentes formas de utilizarlo.

 

Ejemplo (básico):

Código dentro del jsp:

Archivo con el código (mediante tags):

<liferay-ui:message key="ultimas-noticias" />

Archivo con el código (con la clase):

LanguageUtil.get(pageContext, "ultimas-noticias" );

Paso 1: Para la key “ultimas-noticias” no existe ninguna traducción por defecto y no la hemos traducido ni en el Language_es.properties ni en el Language.properties, por lo tanto, muestra la key tal cual, sin traducción.

Resultado:

01.png

Paso 2: Traducimos la key “ultimas-noticias” en el Language_es.properties.

Language_es.properties:

ultimas-noticias=Últimas noticias

Muestra “Últimas noticias” si navegamos en español, pero sigue mostrando "ultimas-noticias" si navegamos en inglés.

Resultado:

02.png 03.png

Paso 3: Traducimos la key “ultimas-noticias” en el Language.properties.

Language.properties:

ultimas-noticias=Últimas noticias

Muestra “Últimas noticias” independientemente del idioma por el que naveguemos.

Resultado:

04.png

Paso 4: Traducimos la key “ultimas-noticias” en el Language_en.properties.

Language_en.properties:

ultimas-noticias=Last news

Ahora muestra “Last news” cuando navegamos en inglés y “Últimas noticias” en el resto de idiomas.

Resultado:

02.png 05.png

 

Ejemplo (con parámetros):

Language_es.properties:

delete-profile-x=Eliminado el perfil de {0} del servicio.

Archivo con el código (mediante tags):

<liferay-ui:message key="delete-profile-x" arguments="<%= user.getName() %>" />

Archivo con el código (con la clase):

LanguageUtil.format(pageContext, "delete-profile-x" , user.getName());

Resultado:

Eliminado el perfil de Juan del servicio.

 

Nota: Hay que tener en cuenta que si sobrescribimos una traducción por defecto es probable que afectemos a literales que usa Liferay, por ejemplo, si modificamos “search” en el Hook no solo afectará a nuestros portlets, sino que también se verá afectado el texto que aparezca en el botón del buscador de Liferay.

 

Esperamos que os sea de ayuda. ¡ Hasta la próxima !

Liferay Hook

Data de publicació 21/11/14 08:47

Un Hook es una herramienta que ofrece Liferay para poder, entre otras cosas, sobrescribir funcionalidades que vienen por defecto. Modificando un archivo de una ruta concreta, el archivo del Hook pasa a ser el utilizado en lugar del que utilizaría un Liferay no hookeado. La ventaja de éste sistema es que, retirando el Hook, Liferay regresa a su estado original.

Los usos más comunes son la modificación del comportamiento de ciertas funcionalidades, y la localización del sitio web (traducción a diferentes idiomas).

 

Pasos para la utilización de un Hook:

1. Crear el hook

- Creamos un nuevo Liferay Plugin Project

01.png

 

- Elegimos el nombre del proyecto, seleccionamos para que SDK se aplicará el Hook y en el tipo de plugin seleccionamos “Hook”.

02.png

Esto generará el árbol básico junto con los archivos de configuración

03.png

 

2. Configurar el hook

En el archivo "liferay-hook.xml " es donde se indican los archivos de donde se extraerán las traducciones y el directorio donde se colocarán los archivos a modificar.

<hook>
      <language-properties>content/Language_es.properties</language-properties>
      <language-properties>content/Language_en.properties</language-properties>
      <language-properties>content/Language_fr.properties</language-properties>
      <language-properties>content/Language_de.properties</language-properties>
      <language-properties>content/Language.properties</language-properties>
      <custom-jsp-dir>/META-INF/custom_jsps</custom-jsp-dir>
<hook>

 

3. Realizar las modificaciones

3.1 Modificar funcionalidades

Lo primero es saber la ruta en la que se encuentran los archivos a modificar. Los archivos base los podemos encontrar en la carpeta ROOT dentro del liferay-portal.

En nuestro caso modificaremos el comportamiento del buscador de Liferay el cual se encuentra en "\ROOT\html\portlet\search”, para ello copiamos los archivos que nos interesa modificar.

Una vez conocemos su ruta la replicamos en nuestro hook, teniendo en cuenta que el ROOT es nuestra carpeta custom_jsps (la que definimos en el paso anterior).

- Path original: \ROOT\html\portlet\search

- Path en el hook: \custom_jsps\html\portlet\search

 Ya podemos pegar en su interior los archivos que posteriormente modificaremos. Solo es necesario copiar los archivos a modificar.

05.png

06.png

 

3.2 Añadir traducciones

A diferencia de lo que hemos hecho con el buscador, los archivos utilizados para los idiomas no machacan las traducciones por defecto (a no ser que usemos la misma key) sino que se añaden a las que ya hay.

Para añadir la localización a distintos idiomas se necesita un archivo por cada idioma que deseamos traducir. El nombre de los archivos es Language_xx.properties donde xx corresponde al código del idioma.

Estos archivos van en la ruta que hemos definido en el "liferay-hook.xml" que suele ser dentro de "WEB-INF/src/content"

07.png

Las traducciones que realicemos en estos archivos afectarán a todo el portal.

 

4.2 Aplicar los cambios

Una vez hemos realizado las modificaciones que nos interesan y/o añadido las traducciones a los idiomas deseados, solo queda realizar el build e instalarlo en nuestro Liferay.

 

En el próximo blog os explicaremos con más detalle cómo utilizar los archivos del Language para realizar la localización del portal. ¡ Nos leemos !

Liferay - Redirect after login

Data de publicació 06/03/14 09:16

Programando uno de nuestros productos, decidimos incorporar la siguiente funcionalidad: En el caso de que el usuario que accede a la aplicación pertenezca a una única organización (que es la mayoría de los casos), se debería redirigir al usuario, después de hacer login, a la página de la organización.
Mirando la documentación de Liferay, vemos que esto se puede hacer como una post-login action dentro de un hook.
Para ello tendremos que hacer lo siguiente:


Primero, creamos el archivo portal.properties, si no existe ya, dentro de la carpeta src/. Dentro, añadimos la siguiente línea:
...
login.events.post=com.sample.action.PostLoginAction
...


Segundo, añadimos (si no existe ya) la siguiente línea en el archivo liferay-hook.xml:
<hook>
    ...
    <portal-properties>portal.properties</portal-properties>
    ...
</hook>


Tercero, creamos el archivo PostLoginAction.java en la carpeta src/com/sample/action/ con el siguiente contenido:
package com.sample.action;
import java.util.ArrayList;
import java.util.List;
import com.liferay.portal.kernel.events.Action;
import com.liferay.portal.kernel.util.PropsKeys;
import com.liferay.portal.kernel.util.PropsUtil;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.portal.model.Group;
import com.liferay.portal.model.User;
import com.liferay.portal.service.GroupLocalServiceUtil;
import com.liferay.portal.service.UserLocalServiceUtil;
import com.liferay.portal.util.PortalUtil;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class PostLoginAction extends Action {

    public void run(HttpServletRequest req, HttpServletResponse res) {
        long userId = 0;
        User user = null;
        String redirect = req.getAttribute("javax.servlet.forward.path_info").toString();
        if(Validator.isNull(redirect)){
            redirect = "/c";
        }
        try{
            userId = Long.parseLong(req.getRemoteUser());
            user = UserLocalServiceUtil.getUser(userId);
        }
        catch(Exception e){ e.printStackTrace(); }
        if(redirect.equals("/c") && Validator.isNotNull(user)){
            // Miramos los grupos a los que pertenece el usuario
            List<Group> aux = new ArrayList<Group>();
            List<Group> groups = new ArrayList<Group>();
            try {
                aux = GroupLocalServiceUtil.getUserGroups(user.getUserId());
                for(Group g:aux){
                    if(g.isActive() && g.isOrganization()){
                        groups.add(g);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            if(groups.size()==1){
                // Si solo hay un grupo, redireccionamos ahí
                redirect = "/group"+groups.get(0).getFriendlyURL();
                redirect = PortalUtil.escapeRedirect(redirect);
                redirect = getCompleteRedirectURL(req, redirect);
                try {
                    res.sendRedirect(redirect);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    protected String getCompleteRedirectURL(
        HttpServletRequest request, String redirect) {
        HttpSession session = request.getSession();

        Boolean httpsInitial = (Boolean)session.getAttribute(
            "HTTPS_INITIAL");
        String portalURL = null;

        if (Boolean.valueOf(PropsUtil.get(PropsKeys.COMPANY_SECURITY_AUTH_REQUIRES_HTTPS)) &&
            !Boolean.valueOf(PropsUtil.get(PropsKeys.SESSION_ENABLE_PHISHING_PROTECTION)) &&
            (httpsInitial != null) && !httpsInitial.booleanValue()) {
            portalURL = PortalUtil.getPortalURL(request, false);
        }
        else {
            portalURL = PortalUtil.getPortalURL(request);
        }
        return portalURL.concat(redirect);
    }
}

Analizando este código vemos que la clase contiene un método run, que es el que se ejecuta después de que Liferay realice la acción de login (y solamente si el login es correcto). Esta funcion toma dos parámetros req y res.


Lo primero que hicimos para saber con qué podíamos trabajar, fue sacar por la consola todos los parámetros y atributos de la variable req. Así, vimos que las variables de login y password no las podíamos coger como parámetros de la petición, ya que no estaban el la variable req. Mirando los métodos accesibles desde req, encontramos getRemoteUser y vemos, sacando este valor por la consola, que contiene  en formato String el id del usuario que se acaba de loguear.


El segundo escollo a superar es cómo saber si la petición original tenía redirect o no. Como el redirect no lo podemos leer como parámetro porque no está en la variable req, miramos los atributos de la petición y vemos que el atributo "javax.servlet.forward.path_info" contiene el valor "/c" si no hay redirect, y el valor del redirect en el caso de que éste exista. Esto es importante porque si hay redirect, queremos que nos lleve ahí después de loguearnos, y si no hay redirect, nos tiene que llevar a la raiz del site de la organización.


Así, en el caso de que "javax.servlet.forward.path_info" sea igual que "/c" y el usuario no sea null, miramos los grupos a los que pertenece el usuario, que estén activos y sean organizaciones, y si solamente hay uno, llevamos al usuario a su página raiz.

Liferay - Términos de uso multisite

Data de publicació 31/03/14 13:19

A raíz de una incidencia recibida hemos visto que la configuración por defecto de Liferay no permite tener varios sites dentro de una instancia de Liferay con diferentes términos de uso.

Concretamente se recibe la solicitud por parte de uno de nuestros clientes de la creación de un site público con acceso privado donde se deben mostrar unos términos de uso determinados (específicos del site). El problema está en que en esta misma instancia de Liferay existe una intranet donde los usuarios deben aceptar también sus propios términos de uso (diferentes a los del site).

Para dar una solución a esta incidencia hemos analizado el funcionamiento por defecto de los términos de uso. Si un usuario de Liferay no tiene el campo agreedToTermsOfUse de la tabla User_ a true se ejecuta el archivo terms_of_use.jsp ubicado en html/portal. Los términos de uso pueden ser los propios de Liferay, en tal caso no hay que hacer nada más o unos propios que implica tener que crear un web content y modificar el archivo portal-ext.properties para añadir el group_id y el article_id de los términos de uso personalizados.

Fragmento de terms_of_use.jsp:

...
<c:when test="<%= (PropsValues.TERMS_OF_USE_JOURNAL_ARTICLE_GROUP_ID > 0) &&

Validator.isNotNull(PropsValues.TERMS_OF_USE_JOURNAL_ARTICLE_ID) %>">
<liferay-ui:journal-article groupId="<%= PropsValues.TERMS_OF_USE_JOURNAL_ARTICLE_GROUP_ID

%>" articleId="<%= PropsValues.TERMS_OF_USE_JOURNAL_ARTICLE_ID %>" />
...

Esta manera de actuar que propone Liferay solo permite especificar un único web content de términos de uso común para toda la instancia de Liferay. Así que para resolver el problema, pero manteniendo el funcionamiento actual sin tener que modificar la base de datos y/o el core de Liferay, hemos optado por la siguiente solución:

  • Hook: Para resetear el campo agreedToTermsOfUse de la tabla User_ cada vez que se le asigna un nuevo site a un usuario de Liferay. Lo que hace este hook es:
  1. Seleccionamos los sites (groupId) a los que ya pertenece el usuario y los comparamos con la lista que nos llega como parámetro de entrada (que son todos, los nuevos y los ya asociados).
  2. Para cada site nuevo del usuario nos recorremos todos sus web contents mediante el motor de búsqueda de Liferay.
  3. Si existe algún web content que contenga el campo is_terms_of_use con valor yes, forzamos que se tengan que volver a aceptar los términos de uso.

Archivo: CustomUserLocalServiceImpl.java. 

import java.util.ArrayList;
import java.util.List;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.kernel.search.BooleanQuery;
import com.liferay.portal.kernel.search.BooleanQueryFactoryUtil;
import com.liferay.portal.kernel.search.Document;
import com.liferay.portal.kernel.search.Field;
import com.liferay.portal.kernel.search.Hits;
import com.liferay.portal.kernel.search.SearchContext;
import com.liferay.portal.kernel.search.SearchEngineUtil;
import com.liferay.portal.kernel.search.Sort;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.portal.model.Group;
import com.liferay.portal.model.User;
import com.liferay.portal.model.UserGroupRole;
import com.liferay.portal.service.GroupLocalServiceUtil;
import com.liferay.portal.service.ServiceContext;
import com.liferay.portal.service.UserLocalService;
import com.liferay.portal.service.UserLocalServiceUtil;
import com.liferay.portal.service.UserLocalServiceWrapper;
import com.liferay.portlet.journal.model.JournalArticle;

public class CustomUserLocalServiceImpl extends UserLocalServiceWrapper {

    public CustomUserLocalServiceImpl(UserLocalService userLocalService) {
        super(userLocalService);
    }
    
    public User updateUser(
            long userId, String oldPassword, String newPassword1,
            String newPassword2, boolean passwordReset,
            String reminderQueryQuestion, String reminderQueryAnswer,
            String screenName, String emailAddress, long facebookId,
            String openId, String languageId, String timeZoneId,
            String greeting, String comments, String firstName,
            String middleName, String lastName, int prefixId, int suffixId,
            boolean male, int birthdayMonth, int birthdayDay, int birthdayYear,
            String smsSn, String aimSn, String facebookSn, String icqSn,
            String jabberSn, String msnSn, String mySpaceSn, String skypeSn,
            String twitterSn, String ymSn, String jobTitle, long[] groupIds,
            long[] organizationIds, long[] roleIds,
            List<UserGroupRole> userGroupRoles, long[] userGroupIds,
            ServiceContext serviceContext)
        throws PortalException, SystemException {

        if (groupIds != null) {
          List<Group> oldGroups = GroupLocalServiceUtil.getUserGroups(userId);
          List<Long> oldGroupIds = new ArrayList<Long>(oldGroups.size());

for (Group oldGroup : oldGroups) {
                long oldGroupId = oldGroup.getGroupId();
                oldGroupIds.add(oldGroupId);

            }

            for (long newGroupId : groupIds) {
                if (!oldGroupIds.contains(newGroupId)) {
                    User user = UserLocalServiceUtil.getUser(userId);
                    String conds = "";
                    
                    // Buscamos si hay terminos de uso en este nuevo site
                    SearchContext searchContext = new SearchContext();
                    searchContext.setSearchEngineId(SearchEngineUtil.SYSTEM_ENGINE_ID);
                    BooleanQuery contextQuery = BooleanQueryFactoryUtil.create(searchContext);
                    contextQuery.addRequiredTerm(Field.GROUP_ID, newGroupId);
                    contextQuery.addRequiredTerm(Field.ENTRY_CLASS_NAME,

JournalArticle.class.getName());
                    contextQuery.addExactTerm("is_terms_of_use", "yes");
                    
                    // Añadimos ordenación (version descendente)
                    Sort sort = new Sort();
                    sort.setFieldName(Field.VERSION);
                    sort.setType(Sort.INT_TYPE);
                    sort.setReverse(true);
                    
                    Hits hits = SearchEngineUtil.search(user.getCompanyId(),

contextQuery, 0, 1);
                    Document[] docs = hits.getDocs();
                    for(int i=0;i<docs.length;i++){
                        conds += docs[i].get(user.getLocale(), "web_content/content");
                    }
                    
                    // Al añadir al usuario a un grupo nuevo, forzamos que se tengan que  
                    //
volver a aceptarlos términos de uso
                    if(Validator.isNotNull(conds)){
                        user.setAgreedToTermsOfUse(false);
                        UserLocalServiceUtil.updateUser(user, false);
                    }
                }
            }
        }

   return super.updateUser(userId, oldPassword, newPassword1, newPassword2,
      passwordReset, reminderQueryQuestion, reminderQueryAnswer, screenName,
       emailAddress, facebookId, openId, languageId, timeZoneId, greeting,
       comments, firstName, middleName, lastName, prefixId, suffixId,
       male, birthdayMonth, birthdayDay,birthdayYear, smsSn, aimSn,
       facebookSn, icqSn, jabberSn, msnSn, mySpaceSn, skypeSn, twitterSn, ymSn, 
       jobTitle, groupIds, organizationIds, roleIds, userGroupRoles, userGroupIds, serviceContext);
    }
}

  • Modificar el archivo terms_of_use.jsp para mostrar todos los trminos de uso de todos los sites asociados al usuario.
  1. Seleccionamos los sites (grupos) a los que pertenece el usuario.
  2. Para cada site del usuario nos recorremos todos sus web contents mediante el motor de búsqueda de Liferay.
  3. Si existe algún web content que contenga el campo is_terms_of_use con valor yes, guardamos su contenido en una variable (conds).
  4. En el caso que conds tenga valor mostraremos su contenido, en caso contrario continuará con el proceso habitual de Liferay.

Archivo: terms_of_use.jsp 

<%
String currentURL = PortalUtil.getCurrentURL(request);

String referer = ParamUtil.getString(request, WebKeys.REFERER, currentURL);

if (referer.equals(themeDisplay.getPathMain() + "/portal/update_terms_of_use")) {
    referer = themeDisplay.getPathMain() + "?doAsUserId=" + themeDisplay.getDoAsUserId();
}

// Obtenemos los grupos a los que pertenece el usuario
List<Group> grupos = new ArrayList<Group>();
try{
    grupos = GroupLocalServiceUtil.getUserGroups(user.getUserId());
}
catch(Exception e){}
String conds = "";
for(Group g:grupos){
    SearchContext searchContext = new SearchContext();
    searchContext.setSearchEngineId(SearchEngineUtil.SYSTEM_ENGINE_ID);
    BooleanQuery contextQuery = BooleanQueryFactoryUtil.create(searchContext);
    contextQuery.addRequiredTerm(Field.GROUP_ID, g.getGroupId());
    contextQuery.addRequiredTerm(Field.ENTRY_CLASS_NAME, JournalArticle.class.getName());
    contextQuery.addExactTerm("is_terms_of_use", "yes");
    
    // Añadimos ordenación (version descendente)
    Sort sort = new Sort();
    sort.setFieldName(Field.VERSION);
    sort.setType(Sort.INT_TYPE);
    sort.setReverse(true);
    
    Hits hits = SearchEngineUtil.search(company.getCompanyId(), contextQuery, 0, 1);
    Document[] docs = hits.getDocs();
    for(int i=0;i<docs.length;i++){
        if(Validator.isNull(docs[i].get(locale, "web_content/content"))) continue;
        conds += docs[i].get(locale, "web_content/content")+"<br />";
    }
}
%>

<aui:form action='<%= themeDisplay.getPathMain() + "/portal/update_terms_of_use"

%>' name="fm" cssClass="content-form">
    <aui:input name="doAsUserId" type="hidden"

value="<%= themeDisplay.getDoAsUserId() %>" />
    <aui:input name="<%= WebKeys.REFERER %>" type="hidden" value="<%= referer %>" />

    <c:choose>
        <c:when test="<%= Validator.isNotNull(conds) %>">
            <%= conds  %>
        </c:when>
        <c:when test="<%= (PropsValues.TERMS_OF_USE_JOURNAL_ARTICLE_GROUP_ID > 0)

&& Validator.isNotNull(PropsValues.TERMS_OF_USE_JOURNAL_ARTICLE_ID) %>">
            <liferay-ui:journal-article groupId="<%= PropsValues.TERMS_OF_USE_JOURNAL

_ARTICLE_GROUP_ID %>" articleId="<%= PropsValues.TERMS_OF_USE_JOURNAL_ARTICLE_ID %>" />
        </c:when>
        <c:otherwise>
            Welcome to our site. We maintain this web site as a service

to our members. By using our site, you are agreeing to comply with and

be bound by the following terms of use. Please review the following

terms carefully. If you do not agree to these terms, you should not use this site.

...

  • Crear una estructura Global, que incluya los campos content y is_terms_of_use 

  • Crear los web contents, uno por cada site con términos de uso, utilizando la estructura creada en el punto anterior.

Siguiendo estos pasos, cada vez que a un usuario se le asigne un nuevo site que contenga un web content con la estructura terms_of_use y el valor de is_terms_of_use a yes se le cambiará el valor del campo agreedToTermsOfUse de la tabla User_ a false (mediante el hook) y la próxima vez que acceda a alguno de los sites le aparecerán todos los web contents asociados a la estructura terms_of_use de los sites a los que esté asociado.

Esta solución siempre mostrará todos los términos de uso cada vez que se le asocie un site nuevo a un usuario. Se podría mejorar para hacer que solo muestre los términos que no haya aceptado, pero esta solución implicaría tocar el core de Liferay, base de datos, workflows, etc.Opción no recomendada desde Sonicon.

 

— 20 Items per Page
S'estan mostrant els 6 resultats.

Bloggers recents Bloggers recents

Oscar Rodríguez
Apunts: 9
Estrelles: 2
Data: 28/09/16
David Berruezo
Apunts: 14
Estrelles: 1
Data: 22/07/16
Javi Martín
Apunts: 2
Estrelles: 1
Data: 20/05/16
Javier Torres
Apunts: 5
Estrelles: 3
Data: 11/04/16
Sergi Mingueza
Apunts: 4
Estrelles: 1
Data: 19/10/15
Matilde Gallardo
Apunts: 1
Estrelles: 0
Data: 26/02/15
Adrià Vilà
Apunts: 4
Estrelles: 4
Data: 31/08/14
Elena Ruiz
Apunts: 1
Estrelles: 2
Data: 13/03/14