CommunityWebManager.java
/*
* Copyright (C) 2000 - 2024 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:
* "http://www.silverpeas.org/docs/core/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.components.community;
import org.silverpeas.components.community.model.CommunityMembership;
import org.silverpeas.components.community.model.CommunityOfUsers;
import org.silverpeas.components.community.model.MembershipStatus;
import org.silverpeas.components.community.notification.user.MembershipLeaveUserNotificationBuilder;
import org.silverpeas.components.community.notification.user.MembershipRequestUserNotificationBuilder;
import org.silverpeas.components.community.notification.user.MembershipRequestValidationUserNotificationBuilder;
import org.silverpeas.core.admin.PaginationPage;
import org.silverpeas.core.admin.component.model.ComponentInst;
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.SilverpeasRole;
import org.silverpeas.core.admin.user.model.User;
import org.silverpeas.core.annotation.Service;
import org.silverpeas.core.cache.service.CacheAccessorProvider;
import org.silverpeas.core.util.ServiceProvider;
import org.silverpeas.core.util.SilverpeasList;
import org.silverpeas.core.web.mvc.webcomponent.WebMessager;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.ws.rs.WebApplicationException;
import java.util.Objects;
import java.util.Set;
import java.util.function.Supplier;
import static org.silverpeas.components.community.CommunityComponentSettings.getMessagesIn;
import static org.silverpeas.core.admin.user.model.SilverpeasRole.fromString;
import static org.silverpeas.kernel.util.StringUtil.getBooleanValue;
/**
* WEB manager which allows to centralize code to be used by REST Web Services and Web Component
* Controller.
*
* @author silveryocha
*/
@Service
public class CommunityWebManager {
private static final String CACHE_KEY_PREFIX = CommunityWebManager.class.getSimpleName() + ":";
public static final PaginationPage NO_PAGINATION = new PaginationPage(1, Integer.MAX_VALUE);
protected CommunityWebManager() {
}
/**
* Gets the singleton instance of the provider.
*/
public static CommunityWebManager get() {
return ServiceProvider.getService(CommunityWebManager.class);
}
/**
* Makes the current user joining the given community.
*
* @param community {@link CommunityOfUsers} instance representing the community.
*/
public void join(final CommunityOfUsers community) {
final SilverpeasRole defaultRole = getDefaultMemberRoleOf(community);
final String spaceName = getSpaceName(community);
final User currentRequester = User.getCurrentRequester();
if (adminMustValidateNewMemberOf(community)) {
community.addAsAPendingMember(currentRequester);
MembershipRequestUserNotificationBuilder
.about(community)
.newRequestFrom(currentRequester)
.build()
.send();
successMessage("community.join.pendingValidation.success", spaceName);
} else {
community.addAsMember(currentRequester, defaultRole);
successMessage("community.join.success", spaceName);
}
}
/**
* Validates the membership request of user given in parameters on specified community.
*
* @param requester the user behind the request to join the community.
* @param community the community the user accesses.
* @param accept true to accept the request, false to refuse.
* @param message message linked to the acceptation or refuse.
*/
public void validateRequestOf(final User requester, final CommunityOfUsers community,
final boolean accept, final String message) {
if (accept) {
final SilverpeasRole defaultRole = getDefaultMemberRoleOf(community);
community.addAsMember(requester, defaultRole);
} else {
community.refuseMembership(requester);
}
MembershipRequestValidationUserNotificationBuilder
.about(community)
.validating(requester, accept)
.withMessage(message)
.build()
.send();
}
/**
* Makes the given user leaving the given community.
*
* @param community {@link CommunityOfUsers} instance representing the community.
* @param member the member to manage.
*/
public void endMembershipOf(final CommunityOfUsers community, final User member) {
community.removeMembership(member);
successMessage("community.endMembership.success", member.getDisplayedName(),
getSpaceName(community));
}
/**
* Makes the current user leaving the given community.
*
* @param community {@link CommunityOfUsers} instance representing the community.
* @param reason the index of the reason of the leaving.
* @param message a message to explain more precisely the member leaving.
* @param contactInFuture boolean, true to indicate that the member accepts to be contacted in the
* future about its leaving.
*/
public void leave(final CommunityOfUsers community, final int reason, final String message,
final boolean contactInFuture) {
final User leavingMember = User.getCurrentRequester();
community.removeMembership(leavingMember);
MembershipLeaveUserNotificationBuilder
.about(community)
.memberLeavingIs(leavingMember)
.withReason(reason)
.andMessage(message)
.andContactInFuture(contactInFuture)
.build()
.send();
successMessage("community.leave.success", getSpaceName(community));
}
/**
* Saves into instance parameter of the given community the value of parameter
* 'displayCharterOnSpaceHomepage'.
*
* @param community {@link CommunityOfUsers} instance representing the community.
* @param value true to display the charter, false otherwise.
*/
public void setDisplayCharterOnSpaceHomepage(final CommunityOfUsers community,
final boolean value) {
final ComponentInst componentInst = OrganizationController.get()
.getComponentInst(community.getComponentInstanceId());
componentInst.getParameter("displayCharterOnSpaceHomepage").setValue(value ? "yes" : "no");
try {
Administration.get().updateComponentInst(componentInst);
} catch (AdminException e) {
throw new WebApplicationException(e);
}
}
/**
* Gets members pending validation of the given community.
*
* @param community {@link CommunityOfUsers} instance representing the community.
* @param page the pending members to get are paginated. Indicates the page to return. If null,
* all the pending members are got.
* @return list of {@link CommunityMembership} instance, representing each one a pending member.
*/
@SuppressWarnings("unchecked")
public SilverpeasList<CommunityMembership> getMembersToValidate(
@Nonnull final CommunityOfUsers community, @Nullable final PaginationPage page) {
PaginationPage paginationPage = page == null ? NO_PAGINATION : page;
return requestCache("membersToValidate", community.getId(), SilverpeasList.class,
() -> community.getMembershipsProvider().getPending(paginationPage));
}
/**
* Gets members of the given community.
*
* @param community {@link CommunityOfUsers} instance representing the community.
* @param page the members to get are paginated. Indicates the page to return. If null, all the
* members are got.
* @return list of {@link CommunityMembership} instance, representing each one a committed member.
*/
@SuppressWarnings("unchecked")
public SilverpeasList<CommunityMembership> getMembers(@Nonnull final CommunityOfUsers community,
@Nullable final PaginationPage page) {
PaginationPage paginationPage = page == null ? NO_PAGINATION : page;
return requestCache("members", community.getId(), SilverpeasList.class,
() -> community.getMembershipsProvider().getInRange(paginationPage));
}
/**
* Gets history of the given community.
*
* @param community {@link CommunityOfUsers} instance representing the community.
* @param page the members to get are paginated. Indicates the page to return. If null, all the
* members are got.
* @return list of {@link CommunityMembership} instance, representing each one a membership
* whatever its status.
*/
@SuppressWarnings("unchecked")
public SilverpeasList<CommunityMembership> getHistory(@Nonnull final CommunityOfUsers community,
@Nullable final PaginationPage page) {
PaginationPage paginationPage = page == null ? NO_PAGINATION : page;
return requestCache("history", community.getId(), SilverpeasList.class,
() -> community.getMembershipsProvider().getHistory(paginationPage));
}
/**
* Indicates if the current requester is a member.
* <p>
* A member MUST be directly specified into ADMIN, PUBLISHER, WRITER or READER role of direct
* parent space.
* </p>
*
* @param community {@link CommunityOfUsers} instance.
* @return true if member, false otherwise.
*/
public boolean isMemberOf(final CommunityOfUsers community) {
return Objects.requireNonNull(requestCache("isMemberOf", community.getId(), Boolean.class,
() -> community.isMember(User.getCurrentRequester())));
}
/**
* Indicates if the current requester has membership pending validation.
* <p>
* A member MUST be directly specified into ADMIN, PUBLISHER, WRITER or READER role of direct
* parent space.
* </p>
*
* @param community {@link CommunityOfUsers} instance.
* @return true if member, false otherwise.
*/
public boolean isMembershipPendingFor(final CommunityOfUsers community) {
return Objects.requireNonNull(requestCache("isMembershipPending",
community.getId(),
Boolean.class,
() -> community.getMembershipsProvider()
.get(User.getCurrentRequester())
.map(CommunityMembership::getStatus)
.map(MembershipStatus::isPending)
.orElse(false)));
}
/**
* Gets the roles the current requester has on the given community.
*
* @param community {@link CommunityOfUsers} instance.
* @return a set of {@link SilverpeasRole}.
*/
@SuppressWarnings("unchecked")
public Set<SilverpeasRole> getUserRoleOn(final CommunityOfUsers community) {
return requestCache("userRoleOf", community.getId(), Set.class,
() -> community.getUserRoles(User.getCurrentRequester()));
}
private boolean adminMustValidateNewMemberOf(final CommunityOfUsers community) {
return getBooleanValue(getCommunityInstanceParameter(community, "validateNewMember"));
}
private SilverpeasRole getDefaultMemberRoleOf(final CommunityOfUsers community) {
return fromString(getCommunityInstanceParameter(community, "defaultMemberRole"));
}
private <T> T requestCache(final String type, final String id, Class<T> classType,
Supplier<T> supplier) {
return CacheAccessorProvider.getThreadCacheAccessor()
.getCache()
.computeIfAbsent(CACHE_KEY_PREFIX + type + ":" + id, classType, supplier);
}
private String getCommunityInstanceParameter(final CommunityOfUsers community,
final String parameterName) {
return OrganizationController.get()
.getComponentParameterValue(community.getComponentInstanceId(), parameterName);
}
private String getSpaceName(final CommunityOfUsers community) {
final String userLanguage = getUserLanguage();
return OrganizationController.get()
.getSpaceInstById(community.getSpaceId())
.getName(userLanguage);
}
/**
* Push a success message to the current user.
*
* @param messageKey the key of the message.
* @param params the message parameters.
*/
private void successMessage(String messageKey, Object... params) {
final String userLanguage = getUserLanguage();
getMessager().addSuccess(getMessagesIn(userLanguage).getString(messageKey), params);
}
private String getUserLanguage() {
return requestCache("language", "user", String.class,
() -> User.getCurrentRequester().getUserPreferences().getLanguage());
}
private WebMessager getMessager() {
return WebMessager.getInstance();
}
}