ServiceContact.java
/*
* Copyright (C) 2000 - 2025 Silverpeas
*
* This program is free software: you can redistribute it and/or modify
* it 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.
*
* As a special exception to the terms and conditions of version 3.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* Open Source Software ("FLOSS") applications as described in Silverpeas's
* FLOSS exception. You should have received a copy of the text describing
* the FLOSS exception, and it is also available here:
* "https://www.silverpeas.org/legal/floss_exception.html"
*
* This program 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
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.silverpeas.mobile.server.services;
import jakarta.inject.Inject;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
import org.apache.commons.lang3.ArrayUtils;
import org.silverpeas.components.yellowpages.service.YellowpagesService;
import org.silverpeas.core.admin.service.AdminException;
import org.silverpeas.core.admin.service.Administration;
import org.silverpeas.core.admin.service.OrganizationController;
import org.silverpeas.core.admin.user.model.GroupDetail;
import org.silverpeas.core.admin.user.model.User;
import org.silverpeas.core.admin.user.model.UserDetail;
import org.silverpeas.core.admin.user.model.UserFull;
import org.silverpeas.core.annotation.WebService;
import org.silverpeas.core.contact.model.CompleteContact;
import org.silverpeas.core.contact.model.ContactDetail;
import org.silverpeas.core.contact.model.ContactPK;
import org.silverpeas.core.contribution.template.publication.PublicationTemplateManager;
import org.silverpeas.core.index.search.SearchEngineProvider;
import org.silverpeas.core.index.search.model.MatchingIndexEntry;
import org.silverpeas.core.index.search.model.ParseException;
import org.silverpeas.core.index.search.model.QueryDescription;
import org.silverpeas.core.socialnetwork.relationship.RelationShipService;
import org.silverpeas.core.web.rs.UserPrivilegeValidation;
import org.silverpeas.core.web.rs.annotation.Authorized;
import org.silverpeas.kernel.bundle.LocalizationBundle;
import org.silverpeas.kernel.bundle.ResourceLocator;
import org.silverpeas.kernel.logging.SilverLogger;
import org.silverpeas.kernel.util.StringUtil;
import org.silverpeas.mobile.server.common.SpMobileLogModule;
import org.silverpeas.mobile.server.helpers.DataURLHelper;
import org.silverpeas.mobile.server.services.helpers.UserHelper;
import org.silverpeas.mobile.shared.dto.DetailUserDTO;
import org.silverpeas.mobile.shared.dto.contact.ContactFilters;
import org.silverpeas.mobile.shared.dto.contact.ContactScope;
import java.util.*;
@WebService
@Authorized
@Path(ServiceContact.PATH)
public class ServiceContact extends AbstractRestWebService {
@Context
HttpServletRequest request;
static final String PATH = "mobile/contact";
@Inject
private OrganizationController organizationController;
@Inject
private RelationShipService relationShipService;
private List<String> getUserProperties() {
List<String> userProperties = new ArrayList<>();
String properties = getSettings().getString("directory.user.properties", "");
StringTokenizer stkU = new StringTokenizer(properties, ",");
while (stkU.hasMoreTokens()) {
userProperties.add(stkU.nextToken());
}
return userProperties;
}
private List<String> getContactProperties() {
List<String> contactProperties = new ArrayList<>();
String formProperties = getSettings().getString("directory.contact.properties", "");
StringTokenizer stkC = new StringTokenizer(formProperties, ",");
while (stkC.hasMoreTokens()) {
contactProperties.add(stkC.nextToken());
}
return contactProperties;
}
private List<String> getdomainsIds() {
List<String> domainsIds = new ArrayList<>();
String domains = getSettings().getString("directory.domains", "");
StringTokenizer stk = new StringTokenizer(domains, ",");
while (stk.hasMoreTokens()) {
domainsIds.add(stk.nextToken());
}
return domainsIds;
}
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/contact/{userId}/")
public DetailUserDTO getContact(@PathParam("userId") String userId) throws AdminException {
UserDetail u = Administration.get().getUserDetail(userId);
return populate(u, false);
}
/**
* Return list of DetailUserDTO of my contacts
*
* @return list of UserDetailDTO
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("paging/{type}/")
public List<DetailUserDTO> getContacts(@PathParam("type") String type,
@QueryParam("filter") String filter, @QueryParam("pageSize") int pageSize,
@QueryParam("startIndex") int startIndex) {
ArrayList<DetailUserDTO> listUsers = new ArrayList<>();
try {
switch (type) {
case ContactFilters.ALL: {
List tabUserDetail = null;
if (filter.isEmpty()) {
tabUserDetail = Administration.get().getUsersOfDomains(getdomainsIds());
} else {
tabUserDetail = getUsersByQuery(filter, "UserFull");
}
for (int i = 0; i < tabUserDetail.size(); i++) {
if (i >= startIndex && i < startIndex + pageSize) {
DetailUserDTO dto = populate(tabUserDetail.get(i), true);
if (dto != null) listUsers.add(dto);
}
}
break;
}
case ContactFilters.ALL_EXT: {
List tabUserDetail = getUsersByQuery(filter, "Contact");
for (int i = 0; i < tabUserDetail.size(); i++) {
if (i >= startIndex && i < startIndex + pageSize) {
listUsers.add(populate(tabUserDetail.get(i), true));
}
}
break;
}
case ContactFilters.MY:
List<String> contactsIds =
relationShipService.getMyContactsIds(Integer.parseInt(getUser().getId()));
for (int j = 0; j < contactsIds.size(); j++) {
if (j >= startIndex && j < startIndex + pageSize) {
String id = contactsIds.get(j);
UserDetail userDetail = organizationController.getUserDetail(id);
DetailUserDTO userDTO = populate(userDetail, true);
listUsers.add(userDTO);
}
}
break;
default:
break;
}
defaultSortContacts(listUsers);
} catch (AdminException ade) {
SilverLogger.getLogger(this).error("ServiceContact.getContacts", "root.EX_NO_MESSAGE", ade);
} catch (Exception e) {
SilverLogger.getLogger(this).error("ServiceContact.getContacts", "root.EX_NO_MESSAGE", e);
throw e;
}
return listUsers;
}
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("{type}/")
public List<DetailUserDTO> getContactsFiltered(@PathParam("type") String type, @QueryParam("filter") String filter)
throws AdminException {
ArrayList<DetailUserDTO> listUsers = new ArrayList<>();
try {
if (type.equals(ContactScope.group.name())) {
String[] groupsIds = filter.split(",");
GroupDetail[] groups = Administration.get().getGroups(groupsIds);
List<User> users = new ArrayList<>();
for (GroupDetail group : groups) {
users.addAll(group.getAllUsers());
}
users = new ArrayList<>(new HashSet<>(users));
for (User user : users) {
DetailUserDTO userDTO = populate(user, true);
listUsers.add(userDTO);
}
} else if (type.equals(ContactScope.domain.name())) {
String[] domainsIds = filter.split(",");
UserDetail[] users = null;
for (String domainId : domainsIds) {
if (users == null) {
users = Administration.get().getUsersOfDomain(domainId);
} else {
users = ArrayUtils.addAll(users, Administration.get().getUsersOfDomain(domainId));
}
}
Objects.requireNonNull(users);
for (User user : users) {
DetailUserDTO userDTO = populate(user, true);
listUsers.add(userDTO);
}
} else if (type.isEmpty()) {
List<UserDetail> users = Administration.get().getAllUsers();
for (User user : users) {
DetailUserDTO userDTO = populate(user, true);
listUsers.add(userDTO);
}
}
} catch (Exception e) {
SilverLogger.getLogger(this)
.error("ServiceContact.getContactsFiltered", "root.EX_NO_MESSAGE", e);
throw e;
}
return listUsers;
}
private void defaultSortContacts(final List<DetailUserDTO> listUsers) {
listUsers.sort(Comparator.comparing(DetailUserDTO::getLastName));
}
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("hasContacts/")
public ContactFilters hasContacts() {
ContactFilters result = new ContactFilters();
List tabUserDetail = getUsersByQuery("", "Contact");
result.setHasContacts(!tabUserDetail.isEmpty());
List<String> contactsIds = new ArrayList<>();
try {
contactsIds = relationShipService.getMyContactsIds(Integer.parseInt(getUser().getId()));
} catch (Exception e) {
// don't treat this case
}
result.setHasPersonnalContacts(!contactsIds.isEmpty());
return result;
}
private List getUsersByQuery(String query, String type) {
if (!query.isEmpty()) {
query += '*';
}
List results = new ArrayList<>();
try {
QueryDescription queryDescription = new QueryDescription(query);
queryDescription.addComponent("users");
for (String appId : getContactComponentIds()) {
queryDescription.addComponent(appId);
}
List<MatchingIndexEntry> plainSearchResults =
SearchEngineProvider.getSearchEngine().search(queryDescription).getEntries();
if (plainSearchResults != null && !plainSearchResults.isEmpty()) {
for (MatchingIndexEntry result : plainSearchResults) {
String objectId = result.getObjectId();
if (type.equals(result.getObjectType())) {
if (result.getObjectType().equals("Contact")) {
ContactDetail contact = YellowpagesService.get()
.getContactDetail(new ContactPK(objectId, result.getComponent()));
results.add(contact);
} else if (result.getObjectType().equals("UserFull")) {
UserDetail userDetail = organizationController.getUserDetail(objectId);
// if userDetail is null than mean user was deleted but is still in index
List<String> domainsIds = getdomainsIds();
if (userDetail != null &&
(domainsIds.isEmpty() || domainsIds.contains(userDetail.getDomainId())) &&
userDetail.isActivatedState()) {
results.add(userDetail);
}
}
}
}
}
} catch (ParseException e) {
SilverLogger.getLogger(this).error(e);
}
return results;
}
private List<String> getContactComponentIds() {
String[] appIds =
organizationController.getComponentIdsForUser(getUser().getId(), "yellowpages");
List<String> result = new ArrayList<>();
for (String appId : appIds) {
String param =
organizationController.getComponentParameterValue(appId, "displayedInDirectory");
if (StringUtil.getBooleanValue(param)) {
result.add(appId);
}
}
return result;
}
private DetailUserDTO populate(Object user, boolean filtered) {
if (user instanceof UserDetail) {
UserDetail userDetail = (UserDetail) user;
SilverLogger.getLogger(this).debug(SpMobileLogModule.getName(), "ServiceContact.populate",
"User id=" + userDetail.getId());
UserFull userFull = UserFull.getById(userDetail.getId());
DetailUserDTO dto = null;
if (userFull != null) {
dto = new DetailUserDTO();
UserHelper.initUserDTO(userFull, dto);
dto.setConnected(userFull.isConnected());
String avatar;
String path = userDetail.getDomain().getSettings().getString("property.ResourceFile");
if (!dto.getLanguage().trim().isEmpty()) path += "_" + dto.getLanguage();
SilverLogger.getLogger(this).info("Loading domain ressource file " + path);
LocalizationBundle domainMultiLang = ResourceLocator.getLocalizationBundle(path);
for (String prop : domainMultiLang.keySet()) {
String label = domainMultiLang.getString(prop);
dto.addPropertyLabel(prop, label);
}
Map<String, String> labels = PublicationTemplateManager.getInstance().getDirectoryFormLabels(userFull.getId(), userFull.getDomainId(), dto.getLanguage());
for (Map.Entry<String, String> prop : labels.entrySet()) {
dto.addPropertyLabel(prop.getKey(), prop.getValue());
}
if (filtered) {
avatar = getAvatar(userDetail, getSettings().getString("avatar.size", "24x"));
for (String prop : getUserProperties()) {
dto.addProperty(prop, userFull.getValue(prop));
dto.addProperty(prop, userFull.getDefinedExtraFormValues(((UserDetail) user).getUserPreferences().getLanguage()).get(prop));
}
} else {
avatar = getAvatar(userDetail, getSettings().getString("profil.avatar.size", "96x"));
Map<String, String> fields = userFull.getAllDefinedValues(userFull.getUserPreferences().getLanguage());
for (Map.Entry<String, String> prop : fields.entrySet()) {
dto.addProperty(prop.getKey(), prop.getValue());
}
}
dto.setAvatar(avatar);
}
return dto;
} else if (user instanceof ContactDetail) {
ContactDetail contactDetail = (ContactDetail) user;
SilverLogger.getLogger(this).debug(SpMobileLogModule.getName(), "ServiceContact.populate",
"Contact id=" + contactDetail.getPK().getId() + "app id=" +
contactDetail.getPK().getInstanceId());
DetailUserDTO dto = new DetailUserDTO();
dto.setId(contactDetail.getPK().getId());
dto.setFirstName(contactDetail.getFirstName());
dto.setLastName(contactDetail.getLastName());
dto.seteMail(contactDetail.getEmail());
dto.setPhoneNumber(contactDetail.getPhone());
dto.setFaxPhoneNumber(contactDetail.getFax());
dto.setAvatar("");
dto.setStatus("");
dto.setCellularPhoneNumber("");
dto.setLanguage("");
CompleteContact completeContact =
YellowpagesService.get().getCompleteContact(((ContactDetail) user).getPK());
Map<String, String> fields =
completeContact.getFormValues(getUser().getUserPreferences().getLanguage(), true);
if (fields != null) {
if (filtered) {
for (String prop : getContactProperties()) {
dto.addProperty(prop, fields.get(prop));
}
} else {
for (Map.Entry<String, String> prop : fields.entrySet()) {
dto.addProperty(prop.getKey(), prop.getValue());
}
}
}
return dto;
}
return null;
}
private static String getAvatar(UserDetail userDetail, String size) {
String avatar;
if (DataURLHelper.hasPersonnalizedAvatar(userDetail.getAvatarFileName())) {
avatar = "/silverpeas/display/avatar/" + size + "/" + userDetail.getLogin() + ".jpg";
} else {
avatar = "/silverpeas/directory/jsp/icons/avatar.png";
}
return avatar;
}
@Override
protected String getResourceBasePath() {
return PATH;
}
@Override
public String getComponentId() {
return null;
}
@Override
public void validateUserAuthorization(final UserPrivilegeValidation validation) {
}
}