Liferay – Términos de uso multisite


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_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 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_ 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.


Leave a Reply

Your email address will not be published. Required fields are marked *