--- /dev/null
+/*******************************************************************************
+ * Copyright � Igor Barma, Alexandre Desoubeaux, Christian Martel, Eric Brun, Mathieu Amblard, Gwenael Gevet, Pierre Guillot, 2012
+ * Copyright Alexandre Desoubeaux, Christian Martel, Cedric Lecarpentier, Alexandre Lefevre, Marc Salvat 2014-2016
+ * Copyright Alexandre Desoubeaux, Christian Martel, Cedric Lecarpentier, Marc Salvat, Marc Suarez, Harifetra Ramamonjy 2017
+ *
+ * This file is part of the work and learning management system Pentila Nero.
+ *
+ * Pentila Nero is free software. You can redistribute it and/or modify since
+ * you respect the terms of either (at least one of the both license) :
+ * - under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ * - the CeCILL-C as published by CeCILL-C; either version 1 of the
+ * License, or any later version
+ * - the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the license,
+ * or (at your option) any later version.
+ *
+ * There are special exceptions to the terms and conditions of the
+ * licenses as they are applied to this software. View the full text of
+ * the exception in file LICENSE-PROJECT.txt in the directory of this software
+ * distribution.
+ *
+ * Pentila Nero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Licenses for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * and the CeCILL-C and the GNU Lesser General Public License along with
+ * Pentila Nero. If not, see :
+ * <http://www.gnu.org/licenses/> and
+ * <http://www.cecill.info/licences.fr.html>.
+ ******************************************************************************/
+package com.pentila.entSavoie.listeners;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.ldap.LdapContext;
+
+import com.liferay.portal.ModelListenerException;
+import com.liferay.portal.kernel.exception.PortalException;
+import com.liferay.portal.kernel.exception.SystemException;
+import com.liferay.portal.kernel.log.Log;
+import com.liferay.portal.kernel.log.LogFactoryUtil;
+import com.liferay.portal.kernel.util.PrefsPropsUtil;
+import com.liferay.portal.model.ModelListener;
+import com.liferay.portal.model.Organization;
+import com.liferay.portal.model.OrganizationConstants;
+import com.liferay.portal.model.Role;
+import com.liferay.portal.model.RoleConstants;
+import com.liferay.portal.model.User;
+import com.liferay.portal.model.UserGroup;
+import com.liferay.portal.security.ldap.PortalLDAPUtil;
+import com.liferay.portal.service.OrganizationLocalServiceUtil;
+import com.liferay.portal.service.RoleLocalServiceUtil;
+import com.liferay.portal.service.UserGroupLocalServiceUtil;
+import com.liferay.portal.service.UserGroupRoleLocalServiceUtil;
+import com.liferay.portal.service.UserLocalServiceUtil;
+import com.pentila.entSavoie.ENTRolesConstants;
+import com.pentila.entSavoie.directory.OrganizationFinderServiceUtil;
+import com.pentila.entSavoie.utils.ENTCacheUtils;
+import com.pentila.entSavoie.utils.ENTMainUtilsLocalServiceUtil;
+import com.pentila.entSavoie.utils.ENTOrganizationsUtil;
+
+/**
+ * @author Lancelot SIX
+ *
+ * Cette classe est utilisée pour monitorer les evenements sur les UserGroup.
+ * Ces groupes sont ceux qui sont importés du LDAP. Ainsi, nous pouvons
+ * dupliquer les changements de ces groupes vers les Organizations (groupes
+ * institutionnels du Liferay).
+ *
+ */
+public class UserGroupListener implements ModelListener<UserGroup> {
+
+ public void onAfterAddAssociation(Object arg0, String arg1, Object arg2)
+ throws ModelListenerException {
+ //Quand un utilisateur est ajout� dans un UserGroup, on l'ajoute dans
+ //les organizations correspondantes ainsi que dans les organizations
+ //parentes de celle-ci.
+ try {
+ final UserGroup gr = UserGroupLocalServiceUtil.getUserGroup(
+ ((Long)arg0).longValue());
+ final User u = UserLocalServiceUtil.getUser(
+ ((Long) arg2).longValue());
+
+ if (gr.getName().toLowerCase().contains("groupAccessReport".toLowerCase())) {
+ manageManager(u);
+ }
+
+ if (isEntLdapObject(gr)) {
+ long currOrgId = OrganizationLocalServiceUtil.getOrganization(
+ gr.getCompanyId(), getOrgName(gr)).getOrganizationId();
+
+ while (currOrgId !=
+ OrganizationConstants.DEFAULT_PARENT_ORGANIZATION_ID) {
+ final Organization currOrg = OrganizationLocalServiceUtil.
+ getOrganization(currOrgId);
+
+ //add the user into all the orgs and parent orgs
+ if (!OrganizationLocalServiceUtil.hasUserOrganization(
+ u.getUserId(), currOrgId, false, true)) {
+ if (_log.isDebugEnabled()) {
+ _log.debug("Adding user "+u.getScreenName()+" to organization "+currOrg.getName());
+ }
+ long[] users = new long[1]; users[0] = u.getUserId();
+ UserLocalServiceUtil.addOrganizationUsers(currOrgId,
+ users);
+
+ }
+
+ currOrgId = currOrg.getParentOrganizationId();
+ }
+ }
+ } catch (Exception e) {
+ if (_log.isDebugEnabled()) {
+ _log.debug(e);
+ }
+ }
+ }
+
+ public void onAfterCreate(UserGroup gr) throws ModelListenerException {
+ try {
+ //A la création d'un UserGroup, on crée si necessaire une Organization
+ //correspondante.
+
+ if (isEntLdapObject(gr)) {
+ //recupere le groupe de l'etab parent (et le cree s'il n'exite
+ //pas
+
+ Organization college = ENTOrganizationsUtil.getOrCreateSchool(gr.getCompanyId(), getEtabName(gr));
+
+ //cree l'org correspondant au userGroup ainsi qu'aux parents
+ ENTOrganizationsUtil.getOrCreateOrganization(gr.getCompanyId(), getOrgName(gr), college.getOrganizationId());
+ if (ENTMainUtilsLocalServiceUtil.getEntSchoolImportType(gr.getCompanyId())) {
+ ENTOrganizationsUtil.getOrCreateOrganization(gr.getCompanyId(), getOrgName(gr)+" - Parents", college.getOrganizationId());
+ }
+ }
+ } catch (Exception e) {
+ if (_log.isErrorEnabled()) {
+ _log.error(e);
+ }
+ }
+ }
+
+ public void onAfterRemove(UserGroup arg0) throws ModelListenerException {}
+
+ public void onAfterRemoveAssociation(Object arg0, String arg1, Object arg2)
+ throws ModelListenerException {}
+
+ public void onAfterUpdate(UserGroup arg0) throws ModelListenerException {}
+
+ public void onBeforeAddAssociation(Object arg0, String arg1, Object arg2)
+ throws ModelListenerException {}
+
+ public void onBeforeCreate(UserGroup gr) throws ModelListenerException {}
+
+ public void onBeforeRemove(UserGroup arg0) throws ModelListenerException {}
+
+
+ /* (non-Javadoc)
+ * @see com.liferay.portal.model.ModelListener#onBeforeRemoveAssociation(java.lang.Object, java.lang.String, java.lang.Object)
+ *
+ * Vas retirer l'utilisateur de l'organization associ�e.
+ *
+ */
+ public void onBeforeRemoveAssociation(Object arg0, String arg1, Object arg2)
+ throws ModelListenerException {
+ try {
+ // Retire egalement l'user de l'organization correspondante.
+ final UserGroup gr = UserGroupLocalServiceUtil.getUserGroup(
+ ((Long)arg0).longValue());
+ final User u = UserLocalServiceUtil.getUser(
+ ((Long) arg2).longValue());
+ //verifie que l'user n'est plus dans le group
+ if (isEntLdapObject(gr)) {
+ long currOrgId = OrganizationLocalServiceUtil.getOrganization(
+ gr.getCompanyId(), getOrgName(gr)).getOrganizationId();
+
+ //Retire l'user quoi qu'il arrive du groupe correspondant au usergroupe d'appel
+ removeUserFromOrganization(currOrgId, u);
+
+ //Retire l'user de toutes les organisations suivantes:
+ // - celles dont l'utilisateur n'est plus dans les sous-organisations si et ssi
+ // - l'org n'est pas cartable de savoie
+ // - l'org n'est pas celle de ratachement
+ final long cartSavoieId = ENTOrganizationsUtil.getOrCreateRootOrg(u.getCompanyId()).getOrganizationId();
+ final long etabRatachementId = OrganizationFinderServiceUtil.getEtabRatachement(u).getOrganizationId();
+
+ while (currOrgId != cartSavoieId && currOrgId != etabRatachementId &&
+ currOrgId != OrganizationConstants.DEFAULT_PARENT_ORGANIZATION_ID) {
+ final Organization currOrg = OrganizationLocalServiceUtil.getOrganization(currOrgId);
+
+ //Retire l'user s'il ne fait plus parti
+ if (!OrganizationLocalServiceUtil.hasUserOrganization(
+ u.getUserId(), currOrgId, true, true)) {
+ removeUserFromOrganization(currOrgId, u);
+ }
+
+ currOrgId = currOrg.getParentOrganizationId();
+ }
+ }
+ } catch (Exception e) {
+ if (_log.isDebugEnabled()) {
+ _log.debug(e);
+ }
+ }
+ }
+
+ public void onBeforeUpdate(UserGroup arg0) throws ModelListenerException {}
+
+
+ private boolean isEntLdapObject(UserGroup gr) throws Exception {
+ // Clé du cache
+ String cacheKey="UserGroupCache_"+gr.getUserGroupId();
+
+ // Get value from cache instance
+ Boolean cacheBool= (Boolean) ENTCacheUtils.getObjectFromCache(cacheKey);
+
+ // On regarde si le cache est null ou non
+ if(cacheBool==null){
+ //if misscache, set new value to variable
+ try {
+ cacheBool= isEntClass(gr) || isEntGroupe(gr);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ ENTCacheUtils.storeObjectIntoCache(cacheKey,cacheBool,-1);
+ }
+ else{
+ //could find and get value from cache instance
+ }
+ return cacheBool;
+ }
+
+
+ private boolean isEntClass(UserGroup gr) throws Exception {
+ LdapContext ct = getLdapContext(gr);
+
+ try {
+ Attributes attrs = ct.getAttributes("cn="+gr.getName()+
+ ",ou=groups,"+PrefsPropsUtil.getString(gr.getCompanyId(),
+ "ldap.base.dn"));
+ Attribute cl = attrs.get("objectClass");
+ for (int i=0; i<cl.size(); i++) {
+ if (cl.get(i).equals("ENTClasse"))
+ return true;
+ }
+ } catch (NamingException e) {
+ //en cas d'erreur, considere que ce n'est pas une classe.
+ return false;
+ }
+
+ return false;
+ }
+
+ private boolean isEntGroupe(UserGroup gr) throws Exception {
+ LdapContext ct = getLdapContext(gr);
+
+ try {
+ Attributes attrs = ct.getAttributes("cn="+gr.getName()+
+ ",ou=groups,"+PrefsPropsUtil.getString(gr.getCompanyId(),
+ "ldap.base.dn"));
+ Attribute cl = attrs.get("objectClass");
+ for (int i=0; i<cl.size(); i++) {
+ if (cl.get(i).equals("ENTGroupe"))
+ return true;
+ }
+ } catch (NamingException e) {
+ //en cas d'erreur, considere que ce n'est pas une classe.
+ return false;
+ }
+
+ return false;
+ }
+
+ private String getOrgName(UserGroup gr) {
+ String initName = gr.getName();
+ String retName = initName;
+ Pattern classPattern = Pattern.compile("^[0-9]+\\$");
+ Matcher classMatcher = classPattern.matcher(initName);
+ if (classMatcher.find()) {
+ //Le nom correspond au nom d'une classe ou d'un gr d'user dans le
+ //ldap
+ retName = getEtabName(gr)+" - "+initName.substring(classMatcher.end());
+ }
+ return retName;
+ }
+
+ private String getEtabName(UserGroup gr) {
+ String initName = gr.getName();
+ String cacheName = null;
+
+ try {
+ Pattern classPattern = Pattern.compile("^[0-9]+\\$");
+ Matcher classMatcher = classPattern.matcher(initName);
+ if (classMatcher.find()) {
+ //Le nom correspond au nom d'une classe ou d'un gr d'user dans le
+ //ldap
+ String retName = initName.substring(classMatcher.start(),
+ classMatcher.end()-1);
+
+ // Clé du cache
+ //key for user group etab name
+ String cacheKey="UG_ENCache_"+gr.getUserGroupId();
+
+ // Get value from cache instance
+ cacheName = (String) ENTCacheUtils.getObjectFromCache(cacheKey);
+ // On regarde si le cache est null ou non
+ if(cacheName==null){
+ //if misscache, set new value to variable
+ try {
+ LdapContext ct = getLdapContext(gr);
+ Attributes attrs = ct.getAttributes("ou="+retName+
+ ",ou=etablissements,"+
+ PrefsPropsUtil.getString(gr.getCompanyId(),
+ "ldap.base.dn"));
+ cacheName = attrs.get("ENTStructureNomCourant").get(0).toString();
+
+ // si classic --> ENTStructureNomCourant
+ // si full --> ENTStructureNomCourant + l + RNE
+ String etabNameType = ENTMainUtilsLocalServiceUtil.getENTSynchroEtabName(gr.getCompanyId());
+ if (etabNameType.equals("full")) {
+ if (attrs.get("l")!=null) {
+ cacheName += " - " + attrs.get(
+ "l").get().toString();
+ }
+ if (attrs.get("ENTStructureUAI")!=null) {
+ cacheName += " - " + attrs.get(
+ "ENTStructureUAI").get().toString();
+ }
+
+ }
+
+ } catch (Exception e) {
+ //e.printStackTrace();
+ }
+ ENTCacheUtils.storeObjectIntoCache(cacheKey,cacheName,-1);
+ }
+ else{
+ //could find and get value from cache instance
+ }
+ }
+ } catch (Exception e) {
+ //if (_log.isErrorEnabled()) {
+ // _log.error(e);
+ //}
+ }
+ return cacheName;
+ }
+
+ private LdapContext getLdapContext(UserGroup gr) throws Exception {
+ if (ctx == null) {
+ ctx = PortalLDAPUtil.getContext(gr.getCompanyId());
+ }
+ return ctx;
+ }
+
+ private void manageManager(User user) {
+ try {
+ if (RoleLocalServiceUtil.hasUserRole(user.getUserId(), user.getCompanyId(), ENTRolesConstants.NATIONAL_4, true)) {
+ Organization coll = OrganizationFinderServiceUtil.getEtabRatachement(user);
+
+ //met l'user dans l'organization
+ UserLocalServiceUtil.addOrganizationUsers(coll.getOrganizationId(), new long[]{user.getUserId()});
+
+ Role adminRole = RoleLocalServiceUtil.getRole(user.getCompanyId(), RoleConstants.ORGANIZATION_ADMINISTRATOR);
+ UserGroupRoleLocalServiceUtil.addUserGroupRoles(user.getUserId(), coll.getGroup().getGroupId(), new long[]{adminRole.getRoleId()});
+
+ if (_log.isDebugEnabled()) {
+ _log.debug("The user "+user.getScreenName()+" is now admin of "+coll.getName());
+ }
+ }
+
+ } catch (Exception e) {
+ if (_log.isErrorEnabled()) {
+ _log.error(e);
+ }
+ }
+ }
+
+ private void removeUserFromOrganization(final long organizationId, final User user) throws PortalException, SystemException {
+ UserLocalServiceUtil.unsetOrganizationUsers(organizationId, new long[]{user.getUserId()});
+ if (_log.isDebugEnabled()) {
+ final String userName = user.getScreenName();
+ _log.debug("Removed user " + userName + " from an organization");
+ }
+ }
+
+ private LdapContext ctx = null;
+ private Log _log = LogFactoryUtil.getLog(this.getClass());
+
+}