diff --git a/portlets/src/main/webapp/WEB-INF/conf/gamification/upgrade-configuration.xml b/portlets/src/main/webapp/WEB-INF/conf/gamification/upgrade-configuration.xml index dbfddc8dfb..e4ac3e1995 100644 --- a/portlets/src/main/webapp/WEB-INF/conf/gamification/upgrade-configuration.xml +++ b/portlets/src/main/webapp/WEB-INF/conf/gamification/upgrade-configuration.xml @@ -76,6 +76,29 @@ + + ProgramVisibilityUpgradePlugin + addUpgradePlugin + io.meeds.gamification.upgrade.ProgramVisibilityUpgradePlugin + An upgrade plugin to set a program visibility switch audience registration type + + + product.group.id + The groupId of the product + org.exoplatform.social + + + plugin.execution.order + The plugin execution order + 5 + + + plugin.upgrade.execute.once + Execute only once, not each version change + true + + + diff --git a/portlets/src/main/webapp/WEB-INF/jsp/engagementCenterActions.jsp b/portlets/src/main/webapp/WEB-INF/jsp/engagementCenterActions.jsp index bcea5e9735..30200b4815 100644 --- a/portlets/src/main/webapp/WEB-INF/jsp/engagementCenterActions.jsp +++ b/portlets/src/main/webapp/WEB-INF/jsp/engagementCenterActions.jsp @@ -21,13 +21,12 @@ <%@ page import="io.meeds.gamification.service.ProgramService"%> <%@ page import="org.exoplatform.container.ExoContainerContext"%> <%@ page import="io.meeds.gamification.utils.Utils" %> -<%@ page import="org.exoplatform.services.security.ConversationState" %> <% -boolean isAdministrator = Utils.isRewardingManager(ConversationState.getCurrent().getIdentity().getUserId()); -boolean isProgramManager = isAdministrator || ExoContainerContext.getService(ProgramService.class).countOwnedPrograms(ConversationState.getCurrent().getIdentity().getUserId()) > 0; + if (Utils.canAccessAnonymousResources()) { + boolean isAdministrator = request.getRemoteUser() != null && Utils.isRewardingManager(request.getRemoteUser()); + boolean isProgramManager = request.getRemoteUser() != null && (isAdministrator || ExoContainerContext.getService(ProgramService.class).countOwnedPrograms(request.getRemoteUser()) > 0); %> -
+<% } %> + diff --git a/portlets/src/main/webapp/WEB-INF/jsp/programsOverview.jsp b/portlets/src/main/webapp/WEB-INF/jsp/programsOverview.jsp new file mode 100644 index 0000000000..d883daffda --- /dev/null +++ b/portlets/src/main/webapp/WEB-INF/jsp/programsOverview.jsp @@ -0,0 +1,11 @@ +<%@page import="io.meeds.gamification.utils.Utils"%> +<% if (Utils.canAccessAnonymousResources()) { %> +
+
+ +
+
+<% } %> + \ No newline at end of file diff --git a/portlets/src/main/webapp/WEB-INF/jsp/rulesOverview/index.jsp b/portlets/src/main/webapp/WEB-INF/jsp/rulesOverview.jsp similarity index 92% rename from portlets/src/main/webapp/WEB-INF/jsp/rulesOverview/index.jsp rename to portlets/src/main/webapp/WEB-INF/jsp/rulesOverview.jsp index e2fc402200..ae70443ac2 100644 --- a/portlets/src/main/webapp/WEB-INF/jsp/rulesOverview/index.jsp +++ b/portlets/src/main/webapp/WEB-INF/jsp/rulesOverview.jsp @@ -18,8 +18,10 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ %> +<%@page import="io.meeds.gamification.utils.Utils"%> <% Object showLocked = request.getAttribute("showLocked"); + if (Utils.canAccessAnonymousResources()) { %>
@@ -28,3 +30,4 @@
+<% } %> diff --git a/portlets/src/main/webapp/WEB-INF/jsp/topChallengers.jsp b/portlets/src/main/webapp/WEB-INF/jsp/topChallengers.jsp new file mode 100644 index 0000000000..85790d2161 --- /dev/null +++ b/portlets/src/main/webapp/WEB-INF/jsp/topChallengers.jsp @@ -0,0 +1,10 @@ +<%@page import="io.meeds.gamification.utils.Utils"%> +<% if (Utils.canAccessAnonymousResources()) { %> +
+
+ +
+
+<% } %> diff --git a/portlets/src/main/webapp/WEB-INF/portlet.xml b/portlets/src/main/webapp/WEB-INF/portlet.xml index b233fa46da..1ff3f2566c 100644 --- a/portlets/src/main/webapp/WEB-INF/portlet.xml +++ b/portlets/src/main/webapp/WEB-INF/portlet.xml @@ -126,7 +126,7 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. prefetch.resource.rest - + text/html @@ -258,14 +258,12 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. org.exoplatform.commons.api.portlet.GenericDispatchedViewPortlet portlet-view-dispatched-file-path - /html/topChallengers.html + /WEB-INF/jsp/topChallengers.jsp prefetch.resource.rest - -1 - PUBLIC text/html @@ -282,7 +280,7 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. org.exoplatform.commons.api.portlet.GenericDispatchedViewPortlet portlet-view-dispatched-file-path - /WEB-INF/jsp/rulesOverview/index.jsp + /WEB-INF/jsp/rulesOverview.jsp text/html @@ -306,7 +304,7 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. org.exoplatform.commons.api.portlet.GenericDispatchedViewPortlet portlet-view-dispatched-file-path - /html/programsOverview.html + /WEB-INF/jsp/programsOverview.jsp preload.resource.bundles @@ -314,10 +312,8 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. preload.resource.rest - + - -1 - PUBLIC text/html diff --git a/portlets/src/main/webapp/html/programsOverview.html b/portlets/src/main/webapp/html/programsOverview.html deleted file mode 100644 index 9655b9611a..0000000000 --- a/portlets/src/main/webapp/html/programsOverview.html +++ /dev/null @@ -1,7 +0,0 @@ -
-
- -
-
diff --git a/portlets/src/main/webapp/html/topChallengers.html b/portlets/src/main/webapp/html/topChallengers.html deleted file mode 100644 index 770e9a3f75..0000000000 --- a/portlets/src/main/webapp/html/topChallengers.html +++ /dev/null @@ -1,7 +0,0 @@ -
-
- -
-
diff --git a/portlets/src/main/webapp/vue-app/profileStats/components/GamificationRank.vue b/portlets/src/main/webapp/vue-app/profileStats/components/GamificationRank.vue index 25aabf8402..e5b8a75d14 100644 --- a/portlets/src/main/webapp/vue-app/profileStats/components/GamificationRank.vue +++ b/portlets/src/main/webapp/vue-app/profileStats/components/GamificationRank.vue @@ -68,12 +68,14 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. justify-center align-end>
-
-
- {{ item.rank }} - + offset-x /> {{ item.score }} diff --git a/portlets/src/main/webapp/vue-app/usersLeaderboard/components/UsersLeaderboard.vue b/portlets/src/main/webapp/vue-app/usersLeaderboard/components/UsersLeaderboard.vue index 6792d92baf..3e1b4183ae 100644 --- a/portlets/src/main/webapp/vue-app/usersLeaderboard/components/UsersLeaderboard.vue +++ b/portlets/src/main/webapp/vue-app/usersLeaderboard/components/UsersLeaderboard.vue @@ -196,7 +196,7 @@ export default { }); }, retrievePrograms() { - return fetch(`${eXo.env.portal.context}/${eXo.env.portal.rest}/gamification/programs?type=ALL&sortByBudget=true`, { + return fetch(`${eXo.env.portal.context}/${eXo.env.portal.rest}/gamification/programs?type=ALL`, { credentials: 'include', }).then(resp => resp?.ok && resp.json()) .then(data => { diff --git a/services/src/main/java/io/meeds/gamification/constant/EntityVisibility.java b/services/src/main/java/io/meeds/gamification/constant/EntityVisibility.java new file mode 100644 index 0000000000..e28b87903f --- /dev/null +++ b/services/src/main/java/io/meeds/gamification/constant/EntityVisibility.java @@ -0,0 +1,26 @@ +/** + * + * This file is part of the Meeds project (https://meeds.io/). + * + * Copyright (C) 2023 Meeds Association contact@meeds.io + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of 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. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +package io.meeds.gamification.constant; + +public enum EntityVisibility { + RESTRICTED, OPEN; +} diff --git a/services/src/main/java/io/meeds/gamification/dao/ProgramDAO.java b/services/src/main/java/io/meeds/gamification/dao/ProgramDAO.java index 893fddbddf..c7e9bf9ce4 100644 --- a/services/src/main/java/io/meeds/gamification/dao/ProgramDAO.java +++ b/services/src/main/java/io/meeds/gamification/dao/ProgramDAO.java @@ -34,6 +34,7 @@ import io.meeds.gamification.constant.EntityFilterType; import io.meeds.gamification.constant.EntityStatusType; import io.meeds.gamification.constant.EntityType; +import io.meeds.gamification.constant.EntityVisibility; import io.meeds.gamification.entity.ProgramEntity; import io.meeds.gamification.model.filter.ProgramFilter; @@ -119,6 +120,9 @@ private void addQueryFilterParameters(ProgramFilter filter, TypedQuery qu if (CollectionUtils.isNotEmpty(filter.getSpacesIds())) { query.setParameter("spacesIds", filter.getSpacesIds()); } + if (filter.getOwnerId() == 0 && (CollectionUtils.isNotEmpty(filter.getSpacesIds()) || !filter.isAllSpaces())) { + query.setParameter("openVisibility", EntityVisibility.OPEN); + } EntityFilterType type = filter.getType(); if (type != null && type != EntityFilterType.ALL) { query.setParameter("type", EntityType.valueOf(type.name())); @@ -173,10 +177,10 @@ private void buildPredicates(ProgramFilter filter, List suffixes, List void addQueryFilterParameters(RuleFilter filter, TypedQuery query if (entityFilterType != null && entityFilterType != EntityFilterType.ALL) { query.setParameter("filterType", EntityType.valueOf(filter.getType().name())); } + if ((CollectionUtils.isNotEmpty(filter.getSpaceIds()) && !filter.isExcludeNoSpace()) + || (CollectionUtils.isEmpty(filter.getSpaceIds()) && !filter.isAllSpaces())) { + query.setParameter("openVisibility", EntityVisibility.OPEN); + } } private String getQueryFilterName(String sortField, @@ -311,11 +316,11 @@ private void buildPredicates(RuleFilter filter, List suffixes, List removePrograms(event)); } + @Override + public void spaceRegistrationEdited(SpaceLifeCycleEvent event) { + CompletableFuture.runAsync(() -> updateProgramsVisibility(event)); + } + + @ExoTransactional + public void updateProgramsVisibility(SpaceLifeCycleEvent event) { + String spaceId = event.getSpace().getId(); + List programIds = getSpaceProgramIds(spaceId); + programIds.forEach(programId -> { + try { + ProgramDTO program = programService.getProgramById(programId); + // Force update visibility computing by updating the program + programService.updateProgram(program); + } catch (Exception e) { + LOG.warn("Error updating program with id {} while its space registration with id {} had changed", + programId, + spaceId, + e); + } + }); + } + @ExoTransactional public void removePrograms(SpaceLifeCycleEvent event) { - ProgramFilter spaceProgramsFilter = new ProgramFilter(true); String spaceId = event.getSpace().getId(); - spaceProgramsFilter.setSpacesIds(Collections.singletonList(Long.parseLong(spaceId))); - List programIds = programService.getProgramIds(spaceProgramsFilter, 0, -1); + List programIds = getSpaceProgramIds(spaceId); programIds.forEach(programId -> { try { ProgramDTO program = programService.getProgramById(programId); @@ -65,4 +86,10 @@ public void removePrograms(SpaceLifeCycleEvent event) { }); } + private List getSpaceProgramIds(String spaceId) { + ProgramFilter spaceProgramsFilter = new ProgramFilter(true); + spaceProgramsFilter.setSpacesIds(Collections.singletonList(Long.parseLong(spaceId))); + return programService.getProgramIds(spaceProgramsFilter, 0, -1); + } + } diff --git a/services/src/main/java/io/meeds/gamification/model/ProgramDTO.java b/services/src/main/java/io/meeds/gamification/model/ProgramDTO.java index 0b1e449954..3c55f3c712 100644 --- a/services/src/main/java/io/meeds/gamification/model/ProgramDTO.java +++ b/services/src/main/java/io/meeds/gamification/model/ProgramDTO.java @@ -20,6 +20,8 @@ import java.util.HashSet; import java.util.Set; +import io.meeds.gamification.constant.EntityVisibility; + import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -29,33 +31,33 @@ @Data public class ProgramDTO implements Serializable, Cloneable { - private static final long serialVersionUID = -8857818632949907592L; + private static final long serialVersionUID = -8857818632949907592L; - protected long id; + protected long id; - protected String title; + protected String title; - protected String description; + protected String description; - protected String color; + protected String color; - protected long spaceId; + protected long spaceId; - protected int priority; + protected int priority; - protected String createdBy; + protected String createdBy; - protected String createdDate; + protected String createdDate; - protected String lastModifiedBy; + protected String lastModifiedBy; - protected String lastModifiedDate; + protected String lastModifiedDate; - protected boolean deleted; + protected boolean deleted; - protected boolean enabled; + protected boolean enabled; - protected long budget; + protected long budget; /** * @deprecated There is no difference anymore between Automatic or Manual @@ -63,25 +65,27 @@ public class ProgramDTO implements Serializable, Cloneable { * used */ @Deprecated(forRemoval = false, since = "1.5.0") - protected String type; + protected String type; + + protected String coverUploadId; - protected String coverUploadId; + protected String avatarUploadId; - protected String avatarUploadId; + protected long coverFileId; - protected long coverFileId; + protected long avatarFileId; - protected long avatarFileId; + protected String coverUrl; - protected String coverUrl; + protected String avatarUrl; - protected String avatarUrl; + protected Set ownerIds; // NOSONAR - protected Set ownerIds; // NOSONAR + protected long rulesTotalScore; - protected long rulesTotalScore; + protected boolean open; - protected boolean open; + protected EntityVisibility visibility; /** * Deprecated should be renamed to spaceId knowing that audienceId should @@ -131,7 +135,8 @@ public ProgramDTO clone() { // NOSONAR avatarUrl, ownerIds == null ? null : new HashSet<>(ownerIds), rulesTotalScore, - open); + open, + visibility); } } diff --git a/services/src/main/java/io/meeds/gamification/model/UserInfoContext.java b/services/src/main/java/io/meeds/gamification/model/UserInfoContext.java index 76e5c76dd7..eff0b29875 100644 --- a/services/src/main/java/io/meeds/gamification/model/UserInfoContext.java +++ b/services/src/main/java/io/meeds/gamification/model/UserInfoContext.java @@ -29,6 +29,8 @@ @ToString(callSuper = true) public class UserInfoContext extends UserInfo { + private boolean canView; + private boolean canEdit; private boolean isAllowedToRealize; diff --git a/services/src/main/java/io/meeds/gamification/plugin/ProgramTranslationPlugin.java b/services/src/main/java/io/meeds/gamification/plugin/ProgramTranslationPlugin.java index 8f53124d78..e68f64fb51 100644 --- a/services/src/main/java/io/meeds/gamification/plugin/ProgramTranslationPlugin.java +++ b/services/src/main/java/io/meeds/gamification/plugin/ProgramTranslationPlugin.java @@ -58,7 +58,7 @@ public String getObjectType() { @Override public boolean hasAccessPermission(long programId, String username) throws ObjectNotFoundException { - return programService.isProgramMember(programId, username); + return programService.canViewProgram(programId, username); } @Override diff --git a/services/src/main/java/io/meeds/gamification/plugin/RuleActivityTypePlugin.java b/services/src/main/java/io/meeds/gamification/plugin/RuleActivityTypePlugin.java index fad6b15e8e..dc13dba95a 100644 --- a/services/src/main/java/io/meeds/gamification/plugin/RuleActivityTypePlugin.java +++ b/services/src/main/java/io/meeds/gamification/plugin/RuleActivityTypePlugin.java @@ -45,7 +45,7 @@ public boolean isActivityViewable(ExoSocialActivity activity, Identity userAclId if (rule == null) { throw new UnsupportedOperationException(); } else { - return programService.isProgramMember(rule.getProgramId(), userAclIdentity.getUserId()); + return programService.canViewProgram(rule.getProgramId(), userAclIdentity.getUserId()); } } diff --git a/services/src/main/java/io/meeds/gamification/plugin/RuleTranslationPlugin.java b/services/src/main/java/io/meeds/gamification/plugin/RuleTranslationPlugin.java index 88e3090198..045f33a990 100644 --- a/services/src/main/java/io/meeds/gamification/plugin/RuleTranslationPlugin.java +++ b/services/src/main/java/io/meeds/gamification/plugin/RuleTranslationPlugin.java @@ -65,7 +65,7 @@ public String getObjectType() { public boolean hasAccessPermission(long ruleId, String username) throws ObjectNotFoundException { try { RuleDTO rule = this.ruleService.findRuleById(ruleId, username); - return rule != null && programService.isProgramMember(rule.getProgramId(), username); + return rule != null && programService.canViewProgram(rule.getProgramId(), username); } catch (IllegalAccessException e) { return false; } diff --git a/services/src/main/java/io/meeds/gamification/rest/LeaderboardEndpoint.java b/services/src/main/java/io/meeds/gamification/rest/LeaderboardEndpoint.java index efe4155266..0b26cd5469 100644 --- a/services/src/main/java/io/meeds/gamification/rest/LeaderboardEndpoint.java +++ b/services/src/main/java/io/meeds/gamification/rest/LeaderboardEndpoint.java @@ -34,6 +34,7 @@ import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; import javax.ws.rs.core.UriInfo; import org.apache.commons.lang3.StringUtils; @@ -56,44 +57,50 @@ import io.meeds.gamification.model.StandardLeaderboard; import io.meeds.gamification.model.filter.LeaderboardFilter; import io.meeds.gamification.service.RealizationService; +import io.meeds.gamification.utils.Utils; +import io.meeds.portal.security.service.SecuritySettingService; + import io.swagger.v3.oas.annotations.Parameter; @Path("/gamification/leaderboard") @Produces(MediaType.APPLICATION_JSON) -@RolesAllowed("users") public class LeaderboardEndpoint implements ResourceContainer { - private static final Log LOG = ExoLogger.getLogger(LeaderboardEndpoint.class); + private static final Log LOG = ExoLogger.getLogger(LeaderboardEndpoint.class); + + private static final String YOUR_CURRENT_RANK_MSG = "Your current rank"; - private static final String YOUR_CURRENT_RANK_MSG = "Your current rank"; + private static final int DEFAULT_LOAD_CAPACITY = 10; - private static final int DEFAULT_LOAD_CAPACITY = 10; + private static final int MAX_LOAD_CAPACITY = 100; - private static final int MAX_LOAD_CAPACITY = 100; + protected IdentityManager identityManager = null; - protected IdentityManager identityManager = null; + protected RealizationService realizationService = null; - protected RealizationService realizationService = null; + protected RelationshipManager relationshipManager; - protected RelationshipManager relationshipManager; + protected SpaceService spaceService; - protected SpaceService spaceService; + protected SecuritySettingService securitySettingService; public LeaderboardEndpoint(IdentityManager identityManager, RealizationService realizationService, RelationshipManager relationshipManager, - SpaceService spaceService) { + SpaceService spaceService, + SecuritySettingService securitySettingService) { this.identityManager = identityManager; this.realizationService = realizationService; this.relationshipManager = relationshipManager; this.spaceService = spaceService; + this.securitySettingService = securitySettingService; } @GET @Path("rank/all") - @RolesAllowed("users") - public Response getAllLeadersByRank(@Context - UriInfo uriInfo, + public Response getAllLeadersByRank( + @Context + UriInfo uriInfo, @Parameter(description = "Get leaderboard of user or space") @DefaultValue("user") @QueryParam("earnerType") @@ -110,6 +117,9 @@ public Response getAllLeadersByRank(@Context @DefaultValue("true") @QueryParam("loadCapacity") boolean loadCapacity) { + if (!Utils.canAccessAnonymousResources(securitySettingService)) { + return Response.status(Status.UNAUTHORIZED).build(); + } LeaderboardFilter leaderboardFilter = new LeaderboardFilter(); IdentityType identityType = IdentityType.getType(earnerType); leaderboardFilter.setIdentityType(identityType); @@ -125,7 +135,8 @@ public Response getAllLeadersByRank(@Context period = Period.ALL.name(); } leaderboardFilter.setPeriod(period); - leaderboardFilter.setCurrentUser(ConversationState.getCurrent().getIdentity().getUserId()); + String currentUser = Utils.getCurrentUser(); + leaderboardFilter.setCurrentUser(currentUser); List leaderboardList = new ArrayList<>(); @@ -135,21 +146,24 @@ public Response getAllLeadersByRank(@Context return Response.ok(leaderboardList, MediaType.APPLICATION_JSON).build(); } int index = 1; + boolean isAnonymous = StringUtils.isBlank(currentUser); for (StandardLeaderboard element : standardLeaderboards) { Identity identity = identityManager.getIdentity(element.getEarnerId()); if (identity == null) { continue; } LeaderboardInfo leaderboardInfo = new LeaderboardInfo(); - leaderboardInfo.setSocialId(identity.getId()); - String technicalId = computeTechnicalId(identity); - leaderboardInfo.setTechnicalId(technicalId); - leaderboardInfo.setScore(element.getReputationScore()); - leaderboardInfo.setRemoteId(identity.getRemoteId()); leaderboardInfo.setFullname(identity.getProfile().getFullName()); leaderboardInfo.setAvatarUrl(identity.getProfile().getAvatarUrl()); - leaderboardInfo.setProfileUrl(identity.getProfile().getUrl()); + leaderboardInfo.setScore(element.getReputationScore()); leaderboardInfo.setRank(index); + if (!isAnonymous) { + leaderboardInfo.setRemoteId(identity.getRemoteId()); + leaderboardInfo.setSocialId(identity.getId()); + String technicalId = computeTechnicalId(identity); + leaderboardInfo.setTechnicalId(technicalId); + leaderboardInfo.setProfileUrl(identity.getProfile().getUrl()); + } leaderboardList.add(leaderboardInfo); index++; } @@ -168,13 +182,15 @@ public Response getAllLeadersByRank(@Context break; } - // Check if the current user is already in top10 - LeaderboardInfo leader = buildCurrentUserRank(date, - leaderboardFilter.getProgramId(), - leaderboardList); - // Complete the final leaderboard - if (leader != null) { - leaderboardList.add(leader); + if (!isAnonymous) { + // Check if the current user is already in top10 + LeaderboardInfo leader = buildCurrentUserRank(date, + leaderboardFilter.getProgramId(), + leaderboardList); + // Complete the final leaderboard + if (leader != null) { + leaderboardList.add(leader); + } } } return Response.ok(leaderboardList, MediaType.APPLICATION_JSON).build(); diff --git a/services/src/main/java/io/meeds/gamification/rest/ProgramRest.java b/services/src/main/java/io/meeds/gamification/rest/ProgramRest.java index 85f4df1837..5db2b0c965 100644 --- a/services/src/main/java/io/meeds/gamification/rest/ProgramRest.java +++ b/services/src/main/java/io/meeds/gamification/rest/ProgramRest.java @@ -67,6 +67,8 @@ import io.meeds.gamification.rest.model.ProgramRestEntity; import io.meeds.gamification.service.ProgramService; import io.meeds.gamification.service.RuleService; +import io.meeds.gamification.utils.Utils; +import io.meeds.portal.security.service.SecuritySettingService; import io.meeds.social.translation.service.TranslationService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -100,37 +102,40 @@ public class ProgramRest implements ResourceContainer { CACHECONTROL.setPrivate(false); } - protected PortalContainer portalContainer; + protected PortalContainer portalContainer; - protected ProgramService programService; + protected ProgramService programService; - protected RuleService ruleService; + protected RuleService ruleService; - protected IdentityManager identityManager; + protected IdentityManager identityManager; - protected TranslationService translationService; + protected TranslationService translationService; - public byte[] defaultProgramCover = null; // NOSONAR + protected SecuritySettingService securitySettingService; - public byte[] defaultProgramAvatar = null; // NOSONAR + public byte[] defaultProgramCover = null; // NOSONAR + + public byte[] defaultProgramAvatar = null; // NOSONAR public ProgramRest(PortalContainer portalContainer, ProgramService programService, RuleService ruleService, TranslationService translationService, - IdentityManager identityManager) { + IdentityManager identityManager, + SecuritySettingService securitySettingService) { this.portalContainer = portalContainer; this.programService = programService; this.ruleService = ruleService; this.translationService = translationService; this.identityManager = identityManager; + this.securitySettingService = securitySettingService; } @GET @Produces({ MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN }) - @RolesAllowed("users") @Operation(summary = "Retrieves the list of available programs", method = "GET") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Request fulfilled"), @@ -185,6 +190,9 @@ public Response getPrograms( @Parameter(description = "Used to retrieve extra information about the program") @QueryParam("expand") String expand) { + if (!Utils.canAccessAnonymousResources(securitySettingService)) { + return Response.status(Status.UNAUTHORIZED).build(); + } ProgramFilter programFilter = new ProgramFilter(); programFilter.setSortByBudget(sortByBudget); @@ -196,7 +204,11 @@ public Response getPrograms( programFilter.setProgramTitle(query); } if (owned) { - programFilter.setOwnerId(getCurrentUserIdentityId()); + long currentUserIdentityId = getCurrentUserIdentityId(); + if (currentUserIdentityId == 0) { + return Response.status(Response.Status.UNAUTHORIZED).build(); + } + programFilter.setOwnerId(currentUserIdentityId); } List expandFields = getExpandOptions(expand); @@ -536,7 +548,6 @@ public Response deleteProgramAvatar( @GET @Produces(MediaType.APPLICATION_JSON) @Path("{programId}") - @RolesAllowed("users") @Operation(summary = "Retrieves a program by its technical identifier", method = "GET") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Request fulfilled"), @@ -559,6 +570,8 @@ public Response getProgramById( String expand) { if (programId == 0) { return Response.status(Response.Status.BAD_REQUEST).entity("Program Id must be not null").build(); + } else if (!Utils.canAccessAnonymousResources(securitySettingService)) { + return Response.status(Status.UNAUTHORIZED).build(); } String currentUser = getCurrentUser(); try { diff --git a/services/src/main/java/io/meeds/gamification/rest/RealizationRest.java b/services/src/main/java/io/meeds/gamification/rest/RealizationRest.java index c7e5f84579..5d48208b98 100644 --- a/services/src/main/java/io/meeds/gamification/rest/RealizationRest.java +++ b/services/src/main/java/io/meeds/gamification/rest/RealizationRest.java @@ -143,7 +143,8 @@ public Response getRealizations( return Response.status(Response.Status.BAD_REQUEST).entity("Either use limit or dates to limit returned results").build(); } - Identity identity = ConversationState.getCurrent().getIdentity(); + ConversationState conversationState = ConversationState.getCurrent(); + Identity identity = conversationState == null ? null : conversationState.getIdentity(); Date fromDate = Utils.parseRFC3339Date(fromDateRfc3339); Date toDate = Utils.parseRFC3339Date(toDateRfc3339); diff --git a/services/src/main/java/io/meeds/gamification/rest/RuleRest.java b/services/src/main/java/io/meeds/gamification/rest/RuleRest.java index 82a729be1c..ec0950a5ca 100644 --- a/services/src/main/java/io/meeds/gamification/rest/RuleRest.java +++ b/services/src/main/java/io/meeds/gamification/rest/RuleRest.java @@ -67,6 +67,8 @@ import io.meeds.gamification.service.ProgramService; import io.meeds.gamification.service.RealizationService; import io.meeds.gamification.service.RuleService; +import io.meeds.gamification.utils.Utils; +import io.meeds.portal.security.service.SecuritySettingService; import io.meeds.social.translation.service.TranslationService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -80,26 +82,29 @@ @Tag(name = "/gamification/rules", description = "Manages rules") public class RuleRest implements ResourceContainer { - private final CacheControl cacheControl; + private final CacheControl cacheControl; - protected ProgramService programService; + protected ProgramService programService; - protected RuleService ruleService; + protected RuleService ruleService; - protected RealizationService realizationService; + protected RealizationService realizationService; - protected TranslationService translationService; + protected TranslationService translationService; - protected FavoriteService favoriteService; + protected FavoriteService favoriteService; - protected IdentityManager identityManager; + protected IdentityManager identityManager; + + protected SecuritySettingService securitySettingService; public RuleRest(ProgramService programService, RuleService ruleService, RealizationService realizationService, TranslationService translationService, FavoriteService favoriteService, - IdentityManager identityManager) { + IdentityManager identityManager, + SecuritySettingService securitySettingService) { cacheControl = new CacheControl(); cacheControl.setNoCache(true); cacheControl.setNoStore(true); @@ -109,11 +114,11 @@ public RuleRest(ProgramService programService, this.translationService = translationService; this.favoriteService = favoriteService; this.identityManager = identityManager; + this.securitySettingService = securitySettingService; } @GET @Produces(MediaType.APPLICATION_JSON) - @RolesAllowed("users") @Operation(summary = "Retrieves the list of available rules", method = "GET") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Request fulfilled"), @@ -210,6 +215,9 @@ public Response getRules(// NOSONAR if (limit < 0) { return Response.status(Response.Status.BAD_REQUEST).entity("Limit must be positive").build(); } + if (!Utils.canAccessAnonymousResources(securitySettingService)) { + return Response.status(Status.UNAUTHORIZED).build(); + } Locale locale = getLocale(lang); @@ -286,7 +294,6 @@ public Response getRules(// NOSONAR @GET @Produces(MediaType.APPLICATION_JSON) - @RolesAllowed("users") @Path("{id}") @Operation(summary = "Retrieves the list of available rules", method = "GET") @ApiResponses(value = { @@ -311,6 +318,10 @@ public Response getRule( @Parameter(description = "Asking for a full representation of a specific subresource, ex: countRealizations", required = false) @QueryParam("expand") String expand) { + if (!Utils.canAccessAnonymousResources(securitySettingService)) { + return Response.status(Status.UNAUTHORIZED).build(); + } + String currentUser = getCurrentUser(); try { RuleDTO rule = ruleService.findRuleById(id, currentUser); diff --git a/services/src/main/java/io/meeds/gamification/rest/builder/ProgramBuilder.java b/services/src/main/java/io/meeds/gamification/rest/builder/ProgramBuilder.java index 1bb33c5cf1..01592348c9 100644 --- a/services/src/main/java/io/meeds/gamification/rest/builder/ProgramBuilder.java +++ b/services/src/main/java/io/meeds/gamification/rest/builder/ProgramBuilder.java @@ -101,7 +101,8 @@ public static ProgramRestEntity toRestEntity(ProgramService programService, program.getSpaceId() > 0 ? Utils.getSpaceById(String.valueOf(program.getSpaceId())) : null, toUserContext(programService, program, username), getProgramOwnersByIds(program.getOwnerIds(), program.getSpaceId()), - activeRulesCount); + activeRulesCount, + program.getVisibility()); } public static void translatedLabels(TranslationService translationService, ProgramDTO program, Locale locale) { @@ -177,29 +178,27 @@ public static UserInfoContext toUserContext(ProgramService programService, UserInfoContext userContext = new UserInfoContext(); IdentityManager identityManager = CommonsUtils.getService(IdentityManager.class); - Identity identity = identityManager.getOrCreateUserIdentity(username); + Identity identity = StringUtils.isBlank(username) ? null : identityManager.getOrCreateUserIdentity(username); mapUserInfo(userContext, identity); if (program != null) { boolean isOwner = programService.isProgramOwner(program.getId(), username); + boolean isMember = programService.isProgramMember(program.getId(), username); + boolean canView = programService.canViewProgram(program.getId(), username); + boolean canEdit = isOwner && !program.isDeleted(); + userContext.setManager(isOwner); + userContext.setCanEdit(canEdit); + userContext.setMember(isMember); + userContext.setCanView(canView); + userContext.setProgramOwner(isOwner); + if (program.isOpen()) { - boolean isMember = programService.isProgramMember(program.getId(), username); - userContext.setManager(isOwner); - userContext.setCanEdit(isOwner); - userContext.setMember(isMember); - userContext.setProgramOwner(isOwner); userContext.setRedactor(true); } else { Space space = Utils.getSpaceById(String.valueOf(program.getSpaceId())); if (space != null) { - SpaceService spaceService = CommonsUtils.getService(SpaceService.class); - boolean isSuperManager = spaceService.isSuperManager(username); - boolean isManager = isSuperManager || spaceService.isManager(space, username); - boolean isMember = isManager || spaceService.isMember(space, username); - boolean isRedactor = isManager || spaceService.isRedactor(space, username); - userContext.setManager(isManager); - userContext.setMember(isMember); - userContext.setProgramOwner(isOwner); - userContext.setCanEdit(isOwner && !program.isDeleted()); + boolean isRedactor = StringUtils.isNotBlank(username) + && CommonsUtils.getService(SpaceService.class) + .canRedactOnSpace(space, Utils.getUserAclIdentity(username)); userContext.setRedactor(isRedactor); } } @@ -214,10 +213,12 @@ private static UserInfo toUserInfo(Identity identity) { } private static void mapUserInfo(E userInfo, Identity identity) { - userInfo.setAvatarUrl(identity.getProfile().getAvatarUrl()); - userInfo.setFullName(identity.getProfile().getFullName()); - userInfo.setRemoteId(identity.getRemoteId()); - userInfo.setId(identity.getId()); + if (identity != null) { + userInfo.setAvatarUrl(identity.getProfile().getAvatarUrl()); + userInfo.setFullName(identity.getProfile().getFullName()); + userInfo.setRemoteId(identity.getRemoteId()); + userInfo.setId(identity.getId()); + } } } diff --git a/services/src/main/java/io/meeds/gamification/rest/model/ProgramRestEntity.java b/services/src/main/java/io/meeds/gamification/rest/model/ProgramRestEntity.java index 7192aebbb8..c0284d6519 100644 --- a/services/src/main/java/io/meeds/gamification/rest/model/ProgramRestEntity.java +++ b/services/src/main/java/io/meeds/gamification/rest/model/ProgramRestEntity.java @@ -22,6 +22,7 @@ import org.exoplatform.social.core.space.model.Space; +import io.meeds.gamification.constant.EntityVisibility; import io.meeds.gamification.model.ProgramDTO; import io.meeds.gamification.model.UserInfo; import lombok.AllArgsConstructor; @@ -73,7 +74,8 @@ public ProgramRestEntity(long id, // NOSONAR Space space, UserInfo userInfo, List owners, - int activeRulesCount) { + int activeRulesCount, + EntityVisibility visibility) { super(id, title, description, @@ -96,7 +98,8 @@ public ProgramRestEntity(long id, // NOSONAR avatarUrl, ownerIds, rulesTotalScore, - open); + open, + visibility); this.space = space; this.userInfo = userInfo; this.owners = owners; diff --git a/services/src/main/java/io/meeds/gamification/rest/model/ProgramWithRulesRestEntity.java b/services/src/main/java/io/meeds/gamification/rest/model/ProgramWithRulesRestEntity.java index b9eb061794..468a2d0572 100644 --- a/services/src/main/java/io/meeds/gamification/rest/model/ProgramWithRulesRestEntity.java +++ b/services/src/main/java/io/meeds/gamification/rest/model/ProgramWithRulesRestEntity.java @@ -61,7 +61,8 @@ public ProgramWithRulesRestEntity(ProgramDTO program) { program.getAvatarUrl(), program.getOwnerIds(), program.getRulesTotalScore(), - program.isOpen()); + program.isOpen(), + program.getVisibility()); } } diff --git a/services/src/main/java/io/meeds/gamification/service/ProgramService.java b/services/src/main/java/io/meeds/gamification/service/ProgramService.java index 71e19b4253..89a1a16ca6 100644 --- a/services/src/main/java/io/meeds/gamification/service/ProgramService.java +++ b/services/src/main/java/io/meeds/gamification/service/ProgramService.java @@ -40,13 +40,13 @@ public interface ProgramService { /** * Gets programs by filter. * - * @param programFilter {@link ProgramFilter} used to filter results - * @param username User name accessing programs - * @param offset index of the search - * @param limit limit of results to return - * @return A {@link List <ProgramDTO>} object + * @param programFilter {@link ProgramFilter} used to filter results + * @param username User name accessing programs + * @param offset index of the search + * @param limit limit of results to return + * @return A {@link List <ProgramDTO>} object * @throws IllegalAccessException when user is not authorized to get another - * owner's programs list + * owner's programs list */ List getPrograms(ProgramFilter programFilter, String username, @@ -56,13 +56,13 @@ List getPrograms(ProgramFilter programFilter, /** * Gets Program Ids by filter. * - * @param programFilter {@link ProgramFilter} used to filter results - * @param username User name accessing Programs - * @param offset index of the search - * @param limit limit of results to return - * @return A {@link List <ProgramDTO>} object + * @param programFilter {@link ProgramFilter} used to filter results + * @param username User name accessing Programs + * @param offset index of the search + * @param limit limit of results to return + * @return A {@link List <ProgramDTO>} object * @throws IllegalAccessException when user is not authorized to get another - * owner's Programs list + * owner's Programs list */ List getProgramIds(ProgramFilter programFilter, String username, @@ -72,88 +72,84 @@ List getProgramIds(ProgramFilter programFilter, /** * Gets Program Ids by filter. * - * @param programFilter {@link ProgramFilter} used to filter results - * @param offset index of the search - * @param limit limit of results to return - * @return A {@link List <ProgramDTO>} object + * @param programFilter {@link ProgramFilter} used to filter results + * @param offset index of the search + * @param limit limit of results to return + * @return A {@link List <ProgramDTO>} object */ List getProgramIds(ProgramFilter programFilter, int offset, int limit); /** - * @param username user name - * @param offset start index for fetch - * @param limit limit to fetch - * @return {@link List} of {@link ProgramDTO} id of programs where - * the user is owner + * @param username user name + * @param offset start index for fetch + * @param limit limit to fetch + * @return {@link List} of {@link ProgramDTO} id of programs where the user is + * owner */ List getOwnedProgramIds(String username, int offset, int limit); /** - * @param username user name - * @param offset start index for fetch - * @param limit limit to fetch - * @return {@link List} of {@link ProgramDTO} id of programs where - * the user is member of + * @param username user name + * @param offset start index for fetch + * @param limit limit to fetch + * @return {@link List} of {@link ProgramDTO} id of programs where the user is + * member of */ List getMemberProgramIds(String username, int offset, int limit); /** * Find a Program by title * - * @param programTitle : Program title - * @return found {@link ProgramDTO} + * @param programTitle : Program title + * @return found {@link ProgramDTO} */ ProgramDTO getProgramByTitle(String programTitle); /** * Creates a new Program * - * @param program : an object of type ProgramDTO - * @param aclIdentity Security identity of user attempting to - * create a program - * @return created {@link ProgramDTO} + * @param program : an object of type ProgramDTO + * @param aclIdentity Security identity of user attempting to create a program + * @return created {@link ProgramDTO} * @throws IllegalAccessException when user is not authorized to create a - * Program for the designated owner defined - * in object + * Program for the designated owner defined in object */ ProgramDTO createProgram(ProgramDTO program, Identity aclIdentity) throws IllegalAccessException; /** * Creates a new Program * - * @param program : an object of type ProgramDTO - * @return created {@link ProgramDTO} + * @param program : an object of type ProgramDTO + * @return created {@link ProgramDTO} */ ProgramDTO createProgram(ProgramDTO program); /** * Update an existing Program * - * @param program : an instance of type ProgramDTO - * @param aclIdentity Security identity of user attempting to - * update a program - * @return updated object {@link ProgramDTO} + * @param program : an instance of type ProgramDTO + * @param aclIdentity Security identity of user attempting to update a program + * @return updated object {@link ProgramDTO} * @throws IllegalArgumentException when user is not authorized to update the - * Program - * @throws ObjectNotFoundException when the Program identified by its - * technical identifier is not found - * @throws IllegalAccessException when user is not authorized to create a - * Program for the designated owner defined - * in object + * Program + * @throws ObjectNotFoundException when the Program identified by its + * technical identifier is not found + * @throws IllegalAccessException when user is not authorized to create a + * Program for the designated owner defined in object */ ProgramDTO updateProgram(ProgramDTO program, Identity aclIdentity) throws ObjectNotFoundException, IllegalAccessException; /** * Update an existing Program * - * @param program : an instance of type ProgramDTO - * @return updated object {@link ProgramDTO} + * @param program : an instance of type ProgramDTO + * @return updated object {@link ProgramDTO} * @throws IllegalArgumentException when user is not authorized to update the - * Program - * @throws ObjectNotFoundException when the Program identified by its - * technical identifier is not found + * Program + * @throws ObjectNotFoundException when the Program identified by its + * technical identifier is not found */ ProgramDTO updateProgram(ProgramDTO program) throws ObjectNotFoundException; @@ -162,12 +158,11 @@ List getProgramIds(ProgramFilter programFilter, /** * Deletes an existing Program by id * - * @param programId Program technical identifier to delete - * @param aclIdentity Security identity of user attempting to - * delete a program - * @return deleted {@link ProgramDTO} - * @throws IllegalAccessException when user is not authorized to delete - * program + * @param programId Program technical identifier to delete + * @param aclIdentity Security identity of user attempting to delete a program + * @return deleted {@link ProgramDTO} + * @throws IllegalAccessException when user is not authorized to delete + * program * @throws ObjectNotFoundException program not found */ ProgramDTO deleteProgramById(long programId, Identity aclIdentity) throws ObjectNotFoundException, IllegalAccessException; // NOSONAR @@ -175,11 +170,11 @@ List getProgramIds(ProgramFilter programFilter, /** * Delete program Cover identified by program id * - * @param programId {@link ProgramDTO} technical identifier - * @param aclIdentity Security identity of user attempting to - * delete the program cover - * @throws IllegalAccessException when user is not authorized to delete - * program cover + * @param programId {@link ProgramDTO} technical identifier + * @param aclIdentity Security identity of user attempting to delete the + * program cover + * @throws IllegalAccessException when user is not authorized to delete + * program cover * @throws ObjectNotFoundException program not found */ void deleteProgramCoverById(long programId, Identity aclIdentity) throws ObjectNotFoundException, IllegalAccessException; // NOSONAR @@ -187,11 +182,11 @@ List getProgramIds(ProgramFilter programFilter, /** * Delete program Avatar identified by program id * - * @param programId {@link ProgramDTO} technical identifier - * @param aclIdentity Security identity of user attempting to - * delete the program avatar - * @throws IllegalAccessException when user is not authorized to delete - * program avatar + * @param programId {@link ProgramDTO} technical identifier + * @param aclIdentity Security identity of user attempting to delete the + * program avatar + * @throws IllegalAccessException when user is not authorized to delete + * program avatar * @throws ObjectNotFoundException program not found */ void deleteProgramAvatarById(long programId, Identity aclIdentity) throws ObjectNotFoundException, IllegalAccessException; @@ -199,8 +194,8 @@ List getProgramIds(ProgramFilter programFilter, /** * Retrieves a program identified by its technical identifier. * - * @param programId : program id - * @return found {@link ProgramDTO} + * @param programId : program id + * @return found {@link ProgramDTO} */ ProgramDTO getProgramById(long programId); @@ -208,11 +203,11 @@ List getProgramIds(ProgramFilter programFilter, * Retrieves a program identified by its technical identifier accessed by a * user * - * @param programId - * @param username - * @return found {@link ProgramDTO} - * @throws IllegalAccessException when user is not authorized to access - * program + * @param programId + * @param username + * @return found {@link ProgramDTO} + * @throws IllegalAccessException when user is not authorized to access + * program * @throws ObjectNotFoundException program not found */ ProgramDTO getProgramById(long programId, String username) throws IllegalAccessException, ObjectNotFoundException; @@ -220,63 +215,59 @@ List getProgramIds(ProgramFilter programFilter, /** * Count all Programs by filter * - * @param programFilter {@link ProgramFilter} used to filter - * Programs - * @param username User name accessing Programs - * @return Programs count + * @param programFilter {@link ProgramFilter} used to filter Programs + * @param username User name accessing Programs + * @return Programs count * @throws IllegalAccessException when user is not authorized to get another - * owner's Programs list + * owner's Programs list */ int countPrograms(ProgramFilter programFilter, String username) throws IllegalAccessException; /** * Count all Programs by filter * - * @param programFilter {@link ProgramFilter} used to filter Programs - * @return Programs count + * @param programFilter {@link ProgramFilter} used to filter Programs + * @return Programs count */ int countPrograms(ProgramFilter programFilter); /** - * @param username User name accessing Programs - * @return Owned Programs count for a given user identified by its - * name + * @param username User name accessing Programs + * @return Owned Programs count for a given user identified by its name */ int countOwnedPrograms(String username); /** - * @param username User name accessing Programs - * @return Programs as member count for a given user identified by - * its name + * @param username User name accessing Programs + * @return Programs as member count for a given user identified by its name */ int countMemberPrograms(String username); /** * Retrieves the program cover identified by Program technical identifier. * - * @param programId Program unique identifier - * @return found {@link InputStream} + * @param programId Program unique identifier + * @return found {@link InputStream} * @throws ObjectNotFoundException When program not found or file attachment - * not found + * not found */ InputStream getProgramCoverStream(long programId) throws ObjectNotFoundException; /** * Retrieves the program avatar identified by Program technical identifier. * - * @param programId Program unique identifier - * @return found {@link InputStream} + * @param programId Program unique identifier + * @return found {@link InputStream} * @throws ObjectNotFoundException When program not found or file attachment - * not found + * not found */ InputStream getProgramAvatarStream(long programId) throws ObjectNotFoundException; /** * Check whether user can add programs or not * - * @param aclIdentity Security identity of user - * @return true if user has enough privileges to create a program, - * else false + * @param aclIdentity Security identity of user + * @return true if user has enough privileges to create a program, else false */ boolean canAddProgram(Identity aclIdentity); @@ -292,21 +283,28 @@ List getProgramIds(ProgramFilter programFilter, /** * Check whether user can add programs or not * - * @param programId technical identifier of program - * @param username user name - * @return true if user has enough privileges to create a program, - * else false + * @param programId technical identifier of program + * @param username user name + * @return true if user has enough privileges to create a program, else false */ boolean isProgramOwner(long programId, String username); /** * Check whether user is member of program or not * - * @param programId technical identifier of program - * @param username user name - * @return true if user has enough privileges to see a program, else - * false + * @param programId technical identifier of program + * @param username user name + * @return true if user has enough privileges to see a program, else false */ boolean isProgramMember(long programId, String username); + /** + * Check whether user can view program details or not + * + * @param programId technical identifier of program + * @param username user name + * @return true if user has enough privileges to see a program, else false + */ + boolean canViewProgram(long programId, String username); + } diff --git a/services/src/main/java/io/meeds/gamification/service/impl/ProgramServiceImpl.java b/services/src/main/java/io/meeds/gamification/service/impl/ProgramServiceImpl.java index 3942dce2b9..7f9caa6d12 100644 --- a/services/src/main/java/io/meeds/gamification/service/impl/ProgramServiceImpl.java +++ b/services/src/main/java/io/meeds/gamification/service/impl/ProgramServiceImpl.java @@ -36,6 +36,7 @@ import org.exoplatform.social.core.space.spi.SpaceService; import io.meeds.gamification.constant.EntityType; +import io.meeds.gamification.constant.EntityVisibility; import io.meeds.gamification.model.ProgramColorAlreadyExists; import io.meeds.gamification.model.ProgramDTO; import io.meeds.gamification.model.filter.ProgramFilter; @@ -48,6 +49,8 @@ public class ProgramServiceImpl implements ProgramService { private static final Log LOG = ExoLogger.getLogger(ProgramServiceImpl.class); + private static final String PROGRAM_DOESN_T_EXIST = "Program doesn't exist"; + protected final ProgramStorage programStorage; protected final ListenerService listenerService; @@ -97,6 +100,9 @@ public List getProgramIds(ProgramFilter programFilter, @Override public List getOwnedProgramIds(String username, int offset, int limit) { + if (StringUtils.isBlank(username)) { + return Collections.emptyList(); + } org.exoplatform.social.core.identity.model.Identity userIdentity = identityManager.getOrCreateUserIdentity(username); long userIdentityId = Long.parseLong(userIdentity.getId()); ProgramFilter programFilter = computeOwnedProgramsFilter(userIdentity.getRemoteId(), userIdentityId); @@ -105,6 +111,9 @@ public List getOwnedProgramIds(String username, int offset, int limit) { @Override public List getMemberProgramIds(String username, int offset, int limit) { + if (StringUtils.isBlank(username)) { + return Collections.emptyList(); + } ProgramFilter programFilter = computeMemberProgramsFilter(username); return getProgramIds(programFilter, offset, limit); } @@ -130,6 +139,9 @@ public int countPrograms(ProgramFilter programFilter) { @Override public int countOwnedPrograms(String username) { + if (StringUtils.isBlank(username)) { + return 0; + } org.exoplatform.social.core.identity.model.Identity userIdentity = identityManager.getOrCreateUserIdentity(username); long userIdentityId = Long.parseLong(userIdentity.getId()); ProgramFilter programFilter = computeOwnedProgramsFilter(userIdentity.getRemoteId(), userIdentityId); @@ -138,6 +150,9 @@ public int countOwnedPrograms(String username) { @Override public int countMemberPrograms(String username) { + if (StringUtils.isBlank(username)) { + return 0; + } ProgramFilter programFilter = computeMemberProgramsFilter(username); return countPrograms(programFilter); } @@ -173,7 +188,7 @@ public ProgramDTO updateProgram(ProgramDTO program, Identity aclIdentity) throws ObjectNotFoundException { ProgramDTO storedProgram = programStorage.getProgramById(program.getId()); if (storedProgram == null) { - throw new ObjectNotFoundException("Program doesn't exist"); + throw new ObjectNotFoundException(PROGRAM_DOESN_T_EXIST); } if (storedProgram.isDeleted()) { throw new ObjectNotFoundException("Program is marked as deleted"); @@ -204,7 +219,7 @@ public ProgramDTO updateProgram(ProgramDTO program, Identity aclIdentity) throws public ProgramDTO updateProgram(ProgramDTO program) throws ObjectNotFoundException { ProgramDTO storedProgram = programStorage.getProgramById(program.getId()); if (storedProgram == null) { - throw new ObjectNotFoundException("Program doesn't exist"); + throw new ObjectNotFoundException(PROGRAM_DOESN_T_EXIST); } if (storedProgram.isDeleted()) { throw new ObjectNotFoundException("Program is marked as deleted"); @@ -225,12 +240,13 @@ public ProgramDTO deleteProgramById(long programId, Identity aclIdentity) throws ObjectNotFoundException { ProgramDTO program = programStorage.getProgramById(programId); if (program == null) { - throw new ObjectNotFoundException("program doesn't exist"); + throw new ObjectNotFoundException(PROGRAM_DOESN_T_EXIST); } if (aclIdentity == null || !isProgramOwner(programId, aclIdentity.getUserId())) { throw new IllegalAccessException("The user is not authorized to delete the program"); } program.setDeleted(true); + program.setVisibility(EntityVisibility.RESTRICTED); program = programStorage.saveProgram(program); broadcast(GAMIFICATION_DOMAIN_DELETE_LISTENER, program, aclIdentity.getUserId()); return program; @@ -241,7 +257,7 @@ public void deleteProgramCoverById(long programId, Identity aclIdentity) throws IllegalAccessException { ProgramDTO program = programStorage.getProgramById(programId); if (program == null) { - throw new ObjectNotFoundException("program doesn't exist"); + throw new ObjectNotFoundException(PROGRAM_DOESN_T_EXIST); } if (aclIdentity == null || !isProgramOwner(programId, aclIdentity.getUserId())) { throw new IllegalAccessException("The user is not authorized to delete the program cover"); @@ -261,7 +277,7 @@ public void deleteProgramAvatarById(long programId, Identity aclIdentity) throws IllegalAccessException { ProgramDTO program = programStorage.getProgramById(programId); if (program == null) { - throw new ObjectNotFoundException("program doesn't exist"); + throw new ObjectNotFoundException(PROGRAM_DOESN_T_EXIST); } if (aclIdentity == null || !isProgramOwner(programId, aclIdentity.getUserId())) { throw new IllegalAccessException("The user is not authorized to delete the program avatar"); @@ -278,18 +294,14 @@ public void deleteProgramAvatarById(long programId, Identity aclIdentity) throws @Override public ProgramDTO getProgramById(long programId, String username) throws IllegalAccessException, ObjectNotFoundException { - if (StringUtils.isBlank(username)) { - throw new IllegalAccessException("Username is mandatory"); - } ProgramDTO program = getProgramById(programId); if (program == null) { - throw new ObjectNotFoundException("Program doesn't exist"); + throw new ObjectNotFoundException(PROGRAM_DOESN_T_EXIST); } if (program.isDeleted()) { throw new ObjectNotFoundException("Program has been deleted"); } - if (!isProgramMember(programId, username) - || (!program.isEnabled() && !isProgramOwner(program.getId(), username))) { + if (!canViewProgram(program, username)) { throw new IllegalAccessException("Program isn't accessible"); } return program; @@ -307,10 +319,10 @@ public ProgramDTO getProgramById(long programId) { public InputStream getProgramCoverStream(long programId) throws ObjectNotFoundException { ProgramDTO program = programStorage.getProgramById(programId); if (program == null) { - throw new ObjectNotFoundException("program with id " + programId + " doesn't exist"); + throw new ObjectNotFoundException(String.format("program with id %s doesn't exist", programId)); } if (program.getCoverFileId() == 0) { - throw new ObjectNotFoundException("program with id " + programId + " doesn't have a coverId"); + throw new ObjectNotFoundException(String.format("program with id %s doesn't have a coverId", programId)); } return programStorage.getImageAsStream(program.getCoverFileId()); } @@ -374,6 +386,18 @@ public boolean canUseProgramColor(long programId, String color) { return canUseProgramColor(color, program == null ? null : program.getColor()); } + @Override + public boolean canViewProgram(long programId, String username) { + ProgramDTO program = getProgramById(programId); + return canViewProgram(program, username); + } + + private boolean canViewProgram(ProgramDTO program, String username) { + return program != null + && (program.getVisibility() == EntityVisibility.OPEN || isProgramMember(program.getId(), username)) + && (program.isEnabled() || isProgramOwner(program.getId(), username)); + } + @SuppressWarnings("unchecked") private ProgramFilter computeUserSpaces(ProgramFilter programFilter, String username) throws IllegalAccessException { // NOSONAR programFilter = programFilter.clone(); @@ -397,7 +421,7 @@ private ProgramFilter computeUserSpaces(ProgramFilter programFilter, String user } programFilter.setSpacesIds(managedSpaceIds); } - } else { + } else if (StringUtils.isNotBlank(username)) { List memberSpacesIds = spaceService.getMemberSpacesIds(username, 0, -1).stream().map(Long::parseLong).toList(); if (CollectionUtils.isNotEmpty(programFilter.getSpacesIds())) { memberSpacesIds = (List) CollectionUtils.intersection(memberSpacesIds, programFilter.getSpacesIds()); @@ -428,6 +452,7 @@ private ProgramDTO createProgram(ProgramDTO program, String username) { if (program.isOpen()) { program.setSpaceId(0); } + program.setVisibility(isSpaceOpen(program.getSpaceId()) ? EntityVisibility.OPEN : EntityVisibility.RESTRICTED); checkProgramColorUnicity(program.getColor(), null); return programStorage.saveProgram(program); } @@ -468,8 +493,11 @@ private boolean isSpaceManager(long spaceId, String username) { } return spaceService.isManager(space, username); } - + private boolean isSpaceMember(long spaceId, String username) { + if (StringUtils.isBlank(username)) { + return false; + } Space space = spaceService.getSpaceById(String.valueOf(spaceId)); if (space == null) { return false; @@ -477,6 +505,11 @@ private boolean isSpaceMember(long spaceId, String username) { return spaceService.isMember(space, username); } + private boolean isSpaceOpen(long spaceId) { + Space space = spaceId > 0 ? spaceService.getSpaceById(String.valueOf(spaceId)) : null; + return space == null || Space.OPEN.equals(space.getRegistration()); + } + private ProgramFilter computeOwnedProgramsFilter(String username, long userIdentityId) { ProgramFilter programFilter = new ProgramFilter(); programFilter.setIncludeDeleted(true); @@ -512,6 +545,7 @@ private ProgramFilter computeMemberProgramsFilter(String username) { private ProgramDTO saveProgramAndBroadcast(ProgramDTO program, ProgramDTO storedProgram, String username) { checkProgramColorUnicity(program.getColor(), storedProgram.getColor()); + program.setVisibility(isSpaceOpen(program.getSpaceId()) ? EntityVisibility.OPEN : EntityVisibility.RESTRICTED); program = programStorage.saveProgram(program); if (storedProgram.isEnabled() && !program.isEnabled()) { broadcast(GAMIFICATION_DOMAIN_DISABLE_LISTENER, program, username); diff --git a/services/src/main/java/io/meeds/gamification/service/impl/RealizationServiceImpl.java b/services/src/main/java/io/meeds/gamification/service/impl/RealizationServiceImpl.java index 0a4dea1ec0..9f178df380 100644 --- a/services/src/main/java/io/meeds/gamification/service/impl/RealizationServiceImpl.java +++ b/services/src/main/java/io/meeds/gamification/service/impl/RealizationServiceImpl.java @@ -525,7 +525,7 @@ public RealizationDTO getRealizationById(long realizationId, Identity userAclIde RealizationDTO realization = realizationStorage.getRealizationById(realizationId); if (realization == null) { throw new ObjectNotFoundException(String.format(REALIZATION_NOT_EXIST_MESSAGE, realizationId)); - } else if (programService.isProgramMember(realization.getProgram().getId(), userAclIdentity.getUserId()) + } else if (programService.canViewProgram(realization.getProgram().getId(), userAclIdentity.getUserId()) || realization.getEarnerId().equals(userIdentity.getId())) { return realization; } else { @@ -583,7 +583,7 @@ private RealizationFilter computeProgramFilter(RealizationFilter realizationFilt throw new IllegalArgumentException("filter is mandatory"); } if (userAclIdentity == null) { - throw new IllegalArgumentException("identity is mandatory"); + return null; } realizationFilter = realizationFilter.clone(); checkDates(realizationFilter.getFromDate(), realizationFilter.getToDate()); @@ -607,7 +607,7 @@ private RealizationFilter computeProgramFilter(RealizationFilter realizationFilt realizationFilter.setProgramIds(ownedProgramIds); } } - } else if (isFilterByPrograms && !isProgramsMember(filterProgramIds, userAclIdentity.getUserId())) { + } else if (isFilterByPrograms && !canViewPrograms(filterProgramIds, userAclIdentity.getUserId())) { throw new IllegalAccessException("User is not member of one or several selected programs :" + filterProgramIds); } else if (!isFilterByPrograms && !isSelfFilter(realizationFilter, username)) { List memberProgramIds = programService.getMemberProgramIds(userAclIdentity.getUserId(), 0, -1); @@ -656,9 +656,9 @@ private boolean isProgramsOwner(List programIds, String username) { .allMatch(programId -> programService.isProgramOwner(programId, username)); } - private boolean isProgramsMember(List programIds, String username) { + private boolean canViewPrograms(List programIds, String username) { return programIds.stream() - .allMatch(programId -> programService.isProgramMember(programId, username)); + .allMatch(programId -> programService.canViewProgram(programId, username)); } private List filterAuthorizedSpaces(List result, diff --git a/services/src/main/java/io/meeds/gamification/service/impl/RuleServiceImpl.java b/services/src/main/java/io/meeds/gamification/service/impl/RuleServiceImpl.java index ebebd5629f..a392818ae3 100644 --- a/services/src/main/java/io/meeds/gamification/service/impl/RuleServiceImpl.java +++ b/services/src/main/java/io/meeds/gamification/service/impl/RuleServiceImpl.java @@ -122,9 +122,6 @@ public RuleDTO findRuleById(long ruleId, String username) throws IllegalAccessEx if (ruleId <= 0) { throw new IllegalArgumentException("ruleId is mandatory"); } - if (StringUtils.isBlank(username)) { - throw new IllegalAccessException(USERNAME_IS_MANDATORY_MESSAGE); - } RuleDTO rule = findRuleById(ruleId); if (rule == null) { throw new ObjectNotFoundException("Rule doesn't exist"); @@ -135,7 +132,7 @@ public RuleDTO findRuleById(long ruleId, String username) throws IllegalAccessEx if (!isRuleManager(rule, username) && (!rule.isEnabled() || rule.getProgram() == null - || !programService.isProgramMember(rule.getProgram().getId(), username))) { + || !programService.canViewProgram(rule.getProgram().getId(), username))) { throw new IllegalAccessException("Rule isn't accessible"); } if (rule.getProgram() != null) { @@ -438,7 +435,7 @@ private RuleDTO createRuleAndBroadcast(RuleDTO rule, String username) { private boolean isRuleManager(RuleDTO rule, String username) { ProgramDTO program = rule.getProgram(); - if (program == null) { + if (program == null || StringUtils.isBlank(username)) { return false; } else { return programService.isProgramOwner(program.getId(), username); diff --git a/services/src/main/java/io/meeds/gamification/storage/mapper/ProgramMapper.java b/services/src/main/java/io/meeds/gamification/storage/mapper/ProgramMapper.java index bd87b8f822..05ee29274d 100644 --- a/services/src/main/java/io/meeds/gamification/storage/mapper/ProgramMapper.java +++ b/services/src/main/java/io/meeds/gamification/storage/mapper/ProgramMapper.java @@ -23,6 +23,7 @@ import org.apache.commons.lang3.StringUtils; import io.meeds.gamification.constant.EntityType; +import io.meeds.gamification.constant.EntityVisibility; import io.meeds.gamification.dao.RuleDAO; import io.meeds.gamification.entity.ProgramEntity; import io.meeds.gamification.model.ProgramDTO; @@ -58,8 +59,10 @@ public static ProgramEntity toEntity(ProgramDTO program) { programEntity.setEnabled(program.isEnabled()); if (program.getSpaceId() > 0 && !program.isOpen()) { programEntity.setAudienceId(program.getSpaceId()); + programEntity.setVisibility(program.getVisibility()); } else { programEntity.setAudienceId(null); + programEntity.setVisibility(EntityVisibility.OPEN); } if (program.getCreatedDate() != null) { programEntity.setCreatedDate(Utils.parseRFC3339Date(program.getCreatedDate())); @@ -119,6 +122,10 @@ public static ProgramDTO fromEntity(RuleDAO ruleDAO, ProgramEntity programEntity program.setAvatarUrl(avatarUrl); program.setOwnerIds(programEntity.getOwners()); program.setOpen(programEntity.getAudienceId() == null); + program.setVisibility(programEntity.getVisibility()); + if (program.getVisibility() == null) { + program.setVisibility(EntityVisibility.RESTRICTED); + } program.setRulesTotalScore(programEntity.isDeleted() || !programEntity.isEnabled() ? 0 : ruleDAO.getRulesTotalScoreByProgramId(programEntity.getId())); return program; diff --git a/services/src/main/java/io/meeds/gamification/upgrade/ProgramVisibilityUpgradePlugin.java b/services/src/main/java/io/meeds/gamification/upgrade/ProgramVisibilityUpgradePlugin.java new file mode 100644 index 0000000000..392a8fc618 --- /dev/null +++ b/services/src/main/java/io/meeds/gamification/upgrade/ProgramVisibilityUpgradePlugin.java @@ -0,0 +1,121 @@ +/** + * This file is part of the Meeds project (https://meeds.io/). + * + * Copyright (C) 2020 - 2023 Meeds Association contact@meeds.io + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of 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. + * 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 + * Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package io.meeds.gamification.upgrade; + +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +import javax.persistence.EntityManager; +import javax.persistence.Query; +import javax.persistence.TypedQuery; + +import org.exoplatform.commons.api.persistence.ExoTransactional; +import org.exoplatform.commons.api.settings.SettingService; +import org.exoplatform.commons.persistence.impl.EntityManagerService; +import org.exoplatform.commons.upgrade.UpgradeProductPlugin; +import org.exoplatform.container.xml.InitParams; +import org.exoplatform.services.log.ExoLogger; +import org.exoplatform.services.log.Log; +import org.exoplatform.social.core.space.model.Space; +import org.exoplatform.social.core.space.spi.SpaceService; + +import io.meeds.gamification.constant.EntityVisibility; + +public class ProgramVisibilityUpgradePlugin extends UpgradeProductPlugin { + + private static final Log LOG = ExoLogger.getLogger(ProgramVisibilityUpgradePlugin.class); + + private static final String VISIBILITY_PARAM = "visibility"; + + private static final String AUDIENCE_IDS_PARAM = "audienceIds"; + + private static final String GET_PROGRAM_SPACE_IDS_QUERY = + "SELECT DISTINCT p.audienceId FROM GamificationDomain p WHERE p.audienceId > 0"; + + private static final String UPGRADE_PROGRAMS_QUERY = + "UPDATE GamificationDomain p SET p.visibility = :" + VISIBILITY_PARAM; + + private static final String UPGRADE_PROGRAMS_WITH_AUDIENCE_QUERY = + UPGRADE_PROGRAMS_QUERY + + " WHERE p.audienceId IS NULL OR p.audienceId = 0 OR p.audienceId IN (:" + + AUDIENCE_IDS_PARAM + ")"; + + private static final String UPGRADE_PROGRAMS_NO_AUDIENCE_QUERY = + "UPDATE GamificationDomain p SET p.visibility = :" + + VISIBILITY_PARAM + + " WHERE p.audienceId IS NULL OR p.audienceId = 0"; + + private EntityManagerService entityManagerService; + + private SpaceService spaceService; + + public ProgramVisibilityUpgradePlugin(EntityManagerService entityManagerService, + SpaceService spaceService, + SettingService settingService, + InitParams initParams) { + super(settingService, initParams); + this.entityManagerService = entityManagerService; + this.spaceService = spaceService; + } + + @Override + public void processUpgrade(String oldVersion, String newVersion) { + LOG.info("Start:: Upgrade Programs Visibility"); + List spaceIds = getProgramSpaceIds(); + spaceIds = spaceIds.stream() + .map(spaceId -> spaceService.getSpaceById(String.valueOf(spaceId))) + .filter(Objects::nonNull) + .filter(s -> Space.OPEN.equals(s.getRegistration())) + .map(Space::getId) + .map(Long::parseLong) + .toList(); + upgradeAllProgramsAsRestricted(); + int openProgramsCount = upgradeProgramsAsOpen(spaceIds); + LOG.info("End:: Upgrade Programs Visibility: {} upgraded as Open.", + openProgramsCount); + } + + @ExoTransactional + public int upgradeAllProgramsAsRestricted() { + EntityManager entityManager = entityManagerService.getEntityManager(); + Query query = entityManager.createQuery(UPGRADE_PROGRAMS_QUERY); + query.setParameter(VISIBILITY_PARAM, EntityVisibility.RESTRICTED); + return query.executeUpdate(); + } + + @ExoTransactional + public int upgradeProgramsAsOpen(List programSpaceIds) { + EntityManager entityManager = entityManagerService.getEntityManager(); + Query query = entityManager.createQuery(programSpaceIds.isEmpty() ? UPGRADE_PROGRAMS_NO_AUDIENCE_QUERY : + UPGRADE_PROGRAMS_WITH_AUDIENCE_QUERY); + query.setParameter(VISIBILITY_PARAM, EntityVisibility.OPEN); + if (!programSpaceIds.isEmpty()) { + query.setParameter(AUDIENCE_IDS_PARAM, programSpaceIds); + } + return query.executeUpdate(); + } + + @ExoTransactional + public List getProgramSpaceIds() { + EntityManager entityManager = entityManagerService.getEntityManager(); + TypedQuery query = entityManager.createQuery(GET_PROGRAM_SPACE_IDS_QUERY, Long.class); + List result = query.getResultList(); + return result == null ? Collections.emptyList() : result; + } +} diff --git a/services/src/main/java/io/meeds/gamification/utils/Utils.java b/services/src/main/java/io/meeds/gamification/utils/Utils.java index 0fbfee8dbf..ea0ff63670 100644 --- a/services/src/main/java/io/meeds/gamification/utils/Utils.java +++ b/services/src/main/java/io/meeds/gamification/utils/Utils.java @@ -29,6 +29,7 @@ import org.exoplatform.services.log.Log; import org.exoplatform.services.security.Authenticator; import org.exoplatform.services.security.ConversationState; +import org.exoplatform.services.security.IdentityConstants; import org.exoplatform.services.security.IdentityRegistry; import org.exoplatform.social.core.identity.model.Identity; import org.exoplatform.social.core.manager.IdentityManager; @@ -42,6 +43,9 @@ import io.meeds.gamification.model.Announcement; import io.meeds.gamification.model.ProgramDTO; import io.meeds.gamification.model.RuleDTO; +import io.meeds.portal.security.constant.UserRegistrationType; +import io.meeds.portal.security.service.SecuritySettingService; + import org.exoplatform.ws.frameworks.json.JsonGenerator; import org.exoplatform.ws.frameworks.json.impl.*; @@ -262,14 +266,23 @@ public static long getUserIdentityId(String username) { Identity identity = identityManager.getOrCreateUserIdentity(username); return identity == null ? 0l : Long.parseLong(identity.getId()); } - + public static final String getCurrentUser() { if (ConversationState.getCurrent() != null && ConversationState.getCurrent().getIdentity() != null) { - return ConversationState.getCurrent().getIdentity().getUserId(); + String userId = ConversationState.getCurrent().getIdentity().getUserId(); + return StringUtils.equals(userId, IdentityConstants.ANONIM) ? null : userId; } return null; } + public static final boolean canAccessAnonymousResources() { + return canAccessAnonymousResources(ExoContainerContext.getService(SecuritySettingService.class)); + } + + public static final boolean canAccessAnonymousResources(SecuritySettingService securitySettingService) { + return StringUtils.isNotBlank(getCurrentUser()) || securitySettingService.getRegistrationType() == UserRegistrationType.OPEN; + } + public static String toRFC3339Date(Date dateTime) { if (dateTime == null) { return null; @@ -415,6 +428,9 @@ public static boolean isRewardingManager(String username) { } public static org.exoplatform.services.security.Identity getUserAclIdentity(String username) { + if (StringUtils.isBlank(username)) { + return null; + } IdentityRegistry identityRegistry = ExoContainerContext.getService(IdentityRegistry.class); org.exoplatform.services.security.Identity aclIdentity = identityRegistry.getIdentity(username); if (aclIdentity == null) { diff --git a/services/src/main/resources/db/changelog/gamification.db.changelog-1.0.0.xml b/services/src/main/resources/db/changelog/gamification.db.changelog-1.0.0.xml index 39f7e43ecb..d4b1cd01a2 100644 --- a/services/src/main/resources/db/changelog/gamification.db.changelog-1.0.0.xml +++ b/services/src/main/resources/db/changelog/gamification.db.changelog-1.0.0.xml @@ -751,4 +751,18 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + + + + + + + + diff --git a/services/src/test/java/io/meeds/gamification/listener/GamificationSpaceListenerTest.java b/services/src/test/java/io/meeds/gamification/listener/GamificationSpaceListenerTest.java index 1c3402423b..394c2a385d 100644 --- a/services/src/test/java/io/meeds/gamification/listener/GamificationSpaceListenerTest.java +++ b/services/src/test/java/io/meeds/gamification/listener/GamificationSpaceListenerTest.java @@ -30,6 +30,7 @@ import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -37,88 +38,108 @@ import java.util.Map; import java.util.function.BiConsumer; +import org.junit.AfterClass; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; +import org.mockito.MockedStatic; import org.mockito.junit.MockitoJUnitRunner; +import org.exoplatform.commons.utils.CommonsUtils; import org.exoplatform.services.listener.ListenerService; +import org.exoplatform.services.security.ConversationState; import org.exoplatform.social.core.identity.model.Identity; import org.exoplatform.social.core.manager.IdentityManager; import org.exoplatform.social.core.space.model.Space; import org.exoplatform.social.core.space.spi.SpaceLifeCycleEvent; +import org.exoplatform.social.core.space.spi.SpaceLifeCycleListener; import org.exoplatform.social.core.space.spi.SpaceService; import io.meeds.gamification.service.RuleService; @RunWith(MockitoJUnitRunner.Silent.class) -public class GamificationSpaceListenerTest { +public class GamificationSpaceListenerTest { // NOSONAR + + private static final MockedStatic COMMONS_UTILS_UTIL = mockStatic(CommonsUtils.class); @Mock - private RuleService ruleService; + private RuleService ruleService; @Mock - private IdentityManager identityManager; + private IdentityManager identityManager; @Mock - private SpaceService spaceService; + private SpaceService spaceService; @Mock - private ListenerService listenerService; + private ListenerService listenerService; + + @Before + public void setUp() { + COMMONS_UTILS_UTIL.when(() -> CommonsUtils.getService(IdentityManager.class)).thenReturn(identityManager); + ConversationState state = new ConversationState(new org.exoplatform.services.security.Identity("root")); + ConversationState.setCurrent(state); + } + + @AfterClass + public static void tearDown() { + COMMONS_UTILS_UTIL.close(); + } @Test public void testSpaceJoin() throws Exception { - testEventTrigger(GAMIFICATION_SOCIAL_SPACE_JOIN, (listener, event) -> listener.joined(event)); + testEventTrigger(GAMIFICATION_SOCIAL_SPACE_JOIN, SpaceLifeCycleListener::joined); } @Test public void testSpaceLeave() throws Exception { - testEventTrigger(GAMIFICATION_SOCIAL_SPACE_JOIN, (listener, event) -> listener.left(event), true); + testEventTrigger(GAMIFICATION_SOCIAL_SPACE_JOIN, SpaceLifeCycleListener::left, true); } @Test public void testAddAppLicationSpace() throws Exception { - testEventTrigger(GAMIFICATION_SOCIAL_SPACE_UPDATE_APPLICATIONS, (listener, event) -> listener.applicationAdded(event)); + testEventTrigger(GAMIFICATION_SOCIAL_SPACE_UPDATE_APPLICATIONS, SpaceLifeCycleListener::applicationAdded); } @Test public void testRemoveAppLicationSpace() throws Exception { - testEventTrigger(GAMIFICATION_SOCIAL_SPACE_UPDATE_APPLICATIONS, (listener, event) -> listener.applicationRemoved(event)); + testEventTrigger(GAMIFICATION_SOCIAL_SPACE_UPDATE_APPLICATIONS, SpaceLifeCycleListener::applicationRemoved); } @Test public void testSpaceBannerEdited() throws Exception { - testEventTrigger(GAMIFICATION_SOCIAL_SPACE_UPDATE_BANNER, (listener, event) -> listener.spaceBannerEdited(event)); + testEventTrigger(GAMIFICATION_SOCIAL_SPACE_UPDATE_BANNER, SpaceLifeCycleListener::spaceBannerEdited); } @Test public void testSpaceAvatarEdited() throws Exception { - testEventTrigger(GAMIFICATION_SOCIAL_SPACE_UPDATE_AVATAR, (listener, event) -> listener.spaceAvatarEdited(event)); + testEventTrigger(GAMIFICATION_SOCIAL_SPACE_UPDATE_AVATAR, SpaceLifeCycleListener::spaceAvatarEdited); } @Test public void testCreateSpace() throws Exception { - testEventTrigger(GAMIFICATION_SOCIAL_SPACE_ADD, (listener, event) -> listener.spaceCreated(event)); + testEventTrigger(GAMIFICATION_SOCIAL_SPACE_ADD, SpaceLifeCycleListener::spaceCreated); } @Test public void testUpdateSpaceDescription() throws Exception { - testEventTrigger(GAMIFICATION_SOCIAL_SPACE_UPDATE_DESCRIPTION, (listener, event) -> listener.spaceDescriptionEdited(event)); + testEventTrigger(GAMIFICATION_SOCIAL_SPACE_UPDATE_DESCRIPTION, SpaceLifeCycleListener::spaceDescriptionEdited); } @Test public void testBecomeSpaceManager() throws Exception { - testEventTrigger(GAMIFICATION_SOCIAL_SPACE_GRANT_AS_LEAD, (listener, event) -> listener.grantedLead(event)); + testEventTrigger(GAMIFICATION_SOCIAL_SPACE_GRANT_AS_LEAD, SpaceLifeCycleListener::grantedLead); } @Test public void testAddInvitedUser() throws Exception { - testEventTrigger(GAMIFICATION_SOCIAL_SPACE_INVITE_USER, (listener, event) -> listener.addInvitedUser(event)); + testEventTrigger(GAMIFICATION_SOCIAL_SPACE_INVITE_USER, SpaceLifeCycleListener::addInvitedUser); } @Test public void testRemoveInvitedUser() throws Exception { - testEventTrigger(GAMIFICATION_SOCIAL_SPACE_INVITE_USER, (listener, event) -> listener.removeInvitedUser(event), true); + testEventTrigger(GAMIFICATION_SOCIAL_SPACE_INVITE_USER, SpaceLifeCycleListener::removeInvitedUser, true); } private void testEventTrigger(String expectedGamifiedEvent, diff --git a/services/src/test/java/io/meeds/gamification/mock/SpaceServiceMock.java b/services/src/test/java/io/meeds/gamification/mock/SpaceServiceMock.java index ffc960940e..ff81168f14 100644 --- a/services/src/test/java/io/meeds/gamification/mock/SpaceServiceMock.java +++ b/services/src/test/java/io/meeds/gamification/mock/SpaceServiceMock.java @@ -45,7 +45,9 @@ public class SpaceServiceMock implements SpaceService { public static final String SPACE_DISPLAY_NAME = "test space"; - public static final String SPACE_ID = "1"; + public static final String SPACE_ID_1 = "1"; + + public static final String SPACE_ID_2 = "200"; public static final List SPACE_MEMBERS = Arrays.asList(new String[] { "root", @@ -85,10 +87,10 @@ public Space getSpaceByGroupId(String groupId) { } public Space getSpaceById(String spaceId) { - if (!SPACE_ID.equals(spaceId)) { + if (!SPACE_ID_1.equals(spaceId) && !SPACE_ID_2.equals(spaceId)) { return null; } - return getSpace(); + return getSpace(spaceId); } public boolean isRedactor(Space space, String userId) { @@ -134,7 +136,7 @@ public ListAccess getMemberSpaces(String username) { public List getMemberSpacesIds(String username, int offset, int limit) { if (SPACE_MEMBERS.contains(username)) { - return Collections.singletonList(SPACE_ID); + return Collections.singletonList(SPACE_ID_1); } else { return Collections.emptyList(); } @@ -142,7 +144,7 @@ public List getMemberSpacesIds(String username, int offset, int limit) { public List getManagerSpacesIds(String username, int offset, int limit) { if (SPACE_MANAGERS.contains(username)) { - return Collections.singletonList(SPACE_ID); + return Collections.singletonList(SPACE_ID_1); } else { return Collections.emptyList(); } @@ -673,8 +675,12 @@ public void removeSuperManagersMembership(String permissionExpression) { } private Space getSpace() { + return getSpace(SPACE_ID_1); + } + + private Space getSpace(String spaceId) { Space space = new Space(); - space.setId(SPACE_ID); + space.setId(spaceId); space.setPrettyName(SPACE_PRETTY_NAME); space.setDisplayName(SPACE_DISPLAY_NAME); space.setGroupId("/spaces/" + SPACE_PRETTY_NAME); @@ -682,6 +688,7 @@ private Space getSpace() { "root1", }); space.setMembers(SPACE_MEMBERS.toArray(new String[0])); + space.setRegistration(SPACE_ID_1.equals(spaceId) ? Space.VALIDATION : Space.OPEN); return space; } diff --git a/services/src/test/java/io/meeds/gamification/plugin/RuleActivityTypePluginTest.java b/services/src/test/java/io/meeds/gamification/plugin/RuleActivityTypePluginTest.java index 8331d4831b..f50072f242 100644 --- a/services/src/test/java/io/meeds/gamification/plugin/RuleActivityTypePluginTest.java +++ b/services/src/test/java/io/meeds/gamification/plugin/RuleActivityTypePluginTest.java @@ -116,11 +116,11 @@ public void testActivityTypePlugin() { activityManager.addActivityTypePlugin(new RuleActivityTypePlugin(programService, ruleService, initParams)); - when(programService.isProgramMember(rule.getProgramId(), owner.getUserId())).thenReturn(true); + when(programService.canViewProgram(rule.getProgramId(), owner.getUserId())).thenReturn(true); assertTrue(activityManager.isActivityViewable(activity, owner)); assertFalse(activityManager.isActivityViewable(activity, viewer)); - when(programService.isProgramMember(rule.getProgramId(), viewer.getUserId())).thenReturn(true); + when(programService.canViewProgram(rule.getProgramId(), viewer.getUserId())).thenReturn(true); assertTrue(activityManager.isActivityViewable(activity, viewer)); } diff --git a/services/src/test/java/io/meeds/gamification/rest/TestProgramRest.java b/services/src/test/java/io/meeds/gamification/rest/TestProgramRest.java index 8a2dff5daa..41a7c6debe 100644 --- a/services/src/test/java/io/meeds/gamification/rest/TestProgramRest.java +++ b/services/src/test/java/io/meeds/gamification/rest/TestProgramRest.java @@ -27,10 +27,15 @@ import org.exoplatform.services.rest.impl.ContainerResponse; import org.exoplatform.services.security.ConversationState; +import io.meeds.gamification.constant.EntityFilterType; +import io.meeds.gamification.constant.EntityStatusType; import io.meeds.gamification.constant.EntityType; import io.meeds.gamification.entity.ProgramEntity; +import io.meeds.gamification.mock.SpaceServiceMock; import io.meeds.gamification.model.ProgramDTO; import io.meeds.gamification.model.UserInfoContext; +import io.meeds.gamification.model.filter.ProgramFilter; +import io.meeds.gamification.rest.model.ProgramList; import io.meeds.gamification.rest.model.ProgramRestEntity; import io.meeds.gamification.test.AbstractServiceTest; import io.meeds.gamification.utils.Utils; @@ -173,8 +178,8 @@ public void testGetProgramCoverById() throws Exception { StandardCharsets.UTF_8); ContainerResponse response = getResponse("GET", - getURLResource("programs/" + Utils.DEFAULT_COVER_REMOTE_ID + "/cover?lastModified=" - + lastUpdateCoverTime + "&r=" + token), + getURLResource("programs/" + Utils.DEFAULT_COVER_REMOTE_ID + "/cover?lastModified=" + + lastUpdateCoverTime + "&r=" + token), null); assertNotNull(response); assertEquals(200, response.getStatus()); @@ -184,17 +189,15 @@ public void testGetProgramCoverById() throws Exception { assertEquals(404, response.getStatus()); response = getResponse("GET", - getURLResource("programs/" + manualDomain.getId() + "/cover?lastModified=" + lastUpdateCoverTime - + "&r=" - + token), + getURLResource("programs/" + manualDomain.getId() + "/cover?lastModified=" + lastUpdateCoverTime + + "&r=" + token), null); assertNotNull(response); assertEquals(200, response.getStatus()); response = getResponse("GET", - getURLResource("programs/" + manualDomain.getId() + "/cover?lastModified=" + lastUpdateCoverTime - + "&r=" - + "wrongToken"), + getURLResource("programs/" + manualDomain.getId() + "/cover?lastModified=" + lastUpdateCoverTime + + "&r=" + "wrongToken"), null); assertNotNull(response); assertEquals(403, response.getStatus()); @@ -209,8 +212,8 @@ public void testGetProgramAvatarById() throws Exception { StandardCharsets.UTF_8); ContainerResponse response = getResponse("GET", - getURLResource("programs/" + Utils.DEFAULT_AVATAR_REMOTE_ID + "/avatar?lastModified=" - + lastUpdateAvatarTime + "&r=" + token), + getURLResource("programs/" + Utils.DEFAULT_AVATAR_REMOTE_ID + + "/avatar?lastModified=" + lastUpdateAvatarTime + "&r=" + token), null); assertNotNull(response); assertEquals(200, response.getStatus()); @@ -221,17 +224,15 @@ public void testGetProgramAvatarById() throws Exception { assertEquals(404, response.getStatus()); response = getResponse("GET", - getURLResource("programs/" + manualDomain.getId() + "/avatar?lastModified=" + lastUpdateAvatarTime - + "&r=" - + token), + getURLResource("programs/" + manualDomain.getId() + "/avatar?lastModified=" + lastUpdateAvatarTime + + "&r=" + token), null); assertNotNull(response); assertEquals(200, response.getStatus()); response = getResponse("GET", - getURLResource("programs/" + manualDomain.getId() + "/avatar?lastModified=" + lastUpdateAvatarTime - + "&r=" - + "wrongToken"), + getURLResource("programs/" + manualDomain.getId() + "/avatar?lastModified=" + lastUpdateAvatarTime + + "&r=" + "wrongToken"), null); assertNotNull(response); assertEquals(403, response.getStatus()); @@ -305,4 +306,77 @@ public void testGetOpenProgramById() throws Exception { assertTrue(((UserInfoContext) savedProgram.getUserInfo()).isMember()); assertTrue(((UserInfoContext) savedProgram.getUserInfo()).isProgramOwner()); } + + @Test + public void testGetAccessibleProgramById() throws Exception { + ProgramFilter filter = new ProgramFilter(); + filter.setType(EntityFilterType.ALL); + filter.setStatus(EntityStatusType.ENABLED); + assertEquals(0, programService.getPrograms(filter, null, offset, 10).size()); + assertEquals(0, programService.countPrograms(filter, null)); + + ProgramEntity programEntity = newDomain(EntityType.AUTOMATIC, "testGetAccessibleProgramById", true, Collections.emptySet()); + ContainerResponse response = getResponse("GET", getURLResource("programs/" + programEntity.getId()), null); + assertNotNull(response); + assertEquals(401, response.getStatus()); + + ProgramDTO program = programService.getProgramById(programEntity.getId()); + program.setSpaceId(Long.parseLong(SpaceServiceMock.SPACE_ID_2)); + programService.updateProgram(program); + + response = getResponse("GET", getURLResource("programs/" + programEntity.getId()), null); + assertNotNull(response); + assertEquals(200, response.getStatus()); + ProgramRestEntity programRestEntity = (ProgramRestEntity) response.getEntity(); + assertNotNull(programRestEntity); + assertEquals(programEntity.getId().longValue(), programRestEntity.getId()); + assertTrue(((UserInfoContext) programRestEntity.getUserInfo()).isCanView()); + assertFalse(((UserInfoContext) programRestEntity.getUserInfo()).isCanEdit()); + assertFalse(((UserInfoContext) programRestEntity.getUserInfo()).isManager()); + assertFalse(((UserInfoContext) programRestEntity.getUserInfo()).isMember()); + assertFalse(((UserInfoContext) programRestEntity.getUserInfo()).isProgramOwner()); + } + + @Test + public void testGetAccessiblePrograms() throws Exception { + ProgramFilter filter = new ProgramFilter(); + filter.setType(EntityFilterType.ALL); + filter.setStatus(EntityStatusType.ENABLED); + assertEquals(0, programService.getPrograms(filter, null, offset, 10).size()); + assertEquals(0, programService.countPrograms(filter, null)); + + ProgramEntity programEntity = newDomain(EntityType.AUTOMATIC, "testGetAccessiblePrograms", true, Collections.emptySet()); + ContainerResponse response = getResponse("GET", getURLResource("programs?offset=0&limit=10&returnSize=true"), null); + assertNotNull(response); + assertEquals(200, response.getStatus()); + + ProgramList programList = (ProgramList) response.getEntity(); + assertNotNull(programList); + assertEquals(0, programList.getSize()); + assertEquals(0, programList.getPrograms().size()); + + ProgramDTO program = programService.getProgramById(programEntity.getId()); + program.setSpaceId(Long.parseLong(SpaceServiceMock.SPACE_ID_2)); + programService.updateProgram(program); + + response = getResponse("GET", getURLResource("programs?offset=0&limit=10&returnSize=true"), null); + assertNotNull(response); + assertEquals(200, response.getStatus()); + + programList = (ProgramList) response.getEntity(); + assertNotNull(programList); + assertNotNull(programList.getPrograms()); + assertEquals(1, programList.getPrograms().size()); + assertEquals(1, programList.getSize()); + + ProgramRestEntity programRestEntity = programList.getPrograms().get(0); + assertNotNull(programRestEntity); + assertEquals(programEntity.getId().longValue(), programRestEntity.getId()); + assertTrue(((UserInfoContext) programRestEntity.getUserInfo()).isCanView()); + assertFalse(((UserInfoContext) programRestEntity.getUserInfo()).isCanEdit()); + assertFalse(((UserInfoContext) programRestEntity.getUserInfo()).isManager()); + assertFalse(((UserInfoContext) programRestEntity.getUserInfo()).isMember()); + assertFalse(((UserInfoContext) programRestEntity.getUserInfo()).isProgramOwner()); + } + } diff --git a/services/src/test/java/io/meeds/gamification/rest/TestRealizationRest.java b/services/src/test/java/io/meeds/gamification/rest/TestRealizationRest.java index fc743f5e5c..37092e482a 100644 --- a/services/src/test/java/io/meeds/gamification/rest/TestRealizationRest.java +++ b/services/src/test/java/io/meeds/gamification/rest/TestRealizationRest.java @@ -212,6 +212,14 @@ public void testGetAllRealizationsSortByDateAscending() throws Exception { List realizations = realizationList.getRealizations(); assertEquals(0, realizations.size()); + startSessionAs("root1"); + response = getResponse("GET", getURLResource(restPath), null); + assertNotNull(response); + assertEquals(200, response.getStatus()); + realizationList = (RealizationList) response.getEntity(); + realizations = realizationList.getRealizations(); + assertEquals(0, realizations.size()); + // add new realization List createdActionHistories = new ArrayList<>(); ProgramEntity domainEntity = newDomain(); diff --git a/services/src/test/java/io/meeds/gamification/rest/TestRuleRest.java b/services/src/test/java/io/meeds/gamification/rest/TestRuleRest.java index 990974ec1d..d43328378b 100644 --- a/services/src/test/java/io/meeds/gamification/rest/TestRuleRest.java +++ b/services/src/test/java/io/meeds/gamification/rest/TestRuleRest.java @@ -32,8 +32,11 @@ import io.meeds.gamification.constant.EntityType; import io.meeds.gamification.entity.ProgramEntity; import io.meeds.gamification.entity.RuleEntity; +import io.meeds.gamification.mock.SpaceServiceMock; import io.meeds.gamification.model.ProgramDTO; import io.meeds.gamification.model.RuleDTO; +import io.meeds.gamification.model.UserInfo; +import io.meeds.gamification.model.UserInfoContext; import io.meeds.gamification.rest.model.ProgramWithRulesRestEntity; import io.meeds.gamification.rest.model.RuleList; import io.meeds.gamification.rest.model.RuleRestEntity; @@ -263,7 +266,7 @@ public void testUpdateRule() throws Exception { assertNotNull(response); assertEquals(404, response.getStatus()); } - + @Test public void testGetRuleById() throws Exception { startSessionAs("root1"); @@ -271,40 +274,40 @@ public void testGetRuleById() throws Exception { StringWriter writer = new StringWriter(); JSONWriter jsonWriter = new JSONWriter(writer); jsonWriter.object() - .key("title") - .value("Rule") - .key("description") - .value("Rule description") - .key("startDate") - .value(START_DATE) - .key("endDate") - .value(END_DATE) - .key("points") - .value("10") - .key("program") - .object() - .key("id") - .value(domain.getId()) - .endObject() - .endObject(); - + .key("title") + .value("Rule") + .key("description") + .value("Rule description") + .key("startDate") + .value(START_DATE) + .key("endDate") + .value(END_DATE) + .key("points") + .value("10") + .key("program") + .object() + .key("id") + .value(domain.getId()) + .endObject() + .endObject(); + ContainerResponse response = getResponse("POST", getURLResource("rules"), writer.getBuffer().toString()); assertNotNull(response); assertEquals(200, response.getStatus()); RuleRestEntity ruleRestEntity = (RuleRestEntity) response.getEntity(); assertNotNull(ruleRestEntity); startSessionAs("root2"); - + response = getResponse("GET", getURLResource("rules/0"), null); assertNotNull(response); assertEquals(400, response.getStatus()); - + response = getResponse("GET", getURLResource("rules/555"), null); assertNotNull(response); assertEquals(404, response.getStatus()); - + startSessionAs("root1"); - + response = getResponse("GET", getURLResource("rules/" + ruleRestEntity.getId()), null); assertNotNull(response); assertEquals(200, response.getStatus()); @@ -313,43 +316,43 @@ public void testGetRuleById() throws Exception { assertEquals(ruleRestEntity.getId(), savedRuleRestEntity.getId()); assertFalse(savedRuleRestEntity.isPublished()); } - + @Test public void testGetRules() throws Exception { ProgramEntity domainEntity = newDomain(); - + newRule("rule", domainEntity.getId()); newRule("rule1", domainEntity.getId()); - + startSessionAs("root0"); ContainerResponse response = getResponse("GET", getURLResource("rules?returnSize=true"), null); assertEquals(200, response.getStatus()); - + response = getResponse("GET", getURLResource("rules?returnSize=true&limit=-1"), null); assertEquals(400, response.getStatus()); - + response = getResponse("GET", getURLResource("rules?returnSize=true&offset=-1"), null); assertEquals(400, response.getStatus()); - + response = getResponse("GET", getURLResource("rules?returnSize=true&programId=" + domainEntity.getId()), null); assertEquals(200, response.getStatus()); RuleList rules = (RuleList) response.getEntity(); assertNotNull(rules); assertEquals(0, rules.getSize()); - + startSessionAsAdministrator("root1"); response = getResponse("GET", getURLResource("rules?returnSize=true&programId=" + domainEntity.getId()), null); assertEquals(200, response.getStatus()); rules = (RuleList) response.getEntity(); assertNotNull(rules); assertEquals(2, rules.getSize()); - + response = getResponse("GET", getURLResource("rules?returnSize=true&spaceId=5555"), null); assertEquals(200, response.getStatus()); rules = (RuleList) response.getEntity(); assertNotNull(rules); assertEquals(0, rules.getSize()); - + response = getResponse("GET", getURLResource("rules?returnSize=true&spaceId=" + domainEntity.getAudienceId() + "&spaceId=5555"), null); @@ -358,7 +361,7 @@ public void testGetRules() throws Exception { assertNotNull(rules); assertEquals(2, rules.getSize()); } - + @Test public void testGetRulesByUser() throws Exception { startSessionAs("root1"); @@ -367,27 +370,27 @@ public void testGetRulesByUser() throws Exception { StringWriter writer = new StringWriter(); JSONWriter jsonWriter = new JSONWriter(writer); jsonWriter.object() - .key("title") - .value("Rule") - .key("description") - .value("Rule description") - .key("startDate") - .value(START_DATE) - .key("endDate") - .value(END_DATE) - .key("points") - .value("10") - .key("enabled") - .value(true) - .key("program") - .object() - .key("id") - .value(domain.getId()) - .endObject() - .endObject(); - + .key("title") + .value("Rule") + .key("description") + .value("Rule description") + .key("startDate") + .value(START_DATE) + .key("endDate") + .value(END_DATE) + .key("points") + .value("10") + .key("enabled") + .value(true) + .key("program") + .object() + .key("id") + .value(domain.getId()) + .endObject() + .endObject(); + ContainerResponse response = getResponse("POST", restPath, writer.getBuffer().toString()); - + assertNotNull(response); assertEquals(200, response.getStatus()); RuleRestEntity rule = (RuleRestEntity) response.getEntity(); @@ -398,23 +401,23 @@ public void testGetRulesByUser() throws Exception { rule = (RuleRestEntity) response.getEntity(); assertNotNull(rule); startSessionAs("root2"); - + restPath = GAMIFICATION_RULES_REST_PATH + "?offset=0&limit=10"; response = getResponse("GET", restPath, null); assertNotNull(response); assertEquals(200, response.getStatus()); RuleList savedRules = (RuleList) response.getEntity(); assertEquals(0, savedRules.getSize()); - + startSessionAs("root1"); - + restPath = GAMIFICATION_RULES_REST_PATH + "?offset=0&limit=10&programId=" + domain.getId() + "&announcements=4"; response = getResponse("GET", restPath, null); assertNotNull(response); assertEquals(200, response.getStatus()); savedRules = (RuleList) response.getEntity(); assertEquals(2, savedRules.getRules().size()); - + restPath = GAMIFICATION_RULES_REST_PATH + "?offset=0&limit=10&programId=0&announcements=4&groupByProgram=true"; response = getResponse("GET", restPath, null); assertNotNull(response); @@ -422,7 +425,7 @@ public void testGetRulesByUser() throws Exception { List domainWithRules = (List) response.getEntity(); assertEquals(1, domainWithRules.size()); assertEquals(2, domainWithRules.get(0).getRules().size()); - + restPath = GAMIFICATION_RULES_REST_PATH + "?offset=0&limit=1&returnSize=true"; response = getResponse("GET", restPath, null); assertNotNull(response); @@ -432,6 +435,83 @@ public void testGetRulesByUser() throws Exception { assertEquals(1, savedRules.getRules().size()); } + @Test + public void testGetRuleByAnonym() throws Exception { + ProgramDTO program = newProgram(); + program = programService.createProgram(program); + + RuleEntity rule = newRule("testGetRuleByAnonym", program.getId()); + + ContainerResponse response = getResponse("GET", getURLResource("rules/0"), null); + assertNotNull(response); + assertEquals(400, response.getStatus()); + + response = getResponse("GET", getURLResource("rules/555"), null); + assertNotNull(response); + assertEquals(404, response.getStatus()); + + response = getResponse("GET", getURLResource("rules/" + rule.getId()), null); + assertNotNull(response); + assertEquals(401, response.getStatus()); + + program.setSpaceId(Long.parseLong(SpaceServiceMock.SPACE_ID_2)); + programService.updateProgram(program); + + response = getResponse("GET", getURLResource("rules/" + rule.getId()), null); + assertNotNull(response); + assertEquals(200, response.getStatus()); + RuleRestEntity ruleRestEntity = (RuleRestEntity) response.getEntity(); + assertNotNull(ruleRestEntity); + assertEquals(rule.getId(), ruleRestEntity.getId()); + UserInfoContext userInfo = (UserInfoContext) ruleRestEntity.getUserInfo(); + assertTrue(userInfo.isCanView()); + assertFalse(userInfo.isCanEdit()); + assertFalse(userInfo.isManager()); + assertFalse(userInfo.isMember()); + assertFalse(userInfo.isProgramOwner()); + assertFalse(userInfo.isRedactor()); + } + + @Test + public void testGetRulesByAnonym() throws Exception { + ProgramDTO program = newProgram(); + program = programService.createProgram(program); + + RuleEntity rule = newRule("testGetRulesByAnonym", program.getId()); + + ContainerResponse response = getResponse("GET", getURLResource("rules?offset=0&limit=10&returnSize=true"), null); + assertNotNull(response); + assertEquals(200, response.getStatus()); + RuleList ruleList = (RuleList) response.getEntity(); + assertNotNull(ruleList); + assertEquals(0, ruleList.getSize()); + assertNotNull(ruleList.getRules()); + assertEquals(0, ruleList.getRules().size()); + + program.setSpaceId(Long.parseLong(SpaceServiceMock.SPACE_ID_2)); + programService.updateProgram(program); + + response = getResponse("GET", getURLResource("rules?offset=0&limit=10&returnSize=true"), null); + assertNotNull(response); + assertEquals(200, response.getStatus()); + ruleList = (RuleList) response.getEntity(); + assertNotNull(ruleList); + assertEquals(1, ruleList.getSize()); + assertNotNull(ruleList.getRules()); + assertEquals(1, ruleList.getRules().size()); + + RuleRestEntity ruleRestEntity = ruleList.getRules().get(0); + assertNotNull(ruleRestEntity); + assertEquals(rule.getId(), ruleRestEntity.getId()); + UserInfoContext userInfo = (UserInfoContext) ruleRestEntity.getUserInfo(); + assertTrue(userInfo.isCanView()); + assertFalse(userInfo.isCanEdit()); + assertFalse(userInfo.isManager()); + assertFalse(userInfo.isMember()); + assertFalse(userInfo.isProgramOwner()); + assertFalse(userInfo.isRedactor()); + } + @Test public void testCreateAndDeleteRule() throws Exception { startSessionAs("root1"); diff --git a/services/src/test/java/io/meeds/gamification/service/ProgramServiceTest.java b/services/src/test/java/io/meeds/gamification/service/ProgramServiceTest.java index 7f17ecab81..10fec99f35 100644 --- a/services/src/test/java/io/meeds/gamification/service/ProgramServiceTest.java +++ b/services/src/test/java/io/meeds/gamification/service/ProgramServiceTest.java @@ -38,6 +38,7 @@ import io.meeds.gamification.constant.EntityStatusType; import io.meeds.gamification.constant.EntityType; import io.meeds.gamification.entity.ProgramEntity; +import io.meeds.gamification.mock.SpaceServiceMock; import io.meeds.gamification.model.ProgramColorAlreadyExists; import io.meeds.gamification.model.ProgramDTO; import io.meeds.gamification.model.RuleDTO; @@ -214,14 +215,38 @@ public void testGetDomainsByOwner() throws IllegalAccessException { filter.setType(EntityFilterType.ALL); filter.setStatus(EntityStatusType.ENABLED); assertEquals(0, programService.getPrograms(filter, SPACE_MEMBER_USER, offset, 10).size()); - ProgramEntity domainEntity = newDomain(EntityType.AUTOMATIC, "domain10", true, Collections.emptySet()); + assertEquals(0, programService.countPrograms(filter, SPACE_MEMBER_USER)); + + ProgramEntity programEntity = newDomain(EntityType.AUTOMATIC, "domain10", true, Collections.emptySet()); filter.setOwnerId(10); assertEquals(0, programService.getPrograms(filter, SPACE_MEMBER_USER, offset, 10).size()); + assertEquals(0, programService.countPrograms(filter, SPACE_MEMBER_USER)); - domainEntity.setOwners(Collections.singleton(10l)); - programDAO.update(domainEntity); + programEntity.setOwners(Collections.singleton(10l)); + programDAO.update(programEntity); assertEquals(1, programService.getPrograms(filter, SPACE_MEMBER_USER, offset, 10).size()); + assertEquals(1, programService.countPrograms(filter, SPACE_MEMBER_USER)); + } + + @Test + public void testGetDomainsByAnonym() throws IllegalAccessException, ObjectNotFoundException { + ProgramFilter filter = new ProgramFilter(); + filter.setType(EntityFilterType.ALL); + filter.setStatus(EntityStatusType.ENABLED); + assertEquals(0, programService.getPrograms(filter, null, offset, 10).size()); + assertEquals(0, programService.countPrograms(filter, null)); + + ProgramEntity programEntity = newDomain(EntityType.AUTOMATIC, "domain10", true, Collections.emptySet()); + assertEquals(0, programService.getPrograms(filter, null, offset, 10).size()); + assertEquals(0, programService.countPrograms(filter, null)); + + ProgramDTO program = programService.getProgramById(programEntity.getId()); + program.setSpaceId(Long.parseLong(SpaceServiceMock.SPACE_ID_2)); + programService.updateProgram(program); + + assertEquals(1, programService.getPrograms(filter, null, offset, 10).size()); + assertEquals(1, programService.countPrograms(filter, null)); } @Test diff --git a/services/src/test/java/io/meeds/gamification/service/RealizationServiceMockTest.java b/services/src/test/java/io/meeds/gamification/service/RealizationServiceMockTest.java index 8d234ef53b..eb00b100ef 100644 --- a/services/src/test/java/io/meeds/gamification/service/RealizationServiceMockTest.java +++ b/services/src/test/java/io/meeds/gamification/service/RealizationServiceMockTest.java @@ -157,7 +157,8 @@ public void testGetRealizationsByFilter() throws IllegalAccessException { when(identityManager.getOrCreateUserIdentity(userAclIdentity.getUserId())).thenReturn(adminIdentity); assertThrows(IllegalArgumentException.class, () -> realizationService.getRealizationsByFilter(null, userAclIdentity, offset, limit)); - assertThrows(IllegalArgumentException.class, () -> realizationService.getRealizationsByFilter(filter, null, offset, limit)); + assertEquals(0, realizationService.getRealizationsByFilter(filter, null, offset, limit).size()); + assertEquals(0, realizationService.countRealizationsByFilter(filter, userAclIdentity)); // When filter.setFromDate(fromDate); @@ -201,7 +202,7 @@ public void testGetRealizationsByFilter() throws IllegalAccessException { filter.setFromDate(fromDate); filter.setToDate(toDate); assertThrows(IllegalArgumentException.class, () -> realizationService.countRealizationsByFilter(null, userAclIdentity)); - assertThrows(IllegalArgumentException.class, () -> realizationService.countRealizationsByFilter(filter, null)); + assertEquals(0, realizationService.countRealizationsByFilter(filter, null)); // When filter.setEarnerIds(null); diff --git a/services/src/test/java/io/meeds/gamification/test/AbstractServiceTest.java b/services/src/test/java/io/meeds/gamification/test/AbstractServiceTest.java index 784588e821..912c57f0da 100644 --- a/services/src/test/java/io/meeds/gamification/test/AbstractServiceTest.java +++ b/services/src/test/java/io/meeds/gamification/test/AbstractServiceTest.java @@ -261,6 +261,7 @@ public void setUp() throws Exception { resourceBinder.clear(); ApplicationContextImpl.setCurrent(new ApplicationContextImpl(null, null, providerBinder, null)); launcher = new ResourceLauncher(requestHandler); + ConversationState.setCurrent(null); begin(); } diff --git a/services/src/test/java/io/meeds/gamification/test/InitContainerTestSuite.java b/services/src/test/java/io/meeds/gamification/test/InitContainerTestSuite.java index e627f87272..191706e24f 100644 --- a/services/src/test/java/io/meeds/gamification/test/InitContainerTestSuite.java +++ b/services/src/test/java/io/meeds/gamification/test/InitContainerTestSuite.java @@ -76,6 +76,7 @@ import io.meeds.gamification.storage.ProgramStorageTest; import io.meeds.gamification.storage.RealizationsStorageTest; import io.meeds.gamification.storage.RuleStorageTest; +import io.meeds.gamification.upgrade.ProgramVisibilityUpgradePluginTest; import io.meeds.gamification.utils.UtilsTest; @RunWith(Suite.class) @@ -132,6 +133,7 @@ ActionPublishedNotificationPluginTest.class, RuleActivityTypePluginTest.class, EventServiceTest.class, + ProgramVisibilityUpgradePluginTest.class, }) @ConfigTestCase(AbstractServiceTest.class) public class InitContainerTestSuite extends BaseExoContainerTestSuite { diff --git a/services/src/test/java/io/meeds/gamification/upgrade/ProgramVisibilityUpgradePluginTest.java b/services/src/test/java/io/meeds/gamification/upgrade/ProgramVisibilityUpgradePluginTest.java new file mode 100644 index 0000000000..b8c4d25b6b --- /dev/null +++ b/services/src/test/java/io/meeds/gamification/upgrade/ProgramVisibilityUpgradePluginTest.java @@ -0,0 +1,71 @@ +/** + * This file is part of the Meeds project (https://meeds.io/). + * + * Copyright (C) 2020 - 2023 Meeds Association contact@meeds.io + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of 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. + * 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 + * Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package io.meeds.gamification.upgrade; + +import org.exoplatform.commons.api.settings.SettingService; +import org.exoplatform.commons.persistence.impl.EntityManagerService; +import org.exoplatform.container.xml.InitParams; +import org.exoplatform.container.xml.ValueParam; +import org.exoplatform.social.core.space.spi.SpaceService; + +import io.meeds.gamification.constant.EntityVisibility; +import io.meeds.gamification.entity.ProgramEntity; +import io.meeds.gamification.mock.SpaceServiceMock; +import io.meeds.gamification.test.AbstractServiceTest; + +public class ProgramVisibilityUpgradePluginTest extends AbstractServiceTest {// NOSONAR + + public void testProgramUpgrade() { + + InitParams initParams = new InitParams(); + + ValueParam valueParam = new ValueParam(); + valueParam.setName("product.group.id"); + valueParam.setValue("org.exoplatform.social"); + initParams.addParam(valueParam); + + valueParam = new ValueParam(); + valueParam.setName("plugin.execution.order"); + valueParam.setValue("5"); + initParams.addParam(valueParam); + + ProgramEntity program1 = newDomain("testProgramUpgrade1"); + ProgramEntity program2 = newDomain("testProgramUpgrade2"); + ProgramEntity program3 = newDomain("testProgramUpgrade3"); + program3.setAudienceId(Long.parseLong(SpaceServiceMock.SPACE_ID_2)); + program3 = programDAO.update(program3); + + EntityManagerService entityManagerService = getContainer().getComponentInstanceOfType(EntityManagerService.class); + SettingService settingService = getContainer().getComponentInstanceOfType(SettingService.class); + SpaceService spaceService = getContainer().getComponentInstanceOfType(SpaceService.class); + ProgramVisibilityUpgradePlugin upgradePlugin = new ProgramVisibilityUpgradePlugin(entityManagerService, + spaceService, + settingService, + initParams); + upgradePlugin.setName("ProgramVisibilityUpgradePlugin"); + assertTrue(upgradePlugin.isEnabled()); + + upgradePlugin.processUpgrade(null, null); + restartTransaction(); + + assertEquals(EntityVisibility.RESTRICTED, programDAO.find(program1.getId()).getVisibility()); + assertEquals(EntityVisibility.RESTRICTED, programDAO.find(program2.getId()).getVisibility()); + assertEquals(EntityVisibility.OPEN, programDAO.find(program3.getId()).getVisibility()); + } + +}