From 2388da0339f214a15c43cff3bc6604f5a7b4b1e1 Mon Sep 17 00:00:00 2001 From: Azmi Touil Date: Thu, 11 Jul 2024 12:41:42 +0200 Subject: [PATCH] feat: Upgrade Service to Spring - MEED-6830 - Meeds-io/MIPs#132 This change will upgrade services to use spring instead of Kernel & WS. --- gamification-github-services/pom.xml | 8 +- .../gamification/github/dao/WebHookDAO.java | 53 --- .../github/plugin/IssueTriggerPlugin.java | 75 ---- .../PullRequestReviewTriggerPlugin.java | 59 --- .../github/rest/HooksManagementRest.java | 296 ------------- .../cached/GithubConsumerCachedStorage.java | 109 ----- .../github/storage/cached/model/CacheKey.java | 71 ---- .../github/gamification/dao/WebHookDAO.java | 27 ++ .../gamification}/entity/WebhookEntity.java | 10 +- .../exception/GithubConnectionException.java | 2 +- .../listener/GithubEventsListener.java | 24 +- .../gamification}/model/Event.java | 2 +- .../model/GithubAccessTokenContext.java | 2 +- .../model/RemoteOrganization.java | 2 +- .../gamification}/model/RemoteRepository.java | 2 +- .../gamification}/model/TokenStatus.java | 2 +- .../gamification}/model/WebHook.java | 2 +- .../CommentPullRequestTriggerPlugin.java | 27 +- .../plugin/CommentTriggerPlugin.java | 27 +- .../plugin/GithubConnectorPlugin.java | 39 +- .../plugin/GithubEventPlugin.java | 17 +- .../plugin/GithubTriggerPlugin.java | 8 +- .../plugin/IssueTriggerPlugin.java | 95 +++++ .../PullRequestReviewTriggerPlugin.java | 79 ++++ .../plugin/PullRequestTriggerPlugin.java | 27 +- .../plugin/PushCodeTriggerPlugin.java | 29 +- .../gamification}/rest/GithubWebHookRest.java | 32 +- .../rest/HooksManagementRest.java | 263 ++++++++++++ .../rest/builder/WebHookBuilder.java | 22 +- .../rest/model/RepositoryList.java | 4 +- .../rest/model/RepositoryRestEntity.java | 2 +- .../gamification}/rest/model/WebHookList.java | 2 +- .../rest/model/WebHookRestEntity.java | 4 +- .../scheduling/SchedulingConfig.java | 26 ++ .../task/GitHubWebHookForceUpdateTask.java} | 29 +- .../services/GithubConsumerService.java | 17 +- .../services/GithubTriggerService.java | 6 +- .../services/WebhookService.java | 63 +-- .../impl/GithubConsumerServiceImpl.java | 29 +- .../impl/GithubTriggerServiceImpl.java | 45 +- .../services/impl/WebhookServiceImpl.java | 96 ++--- .../storage/GithubConsumerStorage.java | 30 +- .../gamification}/storage/WebHookStorage.java | 58 ++- .../storage/mapper/WebHookMapper.java | 15 +- .../utils/StringListConverter.java | 2 +- .../gamification}/utils/Utils.java | 2 +- .../resources/conf/portal/configuration.xml | 95 ----- ...ification-github-storage-configuration.xml | 79 ---- .../src/main/resources/jpa-entities.idx | 2 +- .../gamification/github/BaseGithubTest.java | 141 ------- .../github/dao/WebHookDAOTest.java | 85 ---- .../github/mock/ConnectorServiceMock.java | 68 --- .../mock/ConnectorSettingServiceMock.java | 63 --- .../github/mock/EventServiceMock.java | 83 ---- .../github/mock/IdentityManagerMock.java | 237 ----------- .../github/mock/RuleServiceMock.java | 97 ----- .../github/mock/TriggerServiceMock.java | 39 -- .../github/service/WebhookServiceTest.java | 197 --------- .../listener/GithubEventsListenerTest.java | 70 ++++ .../plugin/GithubConnectorPluginTest.java | 40 ++ .../plugin/GithubEventPluginTest.java | 25 +- .../rest/GithubWebHookRestTest.java | 81 ++++ .../rest/HooksManagementRestTest.java | 390 ++++++++++++++++++ .../service/WebhookServiceTest.java | 209 ++++++++++ .../storage/WebHookStorageTest.java | 134 ++++++ .../conf/portal/github-test-configuration.xml | 12 +- gamification-github-webapp/pom.xml | 5 + .../GamificationGithubApplication.java | 44 ++ .../src/main/resources/github.properties | 20 + .../webapp/html/gitHubWebHookManagement.html | 7 - .../skin/less/gitHubWebHookManagement.less | 144 ------- .../components/GithubEventForm.vue | 7 +- .../GithubAdminConnectorHookList.vue | 9 +- .../initComponents.js | 2 +- .../js/GithubConnectorService.js | 49 +-- 75 files changed, 1914 insertions(+), 2361 deletions(-) delete mode 100644 gamification-github-services/src/main/java/io/meeds/gamification/github/dao/WebHookDAO.java delete mode 100644 gamification-github-services/src/main/java/io/meeds/gamification/github/plugin/IssueTriggerPlugin.java delete mode 100644 gamification-github-services/src/main/java/io/meeds/gamification/github/plugin/PullRequestReviewTriggerPlugin.java delete mode 100644 gamification-github-services/src/main/java/io/meeds/gamification/github/rest/HooksManagementRest.java delete mode 100644 gamification-github-services/src/main/java/io/meeds/gamification/github/storage/cached/GithubConsumerCachedStorage.java delete mode 100644 gamification-github-services/src/main/java/io/meeds/gamification/github/storage/cached/model/CacheKey.java create mode 100644 gamification-github-services/src/main/java/io/meeds/github/gamification/dao/WebHookDAO.java rename gamification-github-services/src/main/java/io/meeds/{gamification/github => github/gamification}/entity/WebhookEntity.java (83%) rename gamification-github-services/src/main/java/io/meeds/{gamification/github => github/gamification}/exception/GithubConnectionException.java (96%) rename gamification-github-services/src/main/java/io/meeds/{gamification/github => github/gamification}/listener/GithubEventsListener.java (77%) rename gamification-github-services/src/main/java/io/meeds/{gamification/github => github/gamification}/model/Event.java (96%) rename gamification-github-services/src/main/java/io/meeds/{gamification/github => github/gamification}/model/GithubAccessTokenContext.java (97%) rename gamification-github-services/src/main/java/io/meeds/{gamification/github => github/gamification}/model/RemoteOrganization.java (96%) rename gamification-github-services/src/main/java/io/meeds/{gamification/github => github/gamification}/model/RemoteRepository.java (96%) rename gamification-github-services/src/main/java/io/meeds/{gamification/github => github/gamification}/model/TokenStatus.java (96%) rename gamification-github-services/src/main/java/io/meeds/{gamification/github => github/gamification}/model/WebHook.java (97%) rename gamification-github-services/src/main/java/io/meeds/{gamification/github => github/gamification}/plugin/CommentPullRequestTriggerPlugin.java (70%) rename gamification-github-services/src/main/java/io/meeds/{gamification/github => github/gamification}/plugin/CommentTriggerPlugin.java (78%) rename gamification-github-services/src/main/java/io/meeds/{gamification/github => github/gamification}/plugin/GithubConnectorPlugin.java (82%) rename gamification-github-services/src/main/java/io/meeds/{gamification/github => github/gamification}/plugin/GithubEventPlugin.java (87%) rename gamification-github-services/src/main/java/io/meeds/{gamification/github => github/gamification}/plugin/GithubTriggerPlugin.java (86%) create mode 100644 gamification-github-services/src/main/java/io/meeds/github/gamification/plugin/IssueTriggerPlugin.java create mode 100644 gamification-github-services/src/main/java/io/meeds/github/gamification/plugin/PullRequestReviewTriggerPlugin.java rename gamification-github-services/src/main/java/io/meeds/{gamification/github => github/gamification}/plugin/PullRequestTriggerPlugin.java (85%) rename gamification-github-services/src/main/java/io/meeds/{gamification/github => github/gamification}/plugin/PushCodeTriggerPlugin.java (68%) rename gamification-github-services/src/main/java/io/meeds/{gamification/github => github/gamification}/rest/GithubWebHookRest.java (61%) create mode 100644 gamification-github-services/src/main/java/io/meeds/github/gamification/rest/HooksManagementRest.java rename gamification-github-services/src/main/java/io/meeds/{gamification/github => github/gamification}/rest/builder/WebHookBuilder.java (79%) rename gamification-github-services/src/main/java/io/meeds/{gamification/github => github/gamification}/rest/model/RepositoryList.java (91%) rename gamification-github-services/src/main/java/io/meeds/{gamification/github => github/gamification}/rest/model/RepositoryRestEntity.java (95%) rename gamification-github-services/src/main/java/io/meeds/{gamification/github => github/gamification}/rest/model/WebHookList.java (96%) rename gamification-github-services/src/main/java/io/meeds/{gamification/github => github/gamification}/rest/model/WebHookRestEntity.java (96%) create mode 100644 gamification-github-services/src/main/java/io/meeds/github/gamification/scheduling/SchedulingConfig.java rename gamification-github-services/src/main/java/io/meeds/{gamification/github/scheduled/GitHubWebHookForceUpdate.java => github/gamification/scheduling/task/GitHubWebHookForceUpdateTask.java} (58%) rename gamification-github-services/src/main/java/io/meeds/{gamification/github => github/gamification}/services/GithubConsumerService.java (89%) rename gamification-github-services/src/main/java/io/meeds/{gamification/github => github/gamification}/services/GithubTriggerService.java (92%) rename gamification-github-services/src/main/java/io/meeds/{gamification/github => github/gamification}/services/WebhookService.java (80%) rename gamification-github-services/src/main/java/io/meeds/{gamification/github => github/gamification}/services/impl/GithubConsumerServiceImpl.java (81%) rename gamification-github-services/src/main/java/io/meeds/{gamification/github => github/gamification}/services/impl/GithubTriggerServiceImpl.java (84%) rename gamification-github-services/src/main/java/io/meeds/{gamification/github => github/gamification}/services/impl/WebhookServiceImpl.java (82%) rename gamification-github-services/src/main/java/io/meeds/{gamification/github => github/gamification}/storage/GithubConsumerStorage.java (94%) rename gamification-github-services/src/main/java/io/meeds/{gamification/github => github/gamification}/storage/WebHookStorage.java (58%) rename gamification-github-services/src/main/java/io/meeds/{gamification/github => github/gamification}/storage/mapper/WebHookMapper.java (87%) rename gamification-github-services/src/main/java/io/meeds/{gamification/github => github/gamification}/utils/StringListConverter.java (97%) rename gamification-github-services/src/main/java/io/meeds/{gamification/github => github/gamification}/utils/Utils.java (99%) delete mode 100644 gamification-github-services/src/main/resources/conf/portal/gamification-github-storage-configuration.xml delete mode 100644 gamification-github-services/src/test/java/io/meeds/gamification/github/BaseGithubTest.java delete mode 100644 gamification-github-services/src/test/java/io/meeds/gamification/github/dao/WebHookDAOTest.java delete mode 100644 gamification-github-services/src/test/java/io/meeds/gamification/github/mock/ConnectorServiceMock.java delete mode 100644 gamification-github-services/src/test/java/io/meeds/gamification/github/mock/ConnectorSettingServiceMock.java delete mode 100644 gamification-github-services/src/test/java/io/meeds/gamification/github/mock/EventServiceMock.java delete mode 100644 gamification-github-services/src/test/java/io/meeds/gamification/github/mock/IdentityManagerMock.java delete mode 100644 gamification-github-services/src/test/java/io/meeds/gamification/github/mock/RuleServiceMock.java delete mode 100644 gamification-github-services/src/test/java/io/meeds/gamification/github/mock/TriggerServiceMock.java delete mode 100644 gamification-github-services/src/test/java/io/meeds/gamification/github/service/WebhookServiceTest.java create mode 100644 gamification-github-services/src/test/java/io/meeds/github/gamification/listener/GithubEventsListenerTest.java create mode 100644 gamification-github-services/src/test/java/io/meeds/github/gamification/plugin/GithubConnectorPluginTest.java rename gamification-github-services/src/test/java/io/meeds/{gamification/github => github/gamification}/plugin/GithubEventPluginTest.java (84%) create mode 100644 gamification-github-services/src/test/java/io/meeds/github/gamification/rest/GithubWebHookRestTest.java create mode 100644 gamification-github-services/src/test/java/io/meeds/github/gamification/rest/HooksManagementRestTest.java create mode 100644 gamification-github-services/src/test/java/io/meeds/github/gamification/service/WebhookServiceTest.java create mode 100644 gamification-github-services/src/test/java/io/meeds/github/gamification/storage/WebHookStorageTest.java create mode 100644 gamification-github-webapp/src/main/java/io/meeds/github/gamification/GamificationGithubApplication.java create mode 100644 gamification-github-webapp/src/main/resources/github.properties delete mode 100644 gamification-github-webapp/src/main/webapp/html/gitHubWebHookManagement.html delete mode 100644 gamification-github-webapp/src/main/webapp/skin/less/gitHubWebHookManagement.less diff --git a/gamification-github-services/pom.xml b/gamification-github-services/pom.xml index 1388ddf0e..db6abfbb8 100644 --- a/gamification-github-services/pom.xml +++ b/gamification-github-services/pom.xml @@ -32,13 +32,17 @@ jar Gamification - Github Connector - Services - 0.24 + 0.30 + + io.meeds.social + social-component-core + provided + io.meeds.social social-component-oauth-auth - provided io.meeds.gamification diff --git a/gamification-github-services/src/main/java/io/meeds/gamification/github/dao/WebHookDAO.java b/gamification-github-services/src/main/java/io/meeds/gamification/github/dao/WebHookDAO.java deleted file mode 100644 index 406b2fb87..000000000 --- a/gamification-github-services/src/main/java/io/meeds/gamification/github/dao/WebHookDAO.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * This file is part of the Meeds project (https://meeds.io/). - * - * Copyright (C) 2020 - 2023 Meeds Lab contact@meedslab.com - * - * 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.github.dao; - -import org.exoplatform.commons.persistence.impl.GenericDAOJPAImpl; -import io.meeds.gamification.github.entity.WebhookEntity; - -import jakarta.persistence.NoResultException; -import jakarta.persistence.TypedQuery; -import java.util.List; - -public class WebHookDAO extends GenericDAOJPAImpl { - - public static final String ORGANIZATION_ID = "organizationId"; - - public WebhookEntity getWebhookByOrganizationId(long organizationId) { - TypedQuery query = getEntityManager().createNamedQuery("GitHubWebhooks.getWebhookByOrganizationId", - WebhookEntity.class); - query.setParameter(ORGANIZATION_ID, organizationId); - try { - return query.getSingleResult(); - } catch (NoResultException e) { - return null; - } - } - - public List getWebhookIds(int offset, int limit) { - TypedQuery query = getEntityManager().createNamedQuery("GitHubWebhooks.getWebhookIds", Long.class); - if (offset > 0) { - query.setFirstResult(offset); - } - if (limit > 0) { - query.setMaxResults(limit); - } - return query.getResultList(); - } -} diff --git a/gamification-github-services/src/main/java/io/meeds/gamification/github/plugin/IssueTriggerPlugin.java b/gamification-github-services/src/main/java/io/meeds/gamification/github/plugin/IssueTriggerPlugin.java deleted file mode 100644 index e081a6a07..000000000 --- a/gamification-github-services/src/main/java/io/meeds/gamification/github/plugin/IssueTriggerPlugin.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * This file is part of the Meeds project (https://meeds.io/). - * - * Copyright (C) 2020 - 2023 Meeds Lab contact@meedslab.com - * - * 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.github.plugin; - -import io.meeds.gamification.github.model.Event; -import static io.meeds.gamification.github.utils.Utils.*; - -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Objects; - -public class IssueTriggerPlugin extends GithubTriggerPlugin { - - @Override - public List getEvents(Map payload) { - String issueState = extractSubItem(payload, ACTION); - String objectId = extractSubItem(payload, ISSUE, HTML_URL); - String userId = extractSubItem(payload, SENDER, LOGIN); - if (Objects.equals(issueState, OPENED)) { - return Collections.singletonList(new Event(CREATE_ISSUE_EVENT_NAME, - userId, - userId, - objectId, - ISSUE_TYPE, - extractSubItem(payload, "organization", "id"), - extractSubItem(payload, "repository", "id"))); - } else if (Objects.equals(issueState, CLOSED)) { - if (Objects.equals(extractSubItem(payload, ISSUE, STATE_REASON), NOT_PLANNED)) { - return Collections.singletonList(new Event(CLOSE_ISSUE_EVENT_NAME, - userId, - userId, - objectId, - ISSUE_TYPE, - extractSubItem(payload, "organization", "id"), - extractSubItem(payload, "repository", "id"))); - } - return Collections.emptyList(); - } else if (Objects.equals(issueState, LABELED)) { - objectId = objectId + "?label=" + extractSubItem(payload, LABEL, NAME); - return Collections.singletonList(new Event(ADD_ISSUE_LABEL_EVENT_NAME, - userId, - userId, - objectId, - ISSUE_TYPE, - extractSubItem(payload, ORGANIZATION, ID), - extractSubItem(payload, REPOSITORY, ID))); - } else if (Objects.equals(issueState, UNLABELED)) { - objectId = objectId + "?label=" + extractSubItem(payload, LABEL, NAME); - return Collections.singletonList(new Event(DELETE_ISSUE_LABEL_EVENT_NAME, - userId, - userId, - objectId, - ISSUE_TYPE, - extractSubItem(payload, ORGANIZATION, ID), - extractSubItem(payload, REPOSITORY, ID))); - } - return Collections.emptyList(); - } -} diff --git a/gamification-github-services/src/main/java/io/meeds/gamification/github/plugin/PullRequestReviewTriggerPlugin.java b/gamification-github-services/src/main/java/io/meeds/gamification/github/plugin/PullRequestReviewTriggerPlugin.java deleted file mode 100644 index b2b471127..000000000 --- a/gamification-github-services/src/main/java/io/meeds/gamification/github/plugin/PullRequestReviewTriggerPlugin.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * This file is part of the Meeds project (https://meeds.io/). - * - * Copyright (C) 2020 - 2023 Meeds Lab contact@meedslab.com - * - * 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.github.plugin; - -import io.meeds.gamification.github.model.Event; -import static io.meeds.gamification.github.utils.Utils.*; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -public class PullRequestReviewTriggerPlugin extends GithubTriggerPlugin { - - @Override - public List getEvents(Map payload) { - String pullState = extractSubItem(payload, PULL_REQUEST_REVIEW, STATE); - if (pullState != null && pullState.equals(PULL_REQUEST_COMMENTED)) { - return Collections.singletonList(new Event(REVIEW_PULL_REQUEST_EVENT_NAME, - extractSubItem(payload, PULL_REQUEST_REVIEW, USER, LOGIN), - extractSubItem(payload, PULL_REQUEST_REVIEW, USER, LOGIN), - extractSubItem(payload, PULL_REQUEST_REVIEW, HTML_URL), - PR_TYPE, - extractSubItem(payload, ORGANIZATION, ID), - extractSubItem(payload, REPOSITORY, ID))); - } else if (pullState != null && pullState.equals(PULL_REQUEST_VALIDATED)) { - return Arrays.asList(new Event(PULL_REQUEST_VALIDATED_EVENT_NAME, - extractSubItem(payload, PULL_REQUEST, USER, LOGIN), - extractSubItem(payload, PULL_REQUEST, USER, LOGIN), - extractSubItem(payload, PULL_REQUEST_REVIEW, HTML_URL), - PR_TYPE, - extractSubItem(payload, ORGANIZATION, ID), - extractSubItem(payload, REPOSITORY, ID)), - new Event(VALIDATE_PULL_REQUEST_EVENT_NAME, - extractSubItem(payload, PULL_REQUEST_REVIEW, USER, LOGIN), - extractSubItem(payload, PULL_REQUEST_REVIEW, USER, LOGIN), - extractSubItem(payload, PULL_REQUEST_REVIEW, HTML_URL), - PR_TYPE, - extractSubItem(payload, ORGANIZATION, ID), - extractSubItem(payload, REPOSITORY, ID))); - } - return Collections.emptyList(); - } -} diff --git a/gamification-github-services/src/main/java/io/meeds/gamification/github/rest/HooksManagementRest.java b/gamification-github-services/src/main/java/io/meeds/gamification/github/rest/HooksManagementRest.java deleted file mode 100644 index 1fbf91efc..000000000 --- a/gamification-github-services/src/main/java/io/meeds/gamification/github/rest/HooksManagementRest.java +++ /dev/null @@ -1,296 +0,0 @@ -/* - * This file is part of the Meeds project (https://meeds.io/). - * - * Copyright (C) 2020 - 2022 Meeds Lab contact@meedslab.com - * - * 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.github.rest; - -import javax.annotation.security.RolesAllowed; -import javax.ws.rs.*; -import javax.ws.rs.core.*; - -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.responses.ApiResponses; -import org.apache.commons.lang3.StringUtils; - -import org.exoplatform.commons.ObjectAlreadyExistsException; -import org.exoplatform.commons.exception.ObjectNotFoundException; -import io.meeds.gamification.github.model.RemoteRepository; -import io.meeds.gamification.github.model.WebHook; -import io.meeds.gamification.github.rest.builder.WebHookBuilder; -import io.meeds.gamification.github.rest.model.RepositoryList; -import io.meeds.gamification.github.rest.model.WebHookList; -import io.meeds.gamification.github.rest.model.WebHookRestEntity; -import io.meeds.gamification.github.services.GithubConsumerService; -import io.meeds.gamification.github.services.WebhookService; -import org.exoplatform.services.rest.http.PATCH; -import org.exoplatform.services.rest.resource.ResourceContainer; -import org.exoplatform.services.security.ConversationState; - -import java.util.Collection; -import java.util.List; - -import static io.meeds.gamification.utils.Utils.getCurrentUser; - -@Path("/gamification/connectors/github/hooks") -public class HooksManagementRest implements ResourceContainer { - - public static final String GITHUB_HOOK_NOT_FOUND = "The GitHub hook doesn't exit"; - - private final WebhookService webhookService; - - private final GithubConsumerService githubConsumerService; - - public HooksManagementRest(WebhookService webhookService, GithubConsumerService githubConsumerService) { - this.webhookService = webhookService; - this.githubConsumerService = githubConsumerService; - } - - @GET - @Produces(MediaType.APPLICATION_JSON) - @RolesAllowed("users") - @Operation(summary = "Retrieves the list GitHub webHooks", method = "GET") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Request fulfilled"), - @ApiResponse(responseCode = "401", description = "Unauthorized operation"), }) - public Response getWebHooks(@QueryParam("offset") int offset, - @Parameter(description = "Query results limit", required = true) @QueryParam("limit") int limit, - @Parameter(description = "WebHook total size") @Schema(defaultValue = "false") @QueryParam("returnSize") boolean returnSize) { - - String currentUser = getCurrentUser(); - List webHookRestEntities; - try { - WebHookList webHookList = new WebHookList(); - webHookRestEntities = getWebHookRestEntities(currentUser); - if (returnSize) { - int webHookSize = webhookService.countWebhooks(currentUser, false); - webHookList.setSize(webHookSize); - } - webHookList.setWebhooks(webHookRestEntities); - webHookList.setOffset(offset); - webHookList.setLimit(limit); - return Response.ok(webHookList).build(); - } catch (IllegalAccessException e) { - return Response.status(Response.Status.UNAUTHORIZED).build(); - } - } - - @GET - @Produces(MediaType.APPLICATION_JSON) - @Path("{webHookId}") - @RolesAllowed("users") - @Operation(summary = "Retrieves a webHook by its technical identifier", method = "GET") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Request fulfilled"), - @ApiResponse(responseCode = "401", description = "Unauthorized operation"), - @ApiResponse(responseCode = "400", description = "Invalid query input"), - @ApiResponse(responseCode = "404", description = "Not found"), - @ApiResponse(responseCode = "500", description = "Internal server error"), }) - public Response getWebHookById(@Parameter(description = "WebHook technical identifier", required = true) @PathParam("webHookId") long webHookId) { - if (webHookId == 0) { - return Response.status(Response.Status.BAD_REQUEST).entity("WebHook Id must be not null").build(); - } - String currentUser = getCurrentUser(); - try { - WebHook webHook = webhookService.getWebhookId(webHookId, currentUser); - return Response.ok(WebHookBuilder.toRestEntity(webhookService, githubConsumerService, webHook)).build(); - } catch (IllegalArgumentException e) { - return Response.status(Response.Status.BAD_REQUEST).entity(e.getMessage()).build(); - } catch (IllegalAccessException e) { - return Response.status(Response.Status.UNAUTHORIZED).entity(e.getMessage()).build(); - } catch (ObjectNotFoundException e) { - return Response.status(Response.Status.NOT_FOUND).entity(e.getMessage()).build(); - } - } - - @POST - @Consumes(MediaType.APPLICATION_FORM_URLENCODED) - @RolesAllowed("users") - @Operation(summary = "Create a organization webhook for Remote GitHub connector.", description = "Create a organization webhook for Remote GitHub connector.", method = "POST") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Request fulfilled"), - @ApiResponse(responseCode = "400", description = "Invalid query input"), - @ApiResponse(responseCode = "401", description = "Unauthorized operation"), - @ApiResponse(responseCode = "500", description = "Internal server error") }) - public Response createWebhookHook(@Parameter(description = "GitHub organization name", required = true) @FormParam("organizationName") String organizationName, - @Parameter(description = "GitHub personal access token", required = true) @FormParam("accessToken") String accessToken) { - - if (StringUtils.isBlank(organizationName)) { - return Response.status(Response.Status.BAD_REQUEST).entity("'organizationName' parameter is mandatory").build(); - } - if (StringUtils.isBlank(accessToken)) { - return Response.status(Response.Status.BAD_REQUEST).entity("'accessToken' parameter is mandatory").build(); - } - String currentUser = ConversationState.getCurrent().getIdentity().getUserId(); - try { - webhookService.createWebhook(organizationName, accessToken, currentUser); - return Response.status(Response.Status.CREATED).build(); - } catch (IllegalAccessException e) { - return Response.status(Response.Status.UNAUTHORIZED).entity(e.getMessage()).build(); - } catch (ObjectAlreadyExistsException e) { - return Response.status(Response.Status.CONFLICT).entity(e.getMessage()).build(); - } catch (ObjectNotFoundException e) { - return Response.status(Response.Status.NOT_FOUND).entity(e.getMessage()).build(); - } - } - - @PATCH - @Consumes(MediaType.APPLICATION_FORM_URLENCODED) - @RolesAllowed("users") - @Operation(summary = "Update a organization webhook personal access token.", description = "Update a organization webhook personal access token.", method = "PATCH") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Request fulfilled"), - @ApiResponse(responseCode = "400", description = "Invalid query input"), - @ApiResponse(responseCode = "401", description = "Unauthorized operation"), - @ApiResponse(responseCode = "500", description = "Internal server error") }) - public Response updateWebHookAccessToken(@Parameter(description = "webHook id", required = true) @FormParam("webHookId") long webHookId, - @Parameter(description = "GitHub personal access token", required = true) @FormParam("accessToken") String accessToken) { - - if (webHookId <= 0) { - return Response.status(Response.Status.BAD_REQUEST).entity("'webHookId' must be positive").build(); - } - if (StringUtils.isBlank(accessToken)) { - return Response.status(Response.Status.BAD_REQUEST).entity("'accessToken' parameter is mandatory").build(); - } - String currentUser = ConversationState.getCurrent().getIdentity().getUserId(); - try { - webhookService.updateWebHookAccessToken(webHookId, accessToken, currentUser); - return Response.status(Response.Status.CREATED).build(); - } catch (IllegalAccessException e) { - return Response.status(Response.Status.UNAUTHORIZED).entity(e.getMessage()).build(); - } catch (ObjectNotFoundException e) { - return Response.status(Response.Status.NOT_FOUND).entity(GITHUB_HOOK_NOT_FOUND).build(); - } - } - - @DELETE - @Path("{organizationId}") - @RolesAllowed("users") - @Operation(summary = "Deletes gitHub organization webhook", description = "Deletes gitHub organization webhook", method = "DELETE") - @ApiResponses(value = { - @ApiResponse(responseCode = "204", description = "Request fulfilled"), - @ApiResponse(responseCode = "400", description = "Bad request"), - @ApiResponse(responseCode = "401", description = "Unauthorized operation"), - @ApiResponse(responseCode = "500", description = "Internal server error"), }) - public Response deleteWebhookHook(@Parameter(description = "GitHub organization id", required = true) @PathParam("organizationId") long organizationId) { - if (organizationId <= 0) { - return Response.status(Response.Status.BAD_REQUEST).entity("'hookName' parameter is mandatory").build(); - } - String currentUser = ConversationState.getCurrent().getIdentity().getUserId(); - try { - webhookService.deleteWebhook(organizationId, currentUser); - return Response.noContent().build(); - } catch (IllegalAccessException e) { - return Response.status(Response.Status.UNAUTHORIZED).entity(e.getMessage()).type(MediaType.TEXT_PLAIN).build(); - } catch (ObjectNotFoundException e) { - return Response.status(Response.Status.NOT_FOUND).entity(GITHUB_HOOK_NOT_FOUND).build(); - } - } - - @GET - @Path("{organizationId}/repos") - @Produces(MediaType.APPLICATION_JSON) - @RolesAllowed("users") - @Operation(summary = "Retrieves the list GitHub organization repositories", method = "GET") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Request fulfilled"), - @ApiResponse(responseCode = "401", description = "Unauthorized operation"), }) - public Response getWebHookRepos(@Parameter(description = "GitHub organization id", required = true) @PathParam("organizationId") long organizationId, - @Parameter(description = "Query page number", required = true) @QueryParam("page") int page, - @Parameter(description = "Query item per page", required = true) @QueryParam("perPage") int perPage, - @Parameter(description = "Keyword to search in repositories title", required = true) @QueryParam("keyword") String keyword) { - - String currentUser = getCurrentUser(); - List remoteRepositories; - try { - RepositoryList repositoryList = new RepositoryList(); - remoteRepositories = webhookService.retrieveOrganizationRepos(organizationId, currentUser, page, perPage, keyword); - repositoryList.setRemoteRepositories(remoteRepositories); - repositoryList.setPage(page); - repositoryList.setPerPage(perPage); - return Response.ok(repositoryList).build(); - } catch (IllegalAccessException e) { - return Response.status(Response.Status.UNAUTHORIZED).build(); - } catch (ObjectNotFoundException e) { - return Response.status(Response.Status.NOT_FOUND).entity(GITHUB_HOOK_NOT_FOUND).build(); - } - } - - @Path("repo/status") - @POST - @RolesAllowed("users") - @Operation(summary = "enables/disables webhook repository.", description = "enables/disables webhook repository", method = "POST") - @ApiResponses(value = { - @ApiResponse(responseCode = "204", description = "Request fulfilled"), - @ApiResponse(responseCode = "400", description = "Bad request"), - @ApiResponse(responseCode = "401", description = "Unauthorized operation"), - @ApiResponse(responseCode = "500", description = "Internal server error"), }) - public Response updateWebHookRepoStatus(@Parameter(description = "GitHub organization remote Id", required = true) @FormParam("organizationId") long organizationId, - @Parameter(description = "Organization repository remote Id", required = true) @FormParam("repositoryId") long repositoryId, - @Parameter(description = "Organization repository status enabled/disabled. possible values: true for enabled, else false", required = true) @FormParam("enabled") boolean enabled) { - - String currentUser = getCurrentUser(); - try { - webhookService.setWebHookRepositoryEnabled(organizationId, repositoryId, enabled, currentUser); - return Response.noContent().build(); - } catch (IllegalAccessException e) { - return Response.status(Response.Status.UNAUTHORIZED).entity(e.getMessage()).type(MediaType.TEXT_PLAIN).build(); - } - } - - @Path("watchScope/status") - @POST - @RolesAllowed("users") - @Operation(summary = "Limit webhook watch scope or not", description = "Limit webhook watch scope or not", method = "POST") - @ApiResponses(value = { - @ApiResponse(responseCode = "204", description = "Request fulfilled"), - @ApiResponse(responseCode = "400", description = "Bad request"), - @ApiResponse(responseCode = "401", description = "Unauthorized operation"), - @ApiResponse(responseCode = "500", description = "Internal server error"), }) - public Response updateWebHookWatchScope(@Parameter(description = "GitHub organization remote Id", required = true) @FormParam("organizationId") long organizationId, - @Parameter(description = "webhook watch scope limited status enabled/disabled. possible values: true for enabled, else false", required = true) @FormParam("enabled") boolean enabled) { - - String currentUser = getCurrentUser(); - try { - webhookService.setWebHookWatchLimitEnabled(organizationId, enabled, currentUser); - return Response.noContent().build(); - } catch (IllegalAccessException e) { - return Response.status(Response.Status.UNAUTHORIZED).entity(e.getMessage()).type(MediaType.TEXT_PLAIN).build(); - } - } - - @Path("forceUpdate") - @PATCH - @RolesAllowed("users") - @Operation(summary = "Force Update a github stored webhooks", description = "Force Update a github stored webhooks", method = "PATCH") - @ApiResponses(value = { @ApiResponse(responseCode = "500", description = "Internal server error") }) - public Response forceUpdateWebhooks() { - try { - webhookService.forceUpdateWebhooks(); - return Response.noContent().build(); - } catch (Exception e) { - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); - } - } - - private List getWebHookRestEntities(String username) throws IllegalAccessException { - Collection webHooks = webhookService.getWebhooks(username, 0, 20, false); - return WebHookBuilder.toRestEntities(webhookService, githubConsumerService, webHooks); - } -} diff --git a/gamification-github-services/src/main/java/io/meeds/gamification/github/storage/cached/GithubConsumerCachedStorage.java b/gamification-github-services/src/main/java/io/meeds/gamification/github/storage/cached/GithubConsumerCachedStorage.java deleted file mode 100644 index e67d93a26..000000000 --- a/gamification-github-services/src/main/java/io/meeds/gamification/github/storage/cached/GithubConsumerCachedStorage.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * This file is part of the Meeds project (https://meeds.io/). - * - * Copyright (C) 2020 - 2023 Meeds Lab contact@meedslab.com - * - * 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.github.storage.cached; - -import io.meeds.gamification.github.model.RemoteOrganization; -import io.meeds.gamification.github.model.WebHook; -import io.meeds.gamification.github.storage.cached.model.CacheKey; -import org.exoplatform.commons.cache.future.FutureExoCache; -import io.meeds.gamification.github.model.RemoteRepository; -import io.meeds.gamification.github.model.TokenStatus; -import io.meeds.gamification.github.storage.GithubConsumerStorage; -import org.exoplatform.services.cache.CacheService; -import org.exoplatform.services.cache.ExoCache; - -import java.io.Serializable; -import java.util.*; - -public class GithubConsumerCachedStorage extends GithubConsumerStorage { - - public static final String GITHUB_CACHE_NAME = "github.connector"; - - private static final int ORG_REPOS_CONTEXT = 0; - - private static final int ORG_BY_ID_CONTEXT = 1; - - private static final int TOKEN_STATUS_CONTEXT = 2; - - private final FutureExoCache githubFutureCache; - - public GithubConsumerCachedStorage(CacheService cacheService) { - ExoCache cacheInstance = cacheService.getCacheInstance(GITHUB_CACHE_NAME); - this.githubFutureCache = new FutureExoCache<>((context, key) -> { - if (ORG_REPOS_CONTEXT == context.getContext()) { - return GithubConsumerCachedStorage.super.retrieveOrganizationRepos(context.getOrganizationName(), - context.getAccessToken(), - context.getPage(), - context.getPerPage(), - context.getKeyword()); - } else if (ORG_BY_ID_CONTEXT == context.getContext()) { - return GithubConsumerCachedStorage.super.retrieveRemoteOrganization(context.getOrganizationId(), - context.getAccessToken()); - } else if (TOKEN_STATUS_CONTEXT == context.getContext()) { - return GithubConsumerCachedStorage.super.checkGitHubTokenStatus(context.getAccessToken()); - } else { - throw new UnsupportedOperationException(); - } - }, cacheInstance); - } - - @Override - public String deleteWebhookHook(WebHook webHook) { - try { - return super.deleteWebhookHook(webHook); - } finally { - clearCache(webHook); - } - } - - @SuppressWarnings("unchecked") - @Override - public List retrieveOrganizationRepos(String organizationName, - String accessToken, - int page, - int perPage, - String keyword) { - CacheKey cacheKey = new CacheKey(ORG_REPOS_CONTEXT, organizationName, accessToken, page, perPage, keyword); - List remoteRepositories = - (List) this.githubFutureCache.get(cacheKey, cacheKey.hashCode()); - return remoteRepositories == null ? Collections.emptyList() : remoteRepositories; - } - - @Override - public RemoteOrganization retrieveRemoteOrganization(long organizationId, String accessToken) { - CacheKey cacheKey = new CacheKey(ORG_BY_ID_CONTEXT, organizationId, accessToken); - return (RemoteOrganization) this.githubFutureCache.get(cacheKey, cacheKey.hashCode()); - } - - @Override - public TokenStatus checkGitHubTokenStatus(String token) { - CacheKey cacheKey = new CacheKey(TOKEN_STATUS_CONTEXT, token); - return (TokenStatus) this.githubFutureCache.get(cacheKey, cacheKey.hashCode()); - } - - @Override - public void clearCache() { - this.githubFutureCache.clear(); - } - - @Override - public void clearCache(WebHook webHook) { - this.githubFutureCache.remove(new CacheKey(ORG_BY_ID_CONTEXT, webHook.getOrganizationId(), webHook.getToken()).hashCode()); - this.githubFutureCache.remove(new CacheKey(TOKEN_STATUS_CONTEXT, webHook.getToken()).hashCode()); - } -} diff --git a/gamification-github-services/src/main/java/io/meeds/gamification/github/storage/cached/model/CacheKey.java b/gamification-github-services/src/main/java/io/meeds/gamification/github/storage/cached/model/CacheKey.java deleted file mode 100644 index 7a0186e47..000000000 --- a/gamification-github-services/src/main/java/io/meeds/gamification/github/storage/cached/model/CacheKey.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * This file is part of the Meeds project (https://meeds.io/). - * - * Copyright (C) 2022 Meeds Lab contact@meedslab.com - * - * 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.github.storage.cached.model; - -import java.io.Serializable; - -import io.meeds.gamification.model.filter.ProgramFilter; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -@AllArgsConstructor -@NoArgsConstructor -@Data -public class CacheKey implements Serializable { - - private static final long serialVersionUID = -8995567724453740730L; - - private ProgramFilter programFilter; - - private int page; - - private int perPage; - - private long organizationId; - - private String organizationName; - - private String accessToken; - - private String keyword; - - private Integer context; - - public CacheKey(Integer context, String organizationName, String accessToken, int page, int perPage, String keyword) { - this.organizationName = organizationName; - this.accessToken = accessToken; - this.page = page; - this.perPage = perPage; - this.keyword = keyword; - this.context = context; - } - - public CacheKey(Integer context, long organizationId, String accessToken) { - this.organizationId = organizationId; - this.accessToken = accessToken; - this.context = context; - } - - public CacheKey(Integer context, String accessToken) { - this.accessToken = accessToken; - this.context = context; - } - -} diff --git a/gamification-github-services/src/main/java/io/meeds/github/gamification/dao/WebHookDAO.java b/gamification-github-services/src/main/java/io/meeds/github/gamification/dao/WebHookDAO.java new file mode 100644 index 000000000..7ed22a753 --- /dev/null +++ b/gamification-github-services/src/main/java/io/meeds/github/gamification/dao/WebHookDAO.java @@ -0,0 +1,27 @@ +/* + * This file is part of the Meeds project (https://meeds.io/). + * + * Copyright (C) 2020 - 2023 Meeds Lab contact@meedslab.com + * + * 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.github.gamification.dao; + +import io.meeds.github.gamification.entity.WebhookEntity; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface WebHookDAO extends JpaRepository { + + WebhookEntity findWebhookEntityByOrganizationId(long organizationId); +} diff --git a/gamification-github-services/src/main/java/io/meeds/gamification/github/entity/WebhookEntity.java b/gamification-github-services/src/main/java/io/meeds/github/gamification/entity/WebhookEntity.java similarity index 83% rename from gamification-github-services/src/main/java/io/meeds/gamification/github/entity/WebhookEntity.java rename to gamification-github-services/src/main/java/io/meeds/github/gamification/entity/WebhookEntity.java index 75c8ca471..0e8ce2cc3 100644 --- a/gamification-github-services/src/main/java/io/meeds/gamification/github/entity/WebhookEntity.java +++ b/gamification-github-services/src/main/java/io/meeds/github/gamification/entity/WebhookEntity.java @@ -16,7 +16,7 @@ * 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.github.entity; +package io.meeds.github.gamification.entity; import java.io.Serializable; import java.util.Date; @@ -29,12 +29,6 @@ @Entity(name = "GitHubWebhooks") @Table(name = "GITHUB_WEBHOOKS") -@NamedQuery(name = "GitHubWebhooks.getWebhookByOrganizationId", - query = "SELECT gitHubWebhook FROM GitHubWebhooks gitHubWebhook" - + " WHERE gitHubWebhook.organizationId = :organizationId") -@NamedQuery(name = "GitHubWebhooks.getWebhookIds", - query = "SELECT gitHubWebhook.id FROM GitHubWebhooks gitHubWebhook" - + " ORDER BY gitHubWebhook.id ASC") @Data public class WebhookEntity implements Serializable { @@ -53,7 +47,7 @@ public class WebhookEntity implements Serializable { private Long organizationId; @Column(name = "ORGANIZATION_NAME", nullable = false) - private String organizationName; + private String organizationName; @Convert(converter = StringListConverter.class) @Column(name = "TRIGGERS", nullable = false) diff --git a/gamification-github-services/src/main/java/io/meeds/gamification/github/exception/GithubConnectionException.java b/gamification-github-services/src/main/java/io/meeds/github/gamification/exception/GithubConnectionException.java similarity index 96% rename from gamification-github-services/src/main/java/io/meeds/gamification/github/exception/GithubConnectionException.java rename to gamification-github-services/src/main/java/io/meeds/github/gamification/exception/GithubConnectionException.java index f7a0f774b..06080daa6 100644 --- a/gamification-github-services/src/main/java/io/meeds/gamification/github/exception/GithubConnectionException.java +++ b/gamification-github-services/src/main/java/io/meeds/github/gamification/exception/GithubConnectionException.java @@ -16,7 +16,7 @@ * 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.github.exception; +package io.meeds.github.gamification.exception; public class GithubConnectionException extends Exception { diff --git a/gamification-github-services/src/main/java/io/meeds/gamification/github/listener/GithubEventsListener.java b/gamification-github-services/src/main/java/io/meeds/github/gamification/listener/GithubEventsListener.java similarity index 77% rename from gamification-github-services/src/main/java/io/meeds/gamification/github/listener/GithubEventsListener.java rename to gamification-github-services/src/main/java/io/meeds/github/gamification/listener/GithubEventsListener.java index bbd177c1a..a85a648ee 100644 --- a/gamification-github-services/src/main/java/io/meeds/gamification/github/listener/GithubEventsListener.java +++ b/gamification-github-services/src/main/java/io/meeds/github/gamification/listener/GithubEventsListener.java @@ -16,32 +16,42 @@ * 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.github.listener; +package io.meeds.github.gamification.listener; import java.util.HashMap; import java.util.Map; +import jakarta.annotation.PostConstruct; import org.exoplatform.services.listener.Event; import org.exoplatform.services.listener.Listener; import org.exoplatform.services.listener.ListenerService; +import org.springframework.stereotype.Component; +import org.springframework.beans.factory.annotation.Autowired; -import static io.meeds.gamification.github.utils.Utils.GITHUB_ACTION_EVENT; -import static io.meeds.gamification.github.utils.Utils.GITHUB_CANCEL_ACTION_EVENT; +import static io.meeds.github.gamification.utils.Utils.GITHUB_ACTION_EVENT; +import static io.meeds.github.gamification.utils.Utils.GITHUB_CANCEL_ACTION_EVENT; +@Component public class GithubEventsListener extends Listener, String> { + private static final String[] LISTENER_EVENTS = { "github.action.event", "github.cancel.action.event" }; + public static final String GAMIFICATION_GENERIC_EVENT = "exo.gamification.generic.action"; public static final String GAMIFICATION_CANCEL_EVENT = "gamification.cancel.event.action"; - private final ListenerService listenerService; + @Autowired + private ListenerService listenerService; - public GithubEventsListener(ListenerService listenerService) { - this.listenerService = listenerService; + @PostConstruct + public void init() { + for (String eventName : LISTENER_EVENTS) { + listenerService.addListener(eventName, this); + } } @Override - public void onEvent(Event, String> event) throws Exception { + public void onEvent(Event, String> event) { Map gam = new HashMap<>(); gam.put("objectId", event.getSource().get("objectId")); gam.put("objectType", event.getSource().get("objectType")); diff --git a/gamification-github-services/src/main/java/io/meeds/gamification/github/model/Event.java b/gamification-github-services/src/main/java/io/meeds/github/gamification/model/Event.java similarity index 96% rename from gamification-github-services/src/main/java/io/meeds/gamification/github/model/Event.java rename to gamification-github-services/src/main/java/io/meeds/github/gamification/model/Event.java index eb61b4bd1..e1762d81c 100644 --- a/gamification-github-services/src/main/java/io/meeds/gamification/github/model/Event.java +++ b/gamification-github-services/src/main/java/io/meeds/github/gamification/model/Event.java @@ -15,7 +15,7 @@ * 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.github.model; +package io.meeds.github.gamification.model; import lombok.AllArgsConstructor; import lombok.Getter; diff --git a/gamification-github-services/src/main/java/io/meeds/gamification/github/model/GithubAccessTokenContext.java b/gamification-github-services/src/main/java/io/meeds/github/gamification/model/GithubAccessTokenContext.java similarity index 97% rename from gamification-github-services/src/main/java/io/meeds/gamification/github/model/GithubAccessTokenContext.java rename to gamification-github-services/src/main/java/io/meeds/github/gamification/model/GithubAccessTokenContext.java index b02070c3f..a27c3ffad 100644 --- a/gamification-github-services/src/main/java/io/meeds/gamification/github/model/GithubAccessTokenContext.java +++ b/gamification-github-services/src/main/java/io/meeds/github/gamification/model/GithubAccessTokenContext.java @@ -16,7 +16,7 @@ * 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.github.model; +package io.meeds.github.gamification.model; import java.io.Serializable; import java.util.Objects; diff --git a/gamification-github-services/src/main/java/io/meeds/gamification/github/model/RemoteOrganization.java b/gamification-github-services/src/main/java/io/meeds/github/gamification/model/RemoteOrganization.java similarity index 96% rename from gamification-github-services/src/main/java/io/meeds/gamification/github/model/RemoteOrganization.java rename to gamification-github-services/src/main/java/io/meeds/github/gamification/model/RemoteOrganization.java index 594c977c6..0573a95ec 100644 --- a/gamification-github-services/src/main/java/io/meeds/gamification/github/model/RemoteOrganization.java +++ b/gamification-github-services/src/main/java/io/meeds/github/gamification/model/RemoteOrganization.java @@ -17,7 +17,7 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package io.meeds.gamification.github.model; +package io.meeds.github.gamification.model; import lombok.AllArgsConstructor; import lombok.Getter; diff --git a/gamification-github-services/src/main/java/io/meeds/gamification/github/model/RemoteRepository.java b/gamification-github-services/src/main/java/io/meeds/github/gamification/model/RemoteRepository.java similarity index 96% rename from gamification-github-services/src/main/java/io/meeds/gamification/github/model/RemoteRepository.java rename to gamification-github-services/src/main/java/io/meeds/github/gamification/model/RemoteRepository.java index 87ff163fc..fe44d39c9 100644 --- a/gamification-github-services/src/main/java/io/meeds/gamification/github/model/RemoteRepository.java +++ b/gamification-github-services/src/main/java/io/meeds/github/gamification/model/RemoteRepository.java @@ -15,7 +15,7 @@ * 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.github.model; +package io.meeds.github.gamification.model; import lombok.*; diff --git a/gamification-github-services/src/main/java/io/meeds/gamification/github/model/TokenStatus.java b/gamification-github-services/src/main/java/io/meeds/github/gamification/model/TokenStatus.java similarity index 96% rename from gamification-github-services/src/main/java/io/meeds/gamification/github/model/TokenStatus.java rename to gamification-github-services/src/main/java/io/meeds/github/gamification/model/TokenStatus.java index 3307f5367..a2472cf0c 100644 --- a/gamification-github-services/src/main/java/io/meeds/gamification/github/model/TokenStatus.java +++ b/gamification-github-services/src/main/java/io/meeds/github/gamification/model/TokenStatus.java @@ -15,7 +15,7 @@ * 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.github.model; +package io.meeds.github.gamification.model; import lombok.*; diff --git a/gamification-github-services/src/main/java/io/meeds/gamification/github/model/WebHook.java b/gamification-github-services/src/main/java/io/meeds/github/gamification/model/WebHook.java similarity index 97% rename from gamification-github-services/src/main/java/io/meeds/gamification/github/model/WebHook.java rename to gamification-github-services/src/main/java/io/meeds/github/gamification/model/WebHook.java index 929a71ec9..6cbfd045c 100644 --- a/gamification-github-services/src/main/java/io/meeds/gamification/github/model/WebHook.java +++ b/gamification-github-services/src/main/java/io/meeds/github/gamification/model/WebHook.java @@ -16,7 +16,7 @@ * 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.github.model; +package io.meeds.github.gamification.model; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/gamification-github-services/src/main/java/io/meeds/gamification/github/plugin/CommentPullRequestTriggerPlugin.java b/gamification-github-services/src/main/java/io/meeds/github/gamification/plugin/CommentPullRequestTriggerPlugin.java similarity index 70% rename from gamification-github-services/src/main/java/io/meeds/gamification/github/plugin/CommentPullRequestTriggerPlugin.java rename to gamification-github-services/src/main/java/io/meeds/github/gamification/plugin/CommentPullRequestTriggerPlugin.java index c3259600a..04494a37a 100644 --- a/gamification-github-services/src/main/java/io/meeds/gamification/github/plugin/CommentPullRequestTriggerPlugin.java +++ b/gamification-github-services/src/main/java/io/meeds/github/gamification/plugin/CommentPullRequestTriggerPlugin.java @@ -15,15 +15,36 @@ * 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.github.plugin; +package io.meeds.github.gamification.plugin; -import io.meeds.gamification.github.model.Event; -import static io.meeds.gamification.github.utils.Utils.*; +import io.meeds.github.gamification.model.Event; +import io.meeds.github.gamification.services.GithubTriggerService; +import jakarta.annotation.PostConstruct; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import static io.meeds.github.gamification.utils.Utils.*; import java.util.*; +@Component public class CommentPullRequestTriggerPlugin extends GithubTriggerPlugin { + private static final String NAME = "pull_request_review_comment"; + + @Autowired + private GithubTriggerService githubTriggerService; + + @PostConstruct + public void init() { + githubTriggerService.addPlugin(this); + } + + @Override + public String getName() { + return NAME; + } + @Override public List getEvents(Map payload) { return Collections.singletonList(new Event(PULL_REQUEST_REVIEW_COMMENT_EVENT_NAME, diff --git a/gamification-github-services/src/main/java/io/meeds/gamification/github/plugin/CommentTriggerPlugin.java b/gamification-github-services/src/main/java/io/meeds/github/gamification/plugin/CommentTriggerPlugin.java similarity index 78% rename from gamification-github-services/src/main/java/io/meeds/gamification/github/plugin/CommentTriggerPlugin.java rename to gamification-github-services/src/main/java/io/meeds/github/gamification/plugin/CommentTriggerPlugin.java index 2b1a6cdbe..9d58c248e 100644 --- a/gamification-github-services/src/main/java/io/meeds/gamification/github/plugin/CommentTriggerPlugin.java +++ b/gamification-github-services/src/main/java/io/meeds/github/gamification/plugin/CommentTriggerPlugin.java @@ -15,18 +15,39 @@ * 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.github.plugin; +package io.meeds.github.gamification.plugin; -import io.meeds.gamification.github.model.Event; -import static io.meeds.gamification.github.utils.Utils.*; +import io.meeds.github.gamification.model.Event; +import static io.meeds.github.gamification.utils.Utils.*; + +import io.meeds.github.gamification.services.GithubTriggerService; +import jakarta.annotation.PostConstruct; import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; import java.util.Collections; import java.util.List; import java.util.Map; +@Component public class CommentTriggerPlugin extends GithubTriggerPlugin { + private static final String NAME = "issue_comment"; + + @Autowired + private GithubTriggerService githubTriggerService; + + @PostConstruct + public void init() { + githubTriggerService.addPlugin(this); + } + + @Override + public String getName() { + return NAME; + } + @Override public List getEvents(Map payload) { diff --git a/gamification-github-services/src/main/java/io/meeds/gamification/github/plugin/GithubConnectorPlugin.java b/gamification-github-services/src/main/java/io/meeds/github/gamification/plugin/GithubConnectorPlugin.java similarity index 82% rename from gamification-github-services/src/main/java/io/meeds/gamification/github/plugin/GithubConnectorPlugin.java rename to gamification-github-services/src/main/java/io/meeds/github/gamification/plugin/GithubConnectorPlugin.java index 3a8f0ced9..486d33bdb 100644 --- a/gamification-github-services/src/main/java/io/meeds/gamification/github/plugin/GithubConnectorPlugin.java +++ b/gamification-github-services/src/main/java/io/meeds/github/gamification/plugin/GithubConnectorPlugin.java @@ -16,21 +16,25 @@ * 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.github.plugin; +package io.meeds.github.gamification.plugin; import com.github.scribejava.apis.GitHubApi; import com.github.scribejava.core.builder.ServiceBuilder; import com.github.scribejava.core.model.OAuth2AccessToken; import com.github.scribejava.core.oauth.OAuth20Service; -import io.meeds.gamification.github.model.GithubAccessTokenContext; +import io.meeds.gamification.service.ConnectorService; +import io.meeds.github.gamification.model.GithubAccessTokenContext; import io.meeds.gamification.model.RemoteConnectorSettings; import io.meeds.gamification.plugin.ConnectorPlugin; import io.meeds.gamification.service.ConnectorSettingService; import io.meeds.oauth.exception.OAuthException; import io.meeds.oauth.exception.OAuthExceptionCode; +import jakarta.annotation.PostConstruct; import org.apache.commons.lang3.StringUtils; import org.exoplatform.services.log.ExoLogger; import org.exoplatform.services.log.Log; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; import java.io.BufferedReader; import java.io.IOException; @@ -39,24 +43,32 @@ import java.net.URL; import java.util.concurrent.ExecutionException; +@Component public class GithubConnectorPlugin extends ConnectorPlugin { - private static final Log LOG = ExoLogger.getLogger(GithubConnectorPlugin.class); + private static final Log LOG = ExoLogger.getLogger(GithubConnectorPlugin.class); - private static final String CONNECTOR_NAME = "github"; + private static final String CONNECTOR_NAME = "github"; - private static final String CONNECTOR_SCOPE = "read:user"; + private static final String CONNECTOR_SCOPE = "read:user"; - private static final String CONNECTOR_REST_API = "https://api.github.com/user"; + private static final String CONNECTOR_REST_API = "https://api.github.com/user"; - private final ConnectorSettingService connectorSettingService; + private static final String NAME = "github"; - private OAuth20Service oAuthService; + private OAuth20Service oAuthService; - private long remoteConnectorId; + private long remoteConnectorId; - public GithubConnectorPlugin(ConnectorSettingService connectorSettingService) { - this.connectorSettingService = connectorSettingService; + @Autowired + private ConnectorSettingService connectorSettingService; + + @Autowired + private ConnectorService connectorService; + + @PostConstruct + public void initData() { + connectorService.addPlugin(this); } @Override @@ -91,6 +103,11 @@ public String getConnectorName() { return CONNECTOR_NAME; } + @Override + public String getName() { + return NAME; + } + private static String fetchUsernameFromAccessToken(GithubAccessTokenContext accessToken) throws IOException { URL url = new URL(CONNECTOR_REST_API); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); diff --git a/gamification-github-services/src/main/java/io/meeds/gamification/github/plugin/GithubEventPlugin.java b/gamification-github-services/src/main/java/io/meeds/github/gamification/plugin/GithubEventPlugin.java similarity index 87% rename from gamification-github-services/src/main/java/io/meeds/gamification/github/plugin/GithubEventPlugin.java rename to gamification-github-services/src/main/java/io/meeds/github/gamification/plugin/GithubEventPlugin.java index c44efcf9d..d81beb623 100644 --- a/gamification-github-services/src/main/java/io/meeds/gamification/github/plugin/GithubEventPlugin.java +++ b/gamification-github-services/src/main/java/io/meeds/github/gamification/plugin/GithubEventPlugin.java @@ -16,19 +16,32 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ -package io.meeds.gamification.github.plugin; +package io.meeds.github.gamification.plugin; import io.meeds.gamification.plugin.EventPlugin; +import io.meeds.gamification.service.EventService; +import jakarta.annotation.PostConstruct; import org.apache.commons.collections.CollectionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; import java.util.*; -import static io.meeds.gamification.github.utils.Utils.*; +import static io.meeds.github.gamification.utils.Utils.*; +@Component public class GithubEventPlugin extends EventPlugin { public static final String EVENT_TYPE = "github"; + @Autowired + private EventService eventService; + + @PostConstruct + public void init() { + eventService.addPlugin(this); + } + @Override public String getEventType() { return EVENT_TYPE; diff --git a/gamification-github-services/src/main/java/io/meeds/gamification/github/plugin/GithubTriggerPlugin.java b/gamification-github-services/src/main/java/io/meeds/github/gamification/plugin/GithubTriggerPlugin.java similarity index 86% rename from gamification-github-services/src/main/java/io/meeds/gamification/github/plugin/GithubTriggerPlugin.java rename to gamification-github-services/src/main/java/io/meeds/github/gamification/plugin/GithubTriggerPlugin.java index 644b38c8b..d1c282171 100644 --- a/gamification-github-services/src/main/java/io/meeds/gamification/github/plugin/GithubTriggerPlugin.java +++ b/gamification-github-services/src/main/java/io/meeds/github/gamification/plugin/GithubTriggerPlugin.java @@ -15,11 +15,12 @@ * 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.github.plugin; +package io.meeds.github.gamification.plugin; -import io.meeds.gamification.github.model.Event; -import io.meeds.gamification.github.services.WebhookService; +import io.meeds.github.gamification.model.Event; +import io.meeds.github.gamification.services.WebhookService; import org.exoplatform.container.component.BaseComponentPlugin; +import org.springframework.stereotype.Component; import java.util.List; import java.util.Map; @@ -28,6 +29,7 @@ * A plugin that will be used by {@link WebhookService} to handle github * triggers */ +@Component public abstract class GithubTriggerPlugin extends BaseComponentPlugin { /** diff --git a/gamification-github-services/src/main/java/io/meeds/github/gamification/plugin/IssueTriggerPlugin.java b/gamification-github-services/src/main/java/io/meeds/github/gamification/plugin/IssueTriggerPlugin.java new file mode 100644 index 000000000..944775c44 --- /dev/null +++ b/gamification-github-services/src/main/java/io/meeds/github/gamification/plugin/IssueTriggerPlugin.java @@ -0,0 +1,95 @@ +/* + * This file is part of the Meeds project (https://meeds.io/). + * + * Copyright (C) 2020 - 2023 Meeds Lab contact@meedslab.com + * + * 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.github.gamification.plugin; + +import io.meeds.github.gamification.model.Event; +import io.meeds.github.gamification.services.GithubTriggerService; +import io.meeds.github.gamification.utils.Utils; +import jakarta.annotation.PostConstruct; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +@Component +public class IssueTriggerPlugin extends GithubTriggerPlugin { + + private static final String NAME = "issues"; + + @Autowired + private GithubTriggerService githubTriggerService; + + @PostConstruct + public void init() { + githubTriggerService.addPlugin(this); + } + + @Override + public String getName() { + return NAME; + } + + @Override + public List getEvents(Map payload) { + String issueState = Utils.extractSubItem(payload, Utils.ACTION); + String objectId = Utils.extractSubItem(payload, Utils.ISSUE, Utils.HTML_URL); + String userId = Utils.extractSubItem(payload, Utils.SENDER, Utils.LOGIN); + if (Objects.equals(issueState, Utils.OPENED)) { + return Collections.singletonList(new Event(Utils.CREATE_ISSUE_EVENT_NAME, + userId, + userId, + objectId, + Utils.ISSUE_TYPE, + Utils.extractSubItem(payload, "organization", "id"), + Utils.extractSubItem(payload, "repository", "id"))); + } else if (Objects.equals(issueState, Utils.CLOSED)) { + if (Objects.equals(Utils.extractSubItem(payload, Utils.ISSUE, Utils.STATE_REASON), Utils.NOT_PLANNED)) { + return Collections.singletonList(new Event(Utils.CLOSE_ISSUE_EVENT_NAME, + userId, + userId, + objectId, + Utils.ISSUE_TYPE, + Utils.extractSubItem(payload, "organization", "id"), + Utils.extractSubItem(payload, "repository", "id"))); + } + return Collections.emptyList(); + } else if (Objects.equals(issueState, Utils.LABELED)) { + objectId = objectId + "?label=" + Utils.extractSubItem(payload, Utils.LABEL, Utils.NAME); + return Collections.singletonList(new Event(Utils.ADD_ISSUE_LABEL_EVENT_NAME, + userId, + userId, + objectId, + Utils.ISSUE_TYPE, + Utils.extractSubItem(payload, Utils.ORGANIZATION, Utils.ID), + Utils.extractSubItem(payload, Utils.REPOSITORY, Utils.ID))); + } else if (Objects.equals(issueState, Utils.UNLABELED)) { + objectId = objectId + "?label=" + Utils.extractSubItem(payload, Utils.LABEL, Utils.NAME); + return Collections.singletonList(new Event(Utils.DELETE_ISSUE_LABEL_EVENT_NAME, + userId, + userId, + objectId, + Utils.ISSUE_TYPE, + Utils.extractSubItem(payload, Utils.ORGANIZATION, Utils.ID), + Utils.extractSubItem(payload, Utils.REPOSITORY, Utils.ID))); + } + return Collections.emptyList(); + } +} diff --git a/gamification-github-services/src/main/java/io/meeds/github/gamification/plugin/PullRequestReviewTriggerPlugin.java b/gamification-github-services/src/main/java/io/meeds/github/gamification/plugin/PullRequestReviewTriggerPlugin.java new file mode 100644 index 000000000..9a56741da --- /dev/null +++ b/gamification-github-services/src/main/java/io/meeds/github/gamification/plugin/PullRequestReviewTriggerPlugin.java @@ -0,0 +1,79 @@ +/* + * This file is part of the Meeds project (https://meeds.io/). + * + * Copyright (C) 2020 - 2023 Meeds Lab contact@meedslab.com + * + * 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.github.gamification.plugin; + +import io.meeds.github.gamification.model.Event; +import io.meeds.github.gamification.services.GithubTriggerService; +import io.meeds.github.gamification.utils.Utils; +import jakarta.annotation.PostConstruct; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +@Component +public class PullRequestReviewTriggerPlugin extends GithubTriggerPlugin { + + private static final String NAME = "pull_request_review"; + + @Autowired + private GithubTriggerService githubTriggerService; + + @PostConstruct + public void init() { + githubTriggerService.addPlugin(this); + } + + @Override + public String getName() { + return NAME; + } + + @Override + public List getEvents(Map payload) { + String pullState = Utils.extractSubItem(payload, Utils.PULL_REQUEST_REVIEW, Utils.STATE); + if (pullState != null && pullState.equals(Utils.PULL_REQUEST_COMMENTED)) { + return Collections.singletonList(new Event(Utils.REVIEW_PULL_REQUEST_EVENT_NAME, + Utils.extractSubItem(payload, Utils.PULL_REQUEST_REVIEW, Utils.USER, Utils.LOGIN), + Utils.extractSubItem(payload, Utils.PULL_REQUEST_REVIEW, Utils.USER, Utils.LOGIN), + Utils.extractSubItem(payload, Utils.PULL_REQUEST_REVIEW, Utils.HTML_URL), + Utils.PR_TYPE, + Utils.extractSubItem(payload, Utils.ORGANIZATION, Utils.ID), + Utils.extractSubItem(payload, Utils.REPOSITORY, Utils.ID))); + } else if (pullState != null && pullState.equals(Utils.PULL_REQUEST_VALIDATED)) { + return Arrays.asList(new Event(Utils.PULL_REQUEST_VALIDATED_EVENT_NAME, + Utils.extractSubItem(payload, Utils.PULL_REQUEST, Utils.USER, Utils.LOGIN), + Utils.extractSubItem(payload, Utils.PULL_REQUEST, Utils.USER, Utils.LOGIN), + Utils.extractSubItem(payload, Utils.PULL_REQUEST_REVIEW, Utils.HTML_URL), + Utils.PR_TYPE, + Utils.extractSubItem(payload, Utils.ORGANIZATION, Utils.ID), + Utils.extractSubItem(payload, Utils.REPOSITORY, Utils.ID)), + new Event(Utils.VALIDATE_PULL_REQUEST_EVENT_NAME, + Utils.extractSubItem(payload, Utils.PULL_REQUEST_REVIEW, Utils.USER, Utils.LOGIN), + Utils.extractSubItem(payload, Utils.PULL_REQUEST_REVIEW, Utils.USER, Utils.LOGIN), + Utils.extractSubItem(payload, Utils.PULL_REQUEST_REVIEW, Utils.HTML_URL), + Utils.PR_TYPE, + Utils.extractSubItem(payload, Utils.ORGANIZATION, Utils.ID), + Utils.extractSubItem(payload, Utils.REPOSITORY, Utils.ID))); + } + return Collections.emptyList(); + } +} diff --git a/gamification-github-services/src/main/java/io/meeds/gamification/github/plugin/PullRequestTriggerPlugin.java b/gamification-github-services/src/main/java/io/meeds/github/gamification/plugin/PullRequestTriggerPlugin.java similarity index 85% rename from gamification-github-services/src/main/java/io/meeds/gamification/github/plugin/PullRequestTriggerPlugin.java rename to gamification-github-services/src/main/java/io/meeds/github/gamification/plugin/PullRequestTriggerPlugin.java index c80c9de54..7c9b31096 100644 --- a/gamification-github-services/src/main/java/io/meeds/gamification/github/plugin/PullRequestTriggerPlugin.java +++ b/gamification-github-services/src/main/java/io/meeds/github/gamification/plugin/PullRequestTriggerPlugin.java @@ -15,15 +15,36 @@ * 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.github.plugin; +package io.meeds.github.gamification.plugin; -import io.meeds.gamification.github.model.Event; -import static io.meeds.gamification.github.utils.Utils.*; +import io.meeds.github.gamification.model.Event; +import io.meeds.github.gamification.services.GithubTriggerService; +import jakarta.annotation.PostConstruct; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import static io.meeds.github.gamification.utils.Utils.*; import java.util.*; +@Component public class PullRequestTriggerPlugin extends GithubTriggerPlugin { + private static final String NAME = "pull_request"; + + @Autowired + private GithubTriggerService githubTriggerService; + + @PostConstruct + public void init() { + githubTriggerService.addPlugin(this); + } + + @Override + public String getName() { + return NAME; + } + @Override public List getEvents(Map payload) { String userId = extractSubItem(payload, SENDER, LOGIN); diff --git a/gamification-github-services/src/main/java/io/meeds/gamification/github/plugin/PushCodeTriggerPlugin.java b/gamification-github-services/src/main/java/io/meeds/github/gamification/plugin/PushCodeTriggerPlugin.java similarity index 68% rename from gamification-github-services/src/main/java/io/meeds/gamification/github/plugin/PushCodeTriggerPlugin.java rename to gamification-github-services/src/main/java/io/meeds/github/gamification/plugin/PushCodeTriggerPlugin.java index 25c656a41..006cc2230 100644 --- a/gamification-github-services/src/main/java/io/meeds/gamification/github/plugin/PushCodeTriggerPlugin.java +++ b/gamification-github-services/src/main/java/io/meeds/github/gamification/plugin/PushCodeTriggerPlugin.java @@ -15,21 +15,42 @@ * 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.github.plugin; +package io.meeds.github.gamification.plugin; -import io.meeds.gamification.github.model.Event; +import io.meeds.github.gamification.model.Event; +import io.meeds.github.gamification.services.GithubTriggerService; +import io.meeds.github.gamification.utils.Utils; +import jakarta.annotation.PostConstruct; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; import java.util.*; -import static io.meeds.gamification.github.utils.Utils.*; +import static io.meeds.github.gamification.utils.Utils.*; +@Component public class PushCodeTriggerPlugin extends GithubTriggerPlugin { + private static final String NAME = "push"; + + @Autowired + private GithubTriggerService githubTriggerService; + + @PostConstruct + public void init() { + githubTriggerService.addPlugin(this); + } + + @Override + public String getName() { + return NAME; + } + @Override public List getEvents(Map payload) { return Collections.singletonList(new Event(PUSH_CODE_EVENT_NAME, null, - extractSubItem(payload, PUSHER, NAME), + extractSubItem(payload, PUSHER, Utils.NAME), extractSubItem(payload, HEAD_COMMIT, URL), null, extractSubItem(payload, ORGANIZATION, ID), diff --git a/gamification-github-services/src/main/java/io/meeds/gamification/github/rest/GithubWebHookRest.java b/gamification-github-services/src/main/java/io/meeds/github/gamification/rest/GithubWebHookRest.java similarity index 61% rename from gamification-github-services/src/main/java/io/meeds/gamification/github/rest/GithubWebHookRest.java rename to gamification-github-services/src/main/java/io/meeds/github/gamification/rest/GithubWebHookRest.java index 5383cc3e6..54130d64e 100644 --- a/gamification-github-services/src/main/java/io/meeds/gamification/github/rest/GithubWebHookRest.java +++ b/gamification-github-services/src/main/java/io/meeds/github/gamification/rest/GithubWebHookRest.java @@ -15,31 +15,29 @@ * 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.github.rest; +package io.meeds.github.gamification.rest; import javax.ws.rs.*; -import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import io.meeds.gamification.github.services.GithubTriggerService; -import org.exoplatform.services.rest.resource.ResourceContainer; +import io.meeds.github.gamification.services.GithubTriggerService; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; -@Path("/gamification/connectors/github/") -public class GithubWebHookRest implements ResourceContainer { +@RestController +@RequestMapping("webhooks") +@Tag(name = "webhooks", description = "Manage triggered github webhook events") // NOSONAR +public class GithubWebHookRest { - private final GithubTriggerService githubTriggerService; + @Autowired + private GithubTriggerService githubTriggerService; - public GithubWebHookRest(GithubTriggerService githubTriggerService) { - this.githubTriggerService = githubTriggerService; - } - - @POST - @Consumes(MediaType.APPLICATION_JSON) - @Path("webhooks") + @PostMapping public Response githubEvent(// NOSONAR - @HeaderParam("x-github-event") String event, - @HeaderParam("x-hub-signature") String signature, - String payload) { + @RequestHeader("x-github-event") String event, + @RequestHeader("x-hub-signature") String signature, + @RequestBody String payload) { try { githubTriggerService.handleTriggerAsync(event, signature, payload); diff --git a/gamification-github-services/src/main/java/io/meeds/github/gamification/rest/HooksManagementRest.java b/gamification-github-services/src/main/java/io/meeds/github/gamification/rest/HooksManagementRest.java new file mode 100644 index 000000000..d1733d469 --- /dev/null +++ b/gamification-github-services/src/main/java/io/meeds/github/gamification/rest/HooksManagementRest.java @@ -0,0 +1,263 @@ +/* + * This file is part of the Meeds project (https://meeds.io/). + * + * Copyright (C) 2020 - 2022 Meeds Lab contact@meedslab.com + * + * 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.github.gamification.rest; + +import io.meeds.github.gamification.model.RemoteRepository; +import io.meeds.github.gamification.model.WebHook; +import io.meeds.github.gamification.rest.builder.WebHookBuilder; +import io.meeds.github.gamification.services.GithubConsumerService; +import io.meeds.github.gamification.services.WebhookService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletRequest; +import org.apache.commons.lang3.StringUtils; + +import org.exoplatform.commons.ObjectAlreadyExistsException; +import org.exoplatform.commons.exception.ObjectNotFoundException; +import io.meeds.github.gamification.rest.model.RepositoryList; +import io.meeds.github.gamification.rest.model.WebHookRestEntity; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.web.PagedResourcesAssembler; +import org.springframework.hateoas.EntityModel; +import org.springframework.hateoas.PagedModel; +import org.springframework.http.HttpStatus; +import org.springframework.security.access.annotation.Secured; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.server.ResponseStatusException; + +import java.util.List; + +@RestController +@RequestMapping("hooks") +@Tag(name = "accounts", description = "Manage and access twitter watched accounts") // NOSONAR +public class HooksManagementRest { + + public static final String GITHUB_HOOK_NOT_FOUND = "The GitHub hook doesn't exit"; + + @Autowired + private WebhookService webhookService; + + @Autowired + private GithubConsumerService githubConsumerService; + + @GetMapping + @Secured("users") + @Operation(summary = "Retrieves the list GitHub webHooks", method = "GET") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Request fulfilled"), + @ApiResponse(responseCode = "401", description = "Unauthorized operation"), }) + public PagedModel> getWebHooks(HttpServletRequest request, + Pageable pageable, + PagedResourcesAssembler assembler) { + + try { + Page webHookRestEntities = getWebHookRestEntities(request.getRemoteUser(), pageable); + return assembler.toModel(webHookRestEntities); + } catch (IllegalAccessException e) { + throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, e.getMessage()); + } + } + + @GetMapping(path = "{webHookId}") + @Secured("users") + @Operation(summary = "Retrieves a webHook by its technical identifier", method = "GET") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Request fulfilled"), + @ApiResponse(responseCode = "401", description = "Unauthorized operation"), + @ApiResponse(responseCode = "400", description = "Invalid query input"), + @ApiResponse(responseCode = "404", description = "Not found"), + @ApiResponse(responseCode = "500", description = "Internal server error"), }) + public WebHookRestEntity getWebHookById(HttpServletRequest request, + @Parameter(description = "WebHook technical identifier", required = true) + @PathVariable("webHookId") + long webHookId) { + if (webHookId == 0) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "WebHook Id must be not null"); + } + try { + WebHook webHook = webhookService.getWebhookId(webHookId, request.getRemoteUser()); + return WebHookBuilder.toRestEntity(webhookService, githubConsumerService, webHook); + } catch (IllegalArgumentException e) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, e.getMessage()); + } catch (IllegalAccessException e) { + throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, e.getMessage()); + } catch (ObjectNotFoundException e) { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, e.getMessage()); + } + } + + @PostMapping + @Secured("users") + @Operation(summary = "Create a organization webhook for Remote GitHub connector.", description = "Create a organization webhook for Remote GitHub connector.", method = "POST") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Request fulfilled"), + @ApiResponse(responseCode = "400", description = "Invalid query input"), + @ApiResponse(responseCode = "401", description = "Unauthorized operation"), + @ApiResponse(responseCode = "500", description = "Internal server error") }) + public void createWebhookHook(HttpServletRequest request, + @Parameter(description = "GitHub organization name", required = true) @RequestParam("organizationName") String organizationName, + @Parameter(description = "GitHub personal access token", required = true) + @RequestParam("accessToken") + String accessToken) { + + if (StringUtils.isBlank(organizationName)) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "'organizationName' parameter is mandatory"); + } + if (StringUtils.isBlank(accessToken)) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "'accessToken' parameter is mandatory"); + } + try { + webhookService.createWebhook(organizationName, accessToken, request.getRemoteUser()); + } catch (IllegalAccessException e) { + throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, e.getMessage()); + } catch (ObjectAlreadyExistsException e) { + throw new ResponseStatusException(HttpStatus.CONFLICT, e.getMessage()); + } catch (ObjectNotFoundException e) { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, e.getMessage()); + } + } + + @PatchMapping(path = "{webHookId}") + @Secured("users") + @Operation(summary = "Update a organization webhook personal access token.", description = "Update a organization webhook personal access token.", method = "PATCH") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Request fulfilled"), + @ApiResponse(responseCode = "400", description = "Invalid query input"), + @ApiResponse(responseCode = "401", description = "Unauthorized operation"), + @ApiResponse(responseCode = "500", description = "Internal server error") }) + public void updateWebHookAccessToken(HttpServletRequest request, + @Parameter(description = "WebHook technical identifier", required = true) + @PathVariable("webHookId") + long webHookId, + @Parameter(description = "GitHub personal access token", required = true) + @RequestParam("accessToken") + String accessToken) { + + if (webHookId <= 0) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "'webHookId' must be positive"); + } + if (StringUtils.isBlank(accessToken)) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "'accessToken' parameter is mandatory"); + } + try { + webhookService.updateWebHookAccessToken(webHookId, accessToken, request.getRemoteUser()); + } catch (IllegalAccessException e) { + throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, e.getMessage()); + } catch (ObjectNotFoundException e) { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, GITHUB_HOOK_NOT_FOUND); + } + } + + @DeleteMapping(path = "{organizationId}") + @Secured("users") + @Operation(summary = "Deletes gitHub organization webhook", description = "Deletes gitHub organization webhook", method = "DELETE") + @ApiResponses(value = { + @ApiResponse(responseCode = "204", description = "Request fulfilled"), + @ApiResponse(responseCode = "400", description = "Bad request"), + @ApiResponse(responseCode = "401", description = "Unauthorized operation"), + @ApiResponse(responseCode = "500", description = "Internal server error"), }) + public void deleteWebhook(HttpServletRequest request, + @Parameter(description = "GitHub organization id", required = true) + @PathVariable("organizationId") + long organizationId) { + + try { + webhookService.deleteWebhook(organizationId, request.getRemoteUser()); + } catch (IllegalAccessException e) { + throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, e.getMessage()); + } catch (ObjectNotFoundException e) { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, e.getMessage()); + } + } + + @GetMapping(path = "{organizationId}/repos") + @Secured("users") + @Operation(summary = "Retrieves the list GitHub organization repositories", method = "GET") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Request fulfilled"), + @ApiResponse(responseCode = "401", description = "Unauthorized operation"), }) + public RepositoryList getWebHookRepos(HttpServletRequest request, + @Parameter(description = "GitHub organization id", required = true) + @PathVariable("organizationId") + long organizationId, + @Parameter(description = "Query page number", required = true) + @RequestParam("page") + int page, + @Parameter(description = "Query item per page", required = true) + @RequestParam("perPage") + int perPage, + @Parameter(description = "Keyword to search in repositories title", required = true) + @RequestParam("keyword") + String keyword) { + + List remoteRepositories; + try { + RepositoryList repositoryList = new RepositoryList(); + remoteRepositories = webhookService.retrieveOrganizationRepos(organizationId, + request.getRemoteUser(), + page, + perPage, + keyword); + repositoryList.setRemoteRepositories(remoteRepositories); + repositoryList.setPage(page); + repositoryList.setPerPage(perPage); + return repositoryList; + } catch (IllegalAccessException e) { + throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, e.getMessage()); + } catch (ObjectNotFoundException e) { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, GITHUB_HOOK_NOT_FOUND); + } + } + + @PostMapping(path = "repo/status") + @Secured("users") + @Operation(summary = "enables/disables webhook repository.", description = "enables/disables webhook repository", method = "POST") + @ApiResponses(value = { + @ApiResponse(responseCode = "204", description = "Request fulfilled"), + @ApiResponse(responseCode = "400", description = "Bad request"), + @ApiResponse(responseCode = "401", description = "Unauthorized operation"), + @ApiResponse(responseCode = "500", description = "Internal server error"), }) + public void updateWebHookRepoStatus(HttpServletRequest request, + @Parameter(description = "GitHub organization remote Id", required = true) + @RequestParam("organizationId") + long organizationId, + @Parameter(description = "Organization repository remote Id", required = true) + @RequestParam("repositoryId") + long repositoryId, + @Parameter(description = "Organization repository status enabled/disabled. possible values: true for enabled, else false", required = true) + @RequestParam("enabled") + boolean enabled) { + + try { + webhookService.setWebHookRepositoryEnabled(organizationId, repositoryId, enabled, request.getRemoteUser()); + } catch (IllegalAccessException e) { + throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, e.getMessage()); + } + } + + private Page getWebHookRestEntities(String username, Pageable pageable) throws IllegalAccessException { + Page webHooks = webhookService.getWebhooks(username, pageable); + return WebHookBuilder.toRestEntities(webhookService, githubConsumerService, webHooks); + } +} diff --git a/gamification-github-services/src/main/java/io/meeds/gamification/github/rest/builder/WebHookBuilder.java b/gamification-github-services/src/main/java/io/meeds/github/gamification/rest/builder/WebHookBuilder.java similarity index 79% rename from gamification-github-services/src/main/java/io/meeds/gamification/github/rest/builder/WebHookBuilder.java rename to gamification-github-services/src/main/java/io/meeds/github/gamification/rest/builder/WebHookBuilder.java index 13e3a51df..90532cebf 100644 --- a/gamification-github-services/src/main/java/io/meeds/gamification/github/rest/builder/WebHookBuilder.java +++ b/gamification-github-services/src/main/java/io/meeds/github/gamification/rest/builder/WebHookBuilder.java @@ -15,17 +15,15 @@ * 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.github.rest.builder; +package io.meeds.github.gamification.rest.builder; -import java.util.Collection; -import java.util.List; - -import io.meeds.gamification.github.model.RemoteOrganization; -import io.meeds.gamification.github.model.WebHook; -import io.meeds.gamification.github.model.TokenStatus; -import io.meeds.gamification.github.rest.model.WebHookRestEntity; -import io.meeds.gamification.github.services.GithubConsumerService; -import io.meeds.gamification.github.services.WebhookService; +import io.meeds.github.gamification.model.RemoteOrganization; +import io.meeds.github.gamification.model.WebHook; +import io.meeds.github.gamification.model.TokenStatus; +import io.meeds.github.gamification.rest.model.WebHookRestEntity; +import io.meeds.github.gamification.services.GithubConsumerService; +import io.meeds.github.gamification.services.WebhookService; +import org.springframework.data.domain.Page; public class WebHookBuilder { @@ -60,7 +58,7 @@ public static WebHookRestEntity toRestEntity(WebhookService webhookService, Gith tokenStatus); } - public static List toRestEntities(WebhookService webhookService, GithubConsumerService githubConsumerService, Collection webHooks) { - return webHooks.stream().map(webHook -> toRestEntity(webhookService, githubConsumerService, webHook)).toList(); + public static Page toRestEntities(WebhookService webhookService, GithubConsumerService githubConsumerService, Page webHooks) { + return webHooks.map(webHook -> toRestEntity(webhookService, githubConsumerService, webHook)); } } diff --git a/gamification-github-services/src/main/java/io/meeds/gamification/github/rest/model/RepositoryList.java b/gamification-github-services/src/main/java/io/meeds/github/gamification/rest/model/RepositoryList.java similarity index 91% rename from gamification-github-services/src/main/java/io/meeds/gamification/github/rest/model/RepositoryList.java rename to gamification-github-services/src/main/java/io/meeds/github/gamification/rest/model/RepositoryList.java index 8dba2ac29..f1336d35f 100644 --- a/gamification-github-services/src/main/java/io/meeds/gamification/github/rest/model/RepositoryList.java +++ b/gamification-github-services/src/main/java/io/meeds/github/gamification/rest/model/RepositoryList.java @@ -15,14 +15,14 @@ * 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.github.rest.model; +package io.meeds.github.gamification.rest.model; import java.util.List; +import io.meeds.github.gamification.model.RemoteRepository; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; -import io.meeds.gamification.github.model.RemoteRepository; @NoArgsConstructor @Getter diff --git a/gamification-github-services/src/main/java/io/meeds/gamification/github/rest/model/RepositoryRestEntity.java b/gamification-github-services/src/main/java/io/meeds/github/gamification/rest/model/RepositoryRestEntity.java similarity index 95% rename from gamification-github-services/src/main/java/io/meeds/gamification/github/rest/model/RepositoryRestEntity.java rename to gamification-github-services/src/main/java/io/meeds/github/gamification/rest/model/RepositoryRestEntity.java index 8177eff98..d5018fd71 100644 --- a/gamification-github-services/src/main/java/io/meeds/gamification/github/rest/model/RepositoryRestEntity.java +++ b/gamification-github-services/src/main/java/io/meeds/github/gamification/rest/model/RepositoryRestEntity.java @@ -15,7 +15,7 @@ * 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.github.rest.model; +package io.meeds.github.gamification.rest.model; import lombok.*; diff --git a/gamification-github-services/src/main/java/io/meeds/gamification/github/rest/model/WebHookList.java b/gamification-github-services/src/main/java/io/meeds/github/gamification/rest/model/WebHookList.java similarity index 96% rename from gamification-github-services/src/main/java/io/meeds/gamification/github/rest/model/WebHookList.java rename to gamification-github-services/src/main/java/io/meeds/github/gamification/rest/model/WebHookList.java index fee612c1e..000b112d4 100644 --- a/gamification-github-services/src/main/java/io/meeds/gamification/github/rest/model/WebHookList.java +++ b/gamification-github-services/src/main/java/io/meeds/github/gamification/rest/model/WebHookList.java @@ -17,7 +17,7 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package io.meeds.gamification.github.rest.model; +package io.meeds.github.gamification.rest.model; import java.util.List; diff --git a/gamification-github-services/src/main/java/io/meeds/gamification/github/rest/model/WebHookRestEntity.java b/gamification-github-services/src/main/java/io/meeds/github/gamification/rest/model/WebHookRestEntity.java similarity index 96% rename from gamification-github-services/src/main/java/io/meeds/gamification/github/rest/model/WebHookRestEntity.java rename to gamification-github-services/src/main/java/io/meeds/github/gamification/rest/model/WebHookRestEntity.java index d8b121a82..a1429233f 100644 --- a/gamification-github-services/src/main/java/io/meeds/gamification/github/rest/model/WebHookRestEntity.java +++ b/gamification-github-services/src/main/java/io/meeds/github/gamification/rest/model/WebHookRestEntity.java @@ -16,10 +16,10 @@ * 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.github.rest.model; +package io.meeds.github.gamification.rest.model; +import io.meeds.github.gamification.model.TokenStatus; import lombok.*; -import io.meeds.gamification.github.model.TokenStatus; import java.util.List; diff --git a/gamification-github-services/src/main/java/io/meeds/github/gamification/scheduling/SchedulingConfig.java b/gamification-github-services/src/main/java/io/meeds/github/gamification/scheduling/SchedulingConfig.java new file mode 100644 index 000000000..a24a73887 --- /dev/null +++ b/gamification-github-services/src/main/java/io/meeds/github/gamification/scheduling/SchedulingConfig.java @@ -0,0 +1,26 @@ +/* + * This file is part of the Meeds project (https://meeds.io/). + * + * Copyright (C) 2020 - 2023 Meeds Lab contact@meedslab.com + * + * 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.github.gamification.scheduling; + +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableScheduling; + +@Configuration +@EnableScheduling +public class SchedulingConfig { +} diff --git a/gamification-github-services/src/main/java/io/meeds/gamification/github/scheduled/GitHubWebHookForceUpdate.java b/gamification-github-services/src/main/java/io/meeds/github/gamification/scheduling/task/GitHubWebHookForceUpdateTask.java similarity index 58% rename from gamification-github-services/src/main/java/io/meeds/gamification/github/scheduled/GitHubWebHookForceUpdate.java rename to gamification-github-services/src/main/java/io/meeds/github/gamification/scheduling/task/GitHubWebHookForceUpdateTask.java index 48b9628ce..72d8470cc 100644 --- a/gamification-github-services/src/main/java/io/meeds/gamification/github/scheduled/GitHubWebHookForceUpdate.java +++ b/gamification-github-services/src/main/java/io/meeds/github/gamification/scheduling/task/GitHubWebHookForceUpdateTask.java @@ -15,32 +15,27 @@ * 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.github.scheduled; +package io.meeds.github.gamification.scheduling.task; -import io.meeds.gamification.github.services.WebhookService; -import org.quartz.DisallowConcurrentExecution; -import org.quartz.Job; -import org.quartz.JobExecutionContext; +import io.meeds.github.gamification.services.WebhookService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; import org.exoplatform.commons.api.persistence.ExoTransactional; -import org.exoplatform.container.ExoContainerContext; /** - * A service that will manage the periodic updating of github webhooks, ensuring - * that webhooks data remains current with external sources. + * A service that will manage the periodic updating of twitter events. */ -@DisallowConcurrentExecution -public class GitHubWebHookForceUpdate implements Job { +@Component +public class GitHubWebHookForceUpdateTask { - private final WebhookService webhookService; + @Autowired + private WebhookService webhookService; - public GitHubWebHookForceUpdate() { - this.webhookService = ExoContainerContext.getService(WebhookService.class); - } - - @Override @ExoTransactional - public void execute(JobExecutionContext context) { + @Scheduled(cron = "${io.meeds.gamification.GitHubWebHookForceUpdate.expression:0 0 * * * *}") + public void execute() { webhookService.forceUpdateWebhooks(); } } diff --git a/gamification-github-services/src/main/java/io/meeds/gamification/github/services/GithubConsumerService.java b/gamification-github-services/src/main/java/io/meeds/github/gamification/services/GithubConsumerService.java similarity index 89% rename from gamification-github-services/src/main/java/io/meeds/gamification/github/services/GithubConsumerService.java rename to gamification-github-services/src/main/java/io/meeds/github/gamification/services/GithubConsumerService.java index 6b0fa816b..c25dfc29e 100644 --- a/gamification-github-services/src/main/java/io/meeds/gamification/github/services/GithubConsumerService.java +++ b/gamification-github-services/src/main/java/io/meeds/github/gamification/services/GithubConsumerService.java @@ -15,16 +15,18 @@ * 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.github.services; +package io.meeds.github.gamification.services; -import io.meeds.gamification.github.model.RemoteOrganization; -import io.meeds.gamification.github.model.WebHook; +import io.meeds.github.gamification.model.RemoteOrganization; +import io.meeds.github.gamification.model.WebHook; +import org.cometd.annotation.Service; import org.exoplatform.commons.exception.ObjectNotFoundException; -import io.meeds.gamification.github.model.RemoteRepository; -import io.meeds.gamification.github.model.TokenStatus; +import io.meeds.github.gamification.model.RemoteRepository; +import io.meeds.github.gamification.model.TokenStatus; import java.util.List; +@Service public interface GithubConsumerService { /** @@ -90,9 +92,4 @@ public interface GithubConsumerService { * @return {@link TokenStatus} */ TokenStatus checkGitHubTokenStatus(String accessToken); - - /** - * clear remote webhook entities cache - */ - void clearCache(); } diff --git a/gamification-github-services/src/main/java/io/meeds/gamification/github/services/GithubTriggerService.java b/gamification-github-services/src/main/java/io/meeds/github/gamification/services/GithubTriggerService.java similarity index 92% rename from gamification-github-services/src/main/java/io/meeds/gamification/github/services/GithubTriggerService.java rename to gamification-github-services/src/main/java/io/meeds/github/gamification/services/GithubTriggerService.java index db97e643b..5254d4899 100644 --- a/gamification-github-services/src/main/java/io/meeds/gamification/github/services/GithubTriggerService.java +++ b/gamification-github-services/src/main/java/io/meeds/github/gamification/services/GithubTriggerService.java @@ -15,10 +15,12 @@ * 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.github.services; +package io.meeds.github.gamification.services; -import io.meeds.gamification.github.plugin.GithubTriggerPlugin; +import io.meeds.github.gamification.plugin.GithubTriggerPlugin; +import org.cometd.annotation.Service; +@Service public interface GithubTriggerService { /** diff --git a/gamification-github-services/src/main/java/io/meeds/gamification/github/services/WebhookService.java b/gamification-github-services/src/main/java/io/meeds/github/gamification/services/WebhookService.java similarity index 80% rename from gamification-github-services/src/main/java/io/meeds/gamification/github/services/WebhookService.java rename to gamification-github-services/src/main/java/io/meeds/github/gamification/services/WebhookService.java index 130393be1..8f78e4b49 100644 --- a/gamification-github-services/src/main/java/io/meeds/gamification/github/services/WebhookService.java +++ b/gamification-github-services/src/main/java/io/meeds/github/gamification/services/WebhookService.java @@ -16,29 +16,31 @@ * 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.github.services; +package io.meeds.github.gamification.services; -import io.meeds.gamification.github.model.WebHook; +import io.meeds.github.gamification.model.WebHook; +import org.cometd.annotation.Service; import org.exoplatform.commons.ObjectAlreadyExistsException; import org.exoplatform.commons.exception.ObjectNotFoundException; -import io.meeds.gamification.github.model.RemoteRepository; +import io.meeds.github.gamification.model.RemoteRepository; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import java.util.List; +@Service public interface WebhookService { /** * Get available github hooks using offset and limit. * * @param currentUser user name attempting to access connector hooks - * @param offset Offset of result - * @param limit Limit of result - * @param forceUpdate force Load remote webhook or not. - * @return {@link List} of {@link WebHook} + * @param pageable {@link Pageable} the page to be returned. + * @return {@link Pageable} of {@link WebHook} * @throws IllegalAccessException when user is not authorized to access github * hooks */ - List getWebhooks(String currentUser, int offset, int limit, boolean forceUpdate) throws IllegalAccessException; + Page getWebhooks(String currentUser, Pageable pageable) throws IllegalAccessException; /** * Retrieves a webHook identified by its technical identifier. @@ -59,27 +61,6 @@ public interface WebhookService { */ WebHook getWebhookId(long webhookId, String username) throws IllegalAccessException, ObjectNotFoundException; - /** - * Get available github hooks using offset and limit. - * - * @param offset Offset of result - * @param limit Limit of result - * @param forceUpdate force Load remote webhooks or not. - * @return {@link List} of {@link WebHook} - */ - List getWebhooks(int offset, int limit, boolean forceUpdate); - - /** - * Count all gitHub webhooks - * - * @param currentUser User name accessing webhooks - * @param forceUpdate force Load remote webhooks count or not. - * @return webhooks count - * @throws IllegalAccessException when user is not authorized to get github - * webhooks - */ - int countWebhooks(String currentUser, boolean forceUpdate) throws IllegalAccessException; - /** * create github organization hook. * @@ -117,12 +98,6 @@ void updateWebHookAccessToken(long webHookId, String accessToken, String current */ void deleteWebhook(long organizationId, String currentUser) throws IllegalAccessException, ObjectNotFoundException; - /** - * Force update the stored github organization webhooks if there is a change to - * the remote webhooks, such as an entity deletion or the update event - **/ - void forceUpdateWebhooks(); - /** * @param payload payload The raw payload of the webhook request. * @param signature The signature received from the external system. @@ -170,18 +145,6 @@ void setWebHookRepositoryEnabled(long organizationRemoteId, */ boolean isWebHookWatchLimitEnabled(long organizationRemoteId); - /** - * Limit webhook watch scope or not - * - * @param organizationRemoteId gitHub organization remote Id - * @param enabled true to enabled, else false - * @param currentUser user name attempting to enables/disables webHook watch - * limit. - * @throws IllegalAccessException when user is not authorized Limit webhook - * watch scope - */ - void setWebHookWatchLimitEnabled(long organizationRemoteId, boolean enabled, String currentUser) throws IllegalAccessException; - /** * Retrieve available github organization repositories. * @@ -200,5 +163,11 @@ List retrieveOrganizationRepos(long organizationRemoteId, int page, int perPage, String keyword) throws IllegalAccessException, ObjectNotFoundException; + /** + * Force update the stored github organization webhooks if there is a change to + * the remote webhooks, such as an entity deletion or the update event + **/ + void forceUpdateWebhooks(); + } diff --git a/gamification-github-services/src/main/java/io/meeds/gamification/github/services/impl/GithubConsumerServiceImpl.java b/gamification-github-services/src/main/java/io/meeds/github/gamification/services/impl/GithubConsumerServiceImpl.java similarity index 81% rename from gamification-github-services/src/main/java/io/meeds/gamification/github/services/impl/GithubConsumerServiceImpl.java rename to gamification-github-services/src/main/java/io/meeds/github/gamification/services/impl/GithubConsumerServiceImpl.java index 2b8a34a2b..c42303417 100644 --- a/gamification-github-services/src/main/java/io/meeds/gamification/github/services/impl/GithubConsumerServiceImpl.java +++ b/gamification-github-services/src/main/java/io/meeds/github/gamification/services/impl/GithubConsumerServiceImpl.java @@ -15,26 +15,28 @@ * 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.github.services.impl; +package io.meeds.github.gamification.services.impl; -import io.meeds.gamification.github.model.RemoteOrganization; -import io.meeds.gamification.github.model.WebHook; +import io.meeds.github.gamification.model.RemoteOrganization; +import io.meeds.github.gamification.model.WebHook; import org.exoplatform.commons.exception.ObjectNotFoundException; -import io.meeds.gamification.github.model.RemoteRepository; -import io.meeds.gamification.github.model.TokenStatus; -import io.meeds.gamification.github.services.GithubConsumerService; -import io.meeds.gamification.github.storage.GithubConsumerStorage; +import io.meeds.github.gamification.model.RemoteRepository; +import io.meeds.github.gamification.model.TokenStatus; +import io.meeds.github.gamification.services.GithubConsumerService; +import io.meeds.github.gamification.storage.GithubConsumerStorage; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Primary; +import org.springframework.stereotype.Service; import java.util.List; +@Primary +@Service public class GithubConsumerServiceImpl implements GithubConsumerService { + @Autowired private GithubConsumerStorage githubConsumerStorage; - public GithubConsumerServiceImpl(GithubConsumerStorage githubConsumerStorage) { - this.githubConsumerStorage = githubConsumerStorage; - } - @Override public WebHook createWebhook(String organizationName, String[] triggers, String accessToken) throws IllegalAccessException { return githubConsumerStorage.createWebhook(organizationName, triggers, accessToken); @@ -74,9 +76,4 @@ public RemoteOrganization retrieveRemoteOrganization(long organizationId, String public TokenStatus checkGitHubTokenStatus(String token) { return githubConsumerStorage.checkGitHubTokenStatus(token); } - - @Override - public void clearCache() { - githubConsumerStorage.clearCache(); - } } diff --git a/gamification-github-services/src/main/java/io/meeds/gamification/github/services/impl/GithubTriggerServiceImpl.java b/gamification-github-services/src/main/java/io/meeds/github/gamification/services/impl/GithubTriggerServiceImpl.java similarity index 84% rename from gamification-github-services/src/main/java/io/meeds/gamification/github/services/impl/GithubTriggerServiceImpl.java rename to gamification-github-services/src/main/java/io/meeds/github/gamification/services/impl/GithubTriggerServiceImpl.java index dc177a5e1..13d909a6d 100644 --- a/gamification-github-services/src/main/java/io/meeds/gamification/github/services/impl/GithubTriggerServiceImpl.java +++ b/gamification-github-services/src/main/java/io/meeds/github/gamification/services/impl/GithubTriggerServiceImpl.java @@ -15,9 +15,9 @@ * 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.github.services.impl; +package io.meeds.github.gamification.services.impl; -import io.meeds.gamification.github.model.Event; +import io.meeds.github.gamification.model.Event; import io.meeds.gamification.model.EventDTO; import io.meeds.gamification.service.ConnectorService; import io.meeds.gamification.service.EventService; @@ -27,54 +27,53 @@ import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.exoplatform.commons.api.persistence.ExoTransactional; import org.exoplatform.container.ExoContainerContext; -import io.meeds.gamification.github.plugin.GithubTriggerPlugin; -import io.meeds.gamification.github.services.GithubTriggerService; -import io.meeds.gamification.github.services.WebhookService; +import io.meeds.github.gamification.plugin.GithubTriggerPlugin; +import io.meeds.github.gamification.services.GithubTriggerService; +import io.meeds.github.gamification.services.WebhookService; import org.exoplatform.services.listener.ListenerService; import org.exoplatform.services.log.ExoLogger; import org.exoplatform.services.log.Log; import org.exoplatform.social.core.identity.model.Identity; import org.exoplatform.social.core.manager.IdentityManager; import org.picocontainer.Startable; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Primary; +import org.springframework.stereotype.Service; import java.util.*; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import static io.meeds.gamification.github.utils.Utils.*; +import static io.meeds.github.gamification.utils.Utils.*; +@Primary +@Service public class GithubTriggerServiceImpl implements GithubTriggerService, Startable { private static final Log LOG = ExoLogger.getLogger(GithubTriggerServiceImpl.class); private final Map triggerPlugins = new HashMap<>(); - private final ConnectorService connectorService; + @Autowired + private ConnectorService connectorService; - private final EventService eventService; + @Autowired + private EventService eventService; - private final TriggerService triggerService; + @Autowired + private TriggerService triggerService; + @Autowired private WebhookService webhookService; - private final IdentityManager identityManager; + @Autowired + private IdentityManager identityManager; - private final ListenerService listenerService; + @Autowired + private ListenerService listenerService; private ExecutorService executorService; - public GithubTriggerServiceImpl(ListenerService listenerService, - ConnectorService connectorService, - IdentityManager identityManager, - EventService eventService, - TriggerService triggerService) { - this.listenerService = listenerService; - this.connectorService = connectorService; - this.identityManager = identityManager; - this.eventService = eventService; - this.triggerService = triggerService; - } - @Override public void start() { QueuedThreadPool threadFactory = new QueuedThreadPool(5, 1, 1); diff --git a/gamification-github-services/src/main/java/io/meeds/gamification/github/services/impl/WebhookServiceImpl.java b/gamification-github-services/src/main/java/io/meeds/github/gamification/services/impl/WebhookServiceImpl.java similarity index 82% rename from gamification-github-services/src/main/java/io/meeds/gamification/github/services/impl/WebhookServiceImpl.java rename to gamification-github-services/src/main/java/io/meeds/github/gamification/services/impl/WebhookServiceImpl.java index 43d2d0c17..241a850a0 100644 --- a/gamification-github-services/src/main/java/io/meeds/gamification/github/services/impl/WebhookServiceImpl.java +++ b/gamification-github-services/src/main/java/io/meeds/github/gamification/services/impl/WebhookServiceImpl.java @@ -15,14 +15,14 @@ * 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.github.services.impl; +package io.meeds.github.gamification.services.impl; import java.util.*; import java.util.stream.Collectors; -import io.meeds.gamification.github.model.RemoteOrganization; -import io.meeds.gamification.github.model.WebHook; -import io.meeds.gamification.github.storage.WebHookStorage; +import io.meeds.github.gamification.model.RemoteOrganization; +import io.meeds.github.gamification.model.WebHook; +import io.meeds.github.gamification.storage.WebHookStorage; import io.meeds.gamification.model.RuleDTO; import io.meeds.gamification.model.filter.RuleFilter; import io.meeds.gamification.service.RuleService; @@ -35,16 +35,23 @@ import org.exoplatform.commons.exception.ObjectNotFoundException; import org.exoplatform.commons.api.settings.SettingService; import org.exoplatform.commons.api.settings.SettingValue; -import io.meeds.gamification.github.model.RemoteRepository; -import io.meeds.gamification.github.model.TokenStatus; -import io.meeds.gamification.github.services.GithubConsumerService; -import io.meeds.gamification.github.services.WebhookService; +import io.meeds.github.gamification.model.RemoteRepository; +import io.meeds.github.gamification.model.TokenStatus; +import io.meeds.github.gamification.services.GithubConsumerService; +import io.meeds.github.gamification.services.WebhookService; import org.exoplatform.services.log.ExoLogger; import org.exoplatform.services.log.Log; import org.json.JSONObject; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Primary; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; -import static io.meeds.gamification.github.utils.Utils.*; +import static io.meeds.github.gamification.utils.Utils.*; +@Primary +@Service public class WebhookServiceImpl implements WebhookService { private static final Log LOG = ExoLogger.getLogger(WebhookServiceImpl.class); @@ -55,29 +62,23 @@ public class WebhookServiceImpl implements WebhookService { private static final Scope DISABLED_REPOS_SCOPE = Scope.APPLICATION.id("disabledRepos"); - private final SettingService settingService; + @Autowired + private SettingService settingService; - private final WebHookStorage webHookStorage; + @Autowired + private WebHookStorage webHookStorage; - private final GithubConsumerService githubServiceConsumer; + @Autowired + private GithubConsumerService githubServiceConsumer; - private final RuleService ruleService; + @Autowired + private RuleService ruleService; - public WebhookServiceImpl(SettingService settingService, - WebHookStorage webHookStorage, - GithubConsumerService githubServiceConsumer, - RuleService ruleService) { - this.settingService = settingService; - this.webHookStorage = webHookStorage; - this.githubServiceConsumer = githubServiceConsumer; - this.ruleService = ruleService; - } - - public List getWebhooks(String currentUser, int offset, int limit, boolean forceUpdate) throws IllegalAccessException { + public Page getWebhooks(String currentUser, Pageable pageable) throws IllegalAccessException { if (!Utils.isRewardingManager(currentUser)) { throw new IllegalAccessException(AUTHORIZED_TO_ACCESS_GIT_HUB_HOOKS); } - return getWebhooks(offset, limit, forceUpdate); + return getWebhooks(pageable); } public WebHook getWebhookId(long webhookId, String username) throws IllegalAccessException, ObjectNotFoundException { @@ -99,26 +100,8 @@ public WebHook getWebhookId(long webhookId) { return webHookStorage.getWebHookById(webhookId); } - public List getWebhooks(int offset, int limit, boolean forceUpdate) { - if (forceUpdate) { - forceUpdateWebhooks(); - } - return getWebhooks(offset, limit); - } - - public List getWebhooks(int offset, int limit) { - List hooksIds = webHookStorage.getWebhookIds(offset, limit); - return hooksIds.stream().map(webHookStorage::getWebHookById).toList(); - } - - public int countWebhooks(String currentUser, boolean forceUpdate) throws IllegalAccessException { - if (!Utils.isRewardingManager(currentUser)) { - throw new IllegalAccessException(AUTHORIZED_TO_ACCESS_GIT_HUB_HOOKS); - } - if (forceUpdate) { - forceUpdateWebhooks(); - } - return webHookStorage.countWebhooks(); + public Page getWebhooks(Pageable pageable) { + return webHookStorage.getWebhooks(pageable); } public WebHook createWebhook(String organizationName, @@ -200,13 +183,6 @@ public void deleteWebhook(long organizationId) { }); } - @Override - public void forceUpdateWebhooks() { - githubServiceConsumer.clearCache(); - List webHook = getWebhooks(0, -1); - webHook.forEach(this::forceUpdateWebhook); - } - @Override public boolean verifyWebhookSecret(String payload, String signature) { JSONObject jsonPayload = new JSONObject(payload); @@ -281,16 +257,6 @@ public boolean isWebHookWatchLimitEnabled(long organizationId) { return true; } - @Override - public void setWebHookWatchLimitEnabled(long organizationId, - boolean enabled, - String currentUser) throws IllegalAccessException { - if (!Utils.isRewardingManager(currentUser)) { - throw new IllegalAccessException("The user is not authorized to update webHook watch limit status"); - } - settingService.set(GITHUB_WEBHOOK_CONTEXT, WATCH_LIMITED_SCOPE, String.valueOf(organizationId), SettingValue.create(enabled)); - } - public List retrieveOrganizationRepos(long organizationRemoteId, String currentUser, int page, @@ -309,6 +275,12 @@ public List retrieveOrganizationRepos(long organizationRemoteI return remoteRepositories; } + @Override + public void forceUpdateWebhooks() { + List webHook = webHookStorage.getWebhooks(); + webHook.forEach(this::forceUpdateWebhook); + } + @SuppressWarnings("unchecked") private void forceUpdateWebhook(WebHook webHook) { TokenStatus tokenStatus = githubServiceConsumer.checkGitHubTokenStatus(webHook.getToken()); diff --git a/gamification-github-services/src/main/java/io/meeds/gamification/github/storage/GithubConsumerStorage.java b/gamification-github-services/src/main/java/io/meeds/github/gamification/storage/GithubConsumerStorage.java similarity index 94% rename from gamification-github-services/src/main/java/io/meeds/gamification/github/storage/GithubConsumerStorage.java rename to gamification-github-services/src/main/java/io/meeds/github/gamification/storage/GithubConsumerStorage.java index c318ea19c..1696573ba 100644 --- a/gamification-github-services/src/main/java/io/meeds/gamification/github/storage/GithubConsumerStorage.java +++ b/gamification-github-services/src/main/java/io/meeds/github/gamification/storage/GithubConsumerStorage.java @@ -1,10 +1,10 @@ -package io.meeds.gamification.github.storage; +package io.meeds.github.gamification.storage; -import io.meeds.gamification.github.exception.GithubConnectionException; -import io.meeds.gamification.github.model.RemoteOrganization; -import io.meeds.gamification.github.model.RemoteRepository; -import io.meeds.gamification.github.model.TokenStatus; -import io.meeds.gamification.github.model.WebHook; +import io.meeds.github.gamification.exception.GithubConnectionException; +import io.meeds.github.gamification.model.RemoteOrganization; +import io.meeds.github.gamification.model.RemoteRepository; +import io.meeds.github.gamification.model.TokenStatus; +import io.meeds.github.gamification.model.WebHook; import org.apache.commons.httpclient.HttpStatus; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; @@ -25,6 +25,8 @@ import org.exoplatform.commons.exception.ObjectNotFoundException; import org.exoplatform.commons.utils.CommonsUtils; import org.json.JSONObject; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Repository; import javax.ws.rs.core.MediaType; import java.io.IOException; @@ -33,8 +35,9 @@ import java.nio.charset.StandardCharsets; import java.util.*; -import static io.meeds.gamification.github.utils.Utils.*; +import static io.meeds.github.gamification.utils.Utils.*; +@Repository public class GithubConsumerStorage { private HttpClient client; @@ -45,7 +48,7 @@ public WebHook createWebhook(String organizationName, String[] triggers, String JSONObject config = new JSONObject(); JSONObject hook = new JSONObject(); String url = GITHUB_API_URL + ORGANIZATIONS + organizationName + "/hooks"; - config.put("url", CommonsUtils.getCurrentDomain() + "/portal/rest/gamification/connectors/github/webhooks"); + config.put("url", CommonsUtils.getCurrentDomain() + "/gamification-github/rest/webhooks"); config.put("content_type", "json"); config.put("insecure_ssl", "0"); config.put("secret", secret); @@ -85,6 +88,7 @@ public String deleteWebhookHook(WebHook webHook) { } @SuppressWarnings("unchecked") + @Cacheable(value = "gamification.github.organizationRepos") public List retrieveOrganizationRepos(String organization, String accessToken, int page, @@ -149,6 +153,7 @@ public RemoteOrganization retrieveRemoteOrganization(String organizationName, return gitHubOrganization; } + @Cacheable(value = "gamification.github.remoteOrganization") public RemoteOrganization retrieveRemoteOrganization(long organizationId, String accessToken) { URI uri = URI.create(GITHUB_API_URL + ORGANIZATIONS + organizationId); String response; @@ -167,6 +172,7 @@ public RemoteOrganization retrieveRemoteOrganization(long organizationId, String return gitHubOrganization; } + @Cacheable(value = "gamification.github.tokenStatus") public TokenStatus checkGitHubTokenStatus(String token) { URI uri = URI.create("https://api.github.com/rate_limit"); String response; @@ -309,12 +315,4 @@ private HttpClientConnectionManager getClientConnectionManager() { connectionManager.setDefaultMaxPerRoute(10); return connectionManager; } - - public void clearCache() { // NOSONAR - // implemented in cached storage - } - - public void clearCache(WebHook webHook) { - // implemented in cached storage - } } diff --git a/gamification-github-services/src/main/java/io/meeds/gamification/github/storage/WebHookStorage.java b/gamification-github-services/src/main/java/io/meeds/github/gamification/storage/WebHookStorage.java similarity index 58% rename from gamification-github-services/src/main/java/io/meeds/gamification/github/storage/WebHookStorage.java rename to gamification-github-services/src/main/java/io/meeds/github/gamification/storage/WebHookStorage.java index a8eb88cd2..fa52bdf57 100644 --- a/gamification-github-services/src/main/java/io/meeds/gamification/github/storage/WebHookStorage.java +++ b/gamification-github-services/src/main/java/io/meeds/github/gamification/storage/WebHookStorage.java @@ -15,24 +15,26 @@ * 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.github.storage; +package io.meeds.github.gamification.storage; import java.util.Date; import java.util.List; -import io.meeds.gamification.github.dao.WebHookDAO; -import io.meeds.gamification.github.model.WebHook; -import io.meeds.gamification.github.storage.mapper.WebHookMapper; +import io.meeds.github.gamification.dao.WebHookDAO; +import io.meeds.github.gamification.model.WebHook; +import io.meeds.github.gamification.storage.mapper.WebHookMapper; import org.exoplatform.commons.ObjectAlreadyExistsException; -import io.meeds.gamification.github.entity.WebhookEntity; +import io.meeds.github.gamification.entity.WebhookEntity; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Repository; +@Repository public class WebHookStorage { - private final WebHookDAO webHookDAO; - - public WebHookStorage(WebHookDAO gitHubHookDAO) { - this.webHookDAO = gitHubHookDAO; - } + @Autowired + private WebHookDAO webHookDAO; public WebHook saveWebHook(WebHook webHook) throws ObjectAlreadyExistsException { WebHook existsWebHook = getWebhookByOrganizationId(webHook.getOrganizationId()); @@ -42,7 +44,7 @@ public WebHook saveWebHook(WebHook webHook) throws ObjectAlreadyExistsException webhookEntity.setUpdatedDate(new Date()); webhookEntity.setRefreshDate(new Date()); webhookEntity.setEnabled(true); - webhookEntity = webHookDAO.create(webhookEntity); + webhookEntity = webHookDAO.save(webhookEntity); return WebHookMapper.fromEntity(webhookEntity); } else { throw new ObjectAlreadyExistsException(existsWebHook); @@ -50,40 +52,52 @@ public WebHook saveWebHook(WebHook webHook) throws ObjectAlreadyExistsException } public WebHook updateWebHook(WebHook webHook, boolean forceUpdate) { - WebhookEntity webhookEntity = webHookDAO.find(webHook.getId()); + WebhookEntity webhookEntity = webHookDAO.findById(webHook.getId()).orElse(null); + if (webhookEntity == null) { + return null; + } if (forceUpdate) { webhookEntity.setRefreshDate(new Date()); webhookEntity.setTriggers(webHook.getTriggers()); } webhookEntity.setUpdatedDate(new Date()); - return WebHookMapper.fromEntity(webHookDAO.update(webhookEntity)); + return WebHookMapper.fromEntity(webHookDAO.save(webhookEntity)); } public WebHook updateWebHookAccessToken(long webhookId, String accessToken) { - WebhookEntity webhookEntity = webHookDAO.find(webhookId); + WebhookEntity webhookEntity = webHookDAO.findById(webhookId).orElse(null); + if (webhookEntity == null) { + return null; + } webhookEntity.setToken(accessToken); - return WebHookMapper.fromEntity(webHookDAO.update(webhookEntity)); + return WebHookMapper.fromEntity(webHookDAO.save(webhookEntity)); } public WebHook getWebHookById(Long id) { - return WebHookMapper.fromEntity(webHookDAO.find(id)); + return WebHookMapper.fromEntity(webHookDAO.findById(id).orElse(null)); + } + + public List getWebhooks() { + List webhookEntities = webHookDAO.findAll(); + return webhookEntities.stream().map(WebHookMapper::fromEntity).toList(); } - public List getWebhookIds(int offset, int limit) { - return webHookDAO.getWebhookIds(offset, limit); + public Page getWebhooks(Pageable pageable) { + Page page = webHookDAO.findAll(pageable); + return page.map(WebHookMapper::fromEntity); } - public int countWebhooks() { - return webHookDAO.count().intValue(); + public long countWebhooks() { + return webHookDAO.count(); } public WebHook getWebhookByOrganizationId(long organizationId) { - WebhookEntity connectorHookEntity = webHookDAO.getWebhookByOrganizationId(organizationId); + WebhookEntity connectorHookEntity = webHookDAO.findWebhookEntityByOrganizationId(organizationId); return WebHookMapper.fromEntity(connectorHookEntity); } public WebHook deleteWebHook(long organizationId) { - WebhookEntity webhookEntity = webHookDAO.getWebhookByOrganizationId(organizationId); + WebhookEntity webhookEntity = webHookDAO.findWebhookEntityByOrganizationId(organizationId); if (webhookEntity != null) { webHookDAO.delete(webhookEntity); } diff --git a/gamification-github-services/src/main/java/io/meeds/gamification/github/storage/mapper/WebHookMapper.java b/gamification-github-services/src/main/java/io/meeds/github/gamification/storage/mapper/WebHookMapper.java similarity index 87% rename from gamification-github-services/src/main/java/io/meeds/gamification/github/storage/mapper/WebHookMapper.java rename to gamification-github-services/src/main/java/io/meeds/github/gamification/storage/mapper/WebHookMapper.java index b0eb5effd..4f8494963 100644 --- a/gamification-github-services/src/main/java/io/meeds/gamification/github/storage/mapper/WebHookMapper.java +++ b/gamification-github-services/src/main/java/io/meeds/github/gamification/storage/mapper/WebHookMapper.java @@ -16,17 +16,17 @@ * 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.github.storage.mapper; +package io.meeds.github.gamification.storage.mapper; -import io.meeds.gamification.github.model.WebHook; +import io.meeds.github.gamification.model.WebHook; import io.meeds.gamification.utils.Utils; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.exoplatform.commons.utils.CommonsUtils; -import io.meeds.gamification.github.entity.WebhookEntity; +import io.meeds.github.gamification.entity.WebhookEntity; import org.exoplatform.social.core.manager.IdentityManager; -import static io.meeds.gamification.github.utils.Utils.*; +import static io.meeds.github.gamification.utils.Utils.*; public class WebHookMapper { @@ -73,8 +73,11 @@ public static WebHook fromEntity(WebhookEntity webhookEntity) { if (webhookEntity == null) { return null; } - IdentityManager identityManager = CommonsUtils.getService(IdentityManager.class); - String watchedBy = identityManager.getIdentity(String.valueOf(webhookEntity.getWatchedBy())).getRemoteId(); + String watchedBy = null; + if (webhookEntity.getWatchedBy() != null) { + IdentityManager identityManager = CommonsUtils.getService(IdentityManager.class); + watchedBy = identityManager.getIdentity(String.valueOf(webhookEntity.getWatchedBy())).getRemoteId(); + } return new WebHook(webhookEntity.getId(), webhookEntity.getWebhookId(), webhookEntity.getOrganizationId(), diff --git a/gamification-github-services/src/main/java/io/meeds/gamification/github/utils/StringListConverter.java b/gamification-github-services/src/main/java/io/meeds/github/gamification/utils/StringListConverter.java similarity index 97% rename from gamification-github-services/src/main/java/io/meeds/gamification/github/utils/StringListConverter.java rename to gamification-github-services/src/main/java/io/meeds/github/gamification/utils/StringListConverter.java index cf5a73b50..e1ff9824b 100644 --- a/gamification-github-services/src/main/java/io/meeds/gamification/github/utils/StringListConverter.java +++ b/gamification-github-services/src/main/java/io/meeds/github/gamification/utils/StringListConverter.java @@ -16,7 +16,7 @@ * 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.github.utils; +package io.meeds.github.gamification.utils; import jakarta.persistence.AttributeConverter; import jakarta.persistence.Converter; diff --git a/gamification-github-services/src/main/java/io/meeds/gamification/github/utils/Utils.java b/gamification-github-services/src/main/java/io/meeds/github/gamification/utils/Utils.java similarity index 99% rename from gamification-github-services/src/main/java/io/meeds/gamification/github/utils/Utils.java rename to gamification-github-services/src/main/java/io/meeds/github/gamification/utils/Utils.java index 8ee41e740..a1d8a30d7 100644 --- a/gamification-github-services/src/main/java/io/meeds/gamification/github/utils/Utils.java +++ b/gamification-github-services/src/main/java/io/meeds/github/gamification/utils/Utils.java @@ -16,7 +16,7 @@ * 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.github.utils; +package io.meeds.github.gamification.utils; import java.io.IOException; import java.security.InvalidKeyException; diff --git a/gamification-github-services/src/main/resources/conf/portal/configuration.xml b/gamification-github-services/src/main/resources/conf/portal/configuration.xml index 94c3d335d..0ad3b830e 100644 --- a/gamification-github-services/src/main/resources/conf/portal/configuration.xml +++ b/gamification-github-services/src/main/resources/conf/portal/configuration.xml @@ -23,101 +23,6 @@ xsi:schemaLocation="http://www.exoplatform.org/xml/ns/kernel_1_2.xsd http://www.exoplatform.org/xml/ns/kernel_1_2.xsd" xmlns="http://www.exoplatform.org/xml/ns/kernel_1_2.xsd"> - - io.meeds.gamification.github.rest.GithubWebHookRest - - - - io.meeds.gamification.github.rest.HooksManagementRest - - - - org.exoplatform.services.listener.ListenerService - - github.action.event - addListener - io.meeds.gamification.github.listener.GithubEventsListener - - - github.cancel.action.event - addListener - io.meeds.gamification.github.listener.GithubEventsListener - - - - - io.meeds.gamification.service.ConnectorService - - github - addPlugin - io.meeds.gamification.github.plugin.GithubConnectorPlugin - - - - - io.meeds.gamification.service.EventService - - github - addPlugin - io.meeds.gamification.github.plugin.GithubEventPlugin - - - - - org.exoplatform.services.scheduler.JobSchedulerService - - GitHubWebHookForceUpdate - addCronJob - org.exoplatform.services.scheduler.CronJob - Configuration to manage the periodic updating of github webhooks, ensuring that webhooks data remains current with external sources - - - cronjob.info - Configuration to manage the periodic updating of github webhooks, ensuring that webhooks data remains current with external sources - - - - - - - - - - - io.meeds.gamification.github.services.GithubTriggerService - - push - addPlugin - io.meeds.gamification.github.plugin.PushCodeTriggerPlugin - - - pull_request - addPlugin - io.meeds.gamification.github.plugin.PullRequestTriggerPlugin - - - pull_request_review_comment - addPlugin - io.meeds.gamification.github.plugin.CommentPullRequestTriggerPlugin - - - pull_request_review - addPlugin - io.meeds.gamification.github.plugin.PullRequestReviewTriggerPlugin - - - issues - addPlugin - io.meeds.gamification.github.plugin.IssueTriggerPlugin - - - issue_comment - addPlugin - io.meeds.gamification.github.plugin.CommentTriggerPlugin - - - jar:/conf/portal/gamification-github-connector-configuration.xml - jar:/conf/portal/gamification-github-storage-configuration.xml \ No newline at end of file diff --git a/gamification-github-services/src/main/resources/conf/portal/gamification-github-storage-configuration.xml b/gamification-github-services/src/main/resources/conf/portal/gamification-github-storage-configuration.xml deleted file mode 100644 index 3697d407b..000000000 --- a/gamification-github-services/src/main/resources/conf/portal/gamification-github-storage-configuration.xml +++ /dev/null @@ -1,79 +0,0 @@ - - - - - - io.meeds.gamification.github.dao.WebHookDAO - - - - io.meeds.gamification.github.storage.WebHookStorage - - - - io.meeds.gamification.github.storage.GithubConsumerStorage - - - - io.meeds.gamification.github.storage.GithubConsumerStorage - io.meeds.gamification.github.storage.cached.GithubConsumerCachedStorage - - - - io.meeds.gamification.github.services.WebhookService - io.meeds.gamification.github.services.impl.WebhookServiceImpl - - - - io.meeds.gamification.github.services.WebhookService - io.meeds.gamification.github.services.impl.WebhookServiceImpl - - - - io.meeds.gamification.github.services.GithubTriggerService - io.meeds.gamification.github.services.impl.GithubTriggerServiceImpl - - - - io.meeds.gamification.github.services.GithubConsumerService - io.meeds.gamification.github.services.impl.GithubConsumerServiceImpl - - - - org.exoplatform.commons.api.persistence.DataInitializer - - GamificationChangeLogsPlugin - addChangeLogsPlugin - org.exoplatform.commons.persistence.impl.ChangeLogsPlugin - - - changelogs - Change logs of GitHub Connector - db/changelog/github-connector.db.changelog-1.0.0.xml - - - - - - \ No newline at end of file diff --git a/gamification-github-services/src/main/resources/jpa-entities.idx b/gamification-github-services/src/main/resources/jpa-entities.idx index 6149a36a7..1436792c3 100644 --- a/gamification-github-services/src/main/resources/jpa-entities.idx +++ b/gamification-github-services/src/main/resources/jpa-entities.idx @@ -1 +1 @@ -io.meeds.gamification.github.entity.WebhookEntity \ No newline at end of file +io.meeds.github.gamification.entity.WebhookEntity \ No newline at end of file diff --git a/gamification-github-services/src/test/java/io/meeds/gamification/github/BaseGithubTest.java b/gamification-github-services/src/test/java/io/meeds/gamification/github/BaseGithubTest.java deleted file mode 100644 index 77832dd7e..000000000 --- a/gamification-github-services/src/test/java/io/meeds/gamification/github/BaseGithubTest.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * This file is part of the Meeds project (https://meeds.io/). - * - * Copyright (C) 2020 - 2024 Meeds Lab contact@meedslab.com - * - * 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.github; - -import io.meeds.gamification.github.dao.WebHookDAO; -import io.meeds.gamification.github.services.GithubConsumerService; -import io.meeds.gamification.github.services.GithubTriggerService; -import io.meeds.gamification.github.services.WebhookService; -import io.meeds.gamification.github.services.impl.GithubTriggerServiceImpl; -import io.meeds.gamification.github.services.impl.WebhookServiceImpl; -import io.meeds.gamification.github.storage.WebHookStorage; -import io.meeds.gamification.service.ConnectorService; -import io.meeds.gamification.service.EventService; -import io.meeds.gamification.service.RuleService; -import io.meeds.gamification.service.TriggerService; -import io.meeds.gamification.utils.Utils; -import org.exoplatform.commons.api.settings.SettingService; -import org.exoplatform.services.listener.ListenerService; -import org.exoplatform.services.security.IdentityRegistry; -import org.exoplatform.services.security.MembershipEntry; -import org.exoplatform.social.core.manager.IdentityManager; -import org.exoplatform.web.security.codec.CodecInitializer; -import org.junit.After; -import org.junit.Before; - -import org.exoplatform.commons.testing.BaseExoTestCase; -import org.exoplatform.component.test.ConfigurationUnit; -import org.exoplatform.component.test.ConfiguredBy; -import org.exoplatform.component.test.ContainerScope; -import org.exoplatform.container.ExoContainerContext; -import org.exoplatform.services.security.ConversationState; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; -import java.util.Collections; - -@RunWith(MockitoJUnitRunner.class) -@ConfiguredBy({ @ConfigurationUnit(scope = ContainerScope.ROOT, path = "conf/configuration.xml"), - @ConfigurationUnit(scope = ContainerScope.PORTAL, path = "conf/portal/github-test-configuration.xml"), - @ConfigurationUnit(scope = ContainerScope.PORTAL, path = "conf/portal/configuration.xml"), }) -public abstract class BaseGithubTest extends BaseExoTestCase { // NOSONAR - - protected WebhookService webhookService; - - protected GithubTriggerService githubTriggerService; - - protected SettingService settingService; - - protected WebHookStorage webHookStorage; - - @Mock - protected GithubConsumerService githubConsumerService; - - @Mock - protected RuleService ruleService; - - @Mock - protected ConnectorService connectorService; - - @Mock - protected TriggerService triggerService; - - @Mock - protected ListenerService listenerService; - - @Mock - protected EventService eventService; - - protected CodecInitializer codecInitializer; - - protected WebHookDAO webHookDAO; - - protected IdentityManager identityManager; - - protected IdentityRegistry identityRegistry; - - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - ExoContainerContext.setCurrentContainer(getContainer()); - settingService = ExoContainerContext.getService(SettingService.class); - webHookDAO = ExoContainerContext.getService(WebHookDAO.class); - codecInitializer = ExoContainerContext.getService(CodecInitializer.class); - identityRegistry = ExoContainerContext.getService(IdentityRegistry.class); - identityManager = ExoContainerContext.getService(IdentityManager.class); - webHookStorage = ExoContainerContext.getService(WebHookStorage.class); - githubTriggerService = new GithubTriggerServiceImpl(listenerService, - connectorService, - identityManager, - eventService, - triggerService); - webhookService = new WebhookServiceImpl(settingService, webHookStorage, githubConsumerService, ruleService); - resetUserSession(); - begin(); - } - - @Override - @After - public void tearDown() { - restartTransaction(); - webHookDAO.deleteAll(); - end(); - } - - protected void resetUserSession() { - ConversationState.setCurrent(null); - } - - protected org.exoplatform.services.security.Identity registerAdministratorUser(String user) { - org.exoplatform.services.security.Identity identity = - new org.exoplatform.services.security.Identity(user, - Collections.singletonList(new MembershipEntry(Utils.REWARDING_GROUP))); - identityRegistry.register(identity); - return identity; - } - - protected org.exoplatform.services.security.Identity registerInternalUser(String username) { - org.exoplatform.services.security.Identity identity = - new org.exoplatform.services.security.Identity(username, - Collections.singletonList(new MembershipEntry("/platform/users"))); - identityRegistry.register(identity); - return identity; - } -} diff --git a/gamification-github-services/src/test/java/io/meeds/gamification/github/dao/WebHookDAOTest.java b/gamification-github-services/src/test/java/io/meeds/gamification/github/dao/WebHookDAOTest.java deleted file mode 100644 index d30e15596..000000000 --- a/gamification-github-services/src/test/java/io/meeds/gamification/github/dao/WebHookDAOTest.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * This file is part of the Meeds project (https://meeds.io/). - * - * Copyright (C) 2020 - 2024 Meeds Lab contact@meedslab.com - * - * 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.github.dao; - -import io.meeds.gamification.github.BaseGithubTest; -import io.meeds.gamification.github.entity.WebhookEntity; -import org.junit.Test; - -import java.util.Date; -import java.util.List; - -public class WebHookDAOTest extends BaseGithubTest { - - @Test - public void testCreateWebhook() { - WebhookEntity webhookEntity = new WebhookEntity(); - webhookEntity.setWebhookId(112448L); - webhookEntity.setOrganizationId(555452L); - webhookEntity.setOrganizationName("organizationName"); - webhookEntity.setSecret("secret"); - webhookEntity.setToken("token"); - webhookEntity.setTriggers(List.of("trigger1", "trigger2")); - webhookEntity.setUpdatedDate(new Date()); - webhookEntity.setWatchedDate(new Date()); - webhookEntity.setWatchedBy(1L); - webhookEntity.setRefreshDate(new Date()); - webhookEntity.setEnabled(true); - - // When - webhookEntity = webHookDAO.create(webhookEntity); - - // Then - assertNotNull(webhookEntity.getId()); - assertEquals("organizationName", webhookEntity.getOrganizationName()); - assertEquals("token", webhookEntity.getToken()); - assertEquals("secret", webhookEntity.getSecret()); - assertNotNull(webhookEntity.getOrganizationId()); - assertNotNull(webhookEntity.getWebhookId()); - - assertEquals(webhookEntity, webHookDAO.getWebhookByOrganizationId(555452L)); - assertNotNull(webHookDAO.getWebhookIds(0, 10)); - } - - @Test - public void testDeleteWebhook() { - WebhookEntity webhookEntity = new WebhookEntity(); - - webhookEntity.setWebhookId(112448L); - webhookEntity.setOrganizationId(555452L); - webhookEntity.setOrganizationName("organizationName"); - webhookEntity.setSecret("secret"); - webhookEntity.setToken("token"); - webhookEntity.setTriggers(List.of("trigger1", "trigger2")); - webhookEntity.setUpdatedDate(new Date()); - webhookEntity.setWatchedDate(new Date()); - webhookEntity.setWatchedBy(1L); - webhookEntity.setRefreshDate(new Date()); - webhookEntity.setEnabled(true); - - webhookEntity = webHookDAO.create(webhookEntity); - - assertNotNull(webhookEntity.getId()); - - webHookDAO.delete(webhookEntity); - - webhookEntity = webHookDAO.find(webhookEntity.getId()); - assertNull(webhookEntity); - } -} diff --git a/gamification-github-services/src/test/java/io/meeds/gamification/github/mock/ConnectorServiceMock.java b/gamification-github-services/src/test/java/io/meeds/gamification/github/mock/ConnectorServiceMock.java deleted file mode 100644 index 41b09521f..000000000 --- a/gamification-github-services/src/test/java/io/meeds/gamification/github/mock/ConnectorServiceMock.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * This file is part of the Meeds project (https://meeds.io/). - * - * Copyright (C) 2020 - 2024 Meeds Lab contact@meedslab.com - * - * 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.github.mock; - -import io.meeds.gamification.model.RemoteConnector; -import io.meeds.gamification.plugin.ConnectorPlugin; -import io.meeds.gamification.service.ConnectorService; -import org.exoplatform.services.security.Identity; - -import java.util.Collection; - -public class ConnectorServiceMock implements ConnectorService { - @Override - public void addPlugin(ConnectorPlugin connectorPlugin) { - - } - - @Override - public void removePlugin(String name) { - - } - - @Override - public Collection getConnectorPlugins() { - return null; - } - - @Override - public Collection getConnectors(String username) { - return null; - } - - @Override - public String connect(String connectorName, String connectorUserId, String accessToken, Identity identity) { - return null; - } - - @Override - public void disconnect(String connectorName, String username) { - - } - - @Override - public String getConnectorRemoteId(String connectorName, String username) { - return null; - } - - @Override - public String getAssociatedUsername(String connectorName, String connectorRemoteId) { - return null; - } -} diff --git a/gamification-github-services/src/test/java/io/meeds/gamification/github/mock/ConnectorSettingServiceMock.java b/gamification-github-services/src/test/java/io/meeds/gamification/github/mock/ConnectorSettingServiceMock.java deleted file mode 100644 index 2404d4702..000000000 --- a/gamification-github-services/src/test/java/io/meeds/gamification/github/mock/ConnectorSettingServiceMock.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * This file is part of the Meeds project (https://meeds.io/). - * - * Copyright (C) 2020 - 2024 Meeds Lab contact@meedslab.com - * - * 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.github.mock; - -import io.meeds.gamification.model.RemoteConnectorSettings; -import io.meeds.gamification.service.ConnectorService; -import io.meeds.gamification.service.ConnectorSettingService; -import org.exoplatform.services.security.Identity; - -import java.util.List; - -public class ConnectorSettingServiceMock implements ConnectorSettingService { - @Override - public void saveConnectorSettings(RemoteConnectorSettings remoteConnectorSettings, Identity aclIdentity) { - - } - - @Override - public void deleteConnectorSettings(String connectorName, Identity aclIdentity) { - - } - - @Override - public RemoteConnectorSettings getConnectorSettings(String connectorName, Identity aclIdentity) { - return null; - } - - @Override - public RemoteConnectorSettings getConnectorSettings(String connectorName) { - return null; - } - - @Override - public String getConnectorSecretKey(String connectorName) { - return null; - } - - @Override - public List getConnectorsSettings(ConnectorService connectorService, Identity aclIdentity) { - return null; - } - - @Override - public boolean canManageConnectorSettings(Identity aclIdentity) { - return false; - } -} diff --git a/gamification-github-services/src/test/java/io/meeds/gamification/github/mock/EventServiceMock.java b/gamification-github-services/src/test/java/io/meeds/gamification/github/mock/EventServiceMock.java deleted file mode 100644 index fbb360886..000000000 --- a/gamification-github-services/src/test/java/io/meeds/gamification/github/mock/EventServiceMock.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * This file is part of the Meeds project (https://meeds.io/). - * - * Copyright (C) 2020 - 2024 Meeds Lab contact@meedslab.com - * - * 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.github.mock; - -import io.meeds.gamification.model.EventDTO; -import io.meeds.gamification.model.filter.EventFilter; -import io.meeds.gamification.plugin.EventPlugin; -import io.meeds.gamification.service.EventService; - -import java.util.List; - -public class EventServiceMock implements EventService { - @Override - public void addPlugin(EventPlugin eventPlugin) { - - } - - @Override - public void removePlugin(String eventType) { - - } - - @Override - public EventPlugin getEventPlugin(String eventType) { - return null; - } - - @Override - public List getEvents(EventFilter eventFilter, int offset, int limit) { - return null; - } - - @Override - public List getEventsByTitle(String title, int offset, int limit) { - return null; - } - - @Override - public int countEvents(EventFilter eventFilter) { - return 0; - } - - @Override - public EventDTO getEventByTitleAndTrigger(String title, String trigger) { - return null; - } - - @Override - public EventDTO createEvent(EventDTO eventDTO) { - return null; - } - - @Override - public EventDTO updateEvent(EventDTO eventDTO) { - return null; - } - - @Override - public EventDTO getEvent(long eventId) { - return null; - } - - @Override - public EventDTO deleteEventById(long eventId) { - return null; - } -} diff --git a/gamification-github-services/src/test/java/io/meeds/gamification/github/mock/IdentityManagerMock.java b/gamification-github-services/src/test/java/io/meeds/gamification/github/mock/IdentityManagerMock.java deleted file mode 100644 index feeba217c..000000000 --- a/gamification-github-services/src/test/java/io/meeds/gamification/github/mock/IdentityManagerMock.java +++ /dev/null @@ -1,237 +0,0 @@ -/* - * This file is part of the Meeds project (https://meeds.io/). - * - * Copyright (C) 2020 - 2024 Meeds Lab contact@meedslab.com - * - * 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.github.mock; - -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; - -import org.apache.commons.codec.binary.StringUtils; - -import org.exoplatform.commons.utils.ListAccess; -import org.exoplatform.social.core.identity.IdentityProvider; -import org.exoplatform.social.core.identity.IdentityProviderPlugin; -import org.exoplatform.social.core.identity.SpaceMemberFilterListAccess.Type; -import org.exoplatform.social.core.identity.model.Identity; -import org.exoplatform.social.core.identity.model.Profile; -import org.exoplatform.social.core.identity.provider.OrganizationIdentityProvider; -import org.exoplatform.social.core.identity.provider.SpaceIdentityProvider; -import org.exoplatform.social.core.manager.IdentityManager; -import org.exoplatform.social.core.profile.ProfileFilter; -import org.exoplatform.social.core.profile.ProfileListener; -import org.exoplatform.social.core.profile.ProfileListenerPlugin; -import org.exoplatform.social.core.space.model.Space; -import org.exoplatform.social.core.storage.api.IdentityStorage; - -public class IdentityManagerMock implements IdentityManager { - - protected static List identities = new ArrayList<>(); - - public IdentityManagerMock() { - for (int i = 0; i < 100; i++) { - Identity identity = new Identity(String.valueOf(i)); - identity.setDeleted(false); - identity.setEnable(true); - identity.setProviderId(OrganizationIdentityProvider.NAME); - identity.setRemoteId("root" + i); - Profile profile = new Profile(identity); - identity.setProfile(profile); - identities.add(identity); - } - - for (int i = 100; i < 200; i++) { - Identity identity = new Identity(String.valueOf(i)); - identity.setDeleted(false); - identity.setEnable(true); - identity.setProviderId(SpaceIdentityProvider.NAME); - identity.setRemoteId("space" + i); - Profile profile = new Profile(identity); - identity.setProfile(profile); - identities.add(identity); - } - } - - public Identity getOrCreateIdentity(String providerId, String remoteId, boolean isProfileLoaded) { - return identities.stream() - .filter(identity -> StringUtils.equals(identity.getProviderId(), providerId) - && StringUtils.equals(identity.getRemoteId(), remoteId)) - .findFirst() - .orElse(null); - } - - public Identity getOrCreateSpaceIdentity(String spacePrettyName) { - return getOrCreateIdentity(SpaceIdentityProvider.NAME, spacePrettyName); - } - - public Identity getOrCreateUserIdentity(String username) { - return getOrCreateIdentity(OrganizationIdentityProvider.NAME, username); - } - - public Identity getIdentity(String identityId, boolean isProfileLoaded) { - return identities.stream().filter(identity -> StringUtils.equals(identity.getId(), identityId)).findFirst().orElse(null); - } - - public void registerIdentityProviders(IdentityProviderPlugin plugin) { - // NOOP - } - - public void addProfileListener(ProfileListenerPlugin plugin) { - // NOOP - } - - public Identity getIdentity(String providerId, String remoteId, boolean loadProfile) { - return getOrCreateIdentity(providerId, remoteId, loadProfile); - } - - public boolean identityExisted(String providerId, String remoteId) { - return getOrCreateIdentity(providerId, remoteId, true) != null; - } - - public Identity getIdentity(String id) { - return getIdentity(id, true); - } - - public Identity getOrCreateIdentity(String providerId, String remoteId) { - return getOrCreateIdentity(providerId, remoteId, true); - } - - public Identity updateIdentity(Identity identity) { - identities.replaceAll(existingIdentity -> StringUtils.equals(identity.getId(), existingIdentity.getId()) ? identity - : existingIdentity); - return identity; - } - - public List getLastIdentities(int limit) { - throw new UnsupportedOperationException(); - } - - public void deleteIdentity(Identity identity) { - throw new UnsupportedOperationException(); - } - - public void hardDeleteIdentity(Identity identity) { - throw new UnsupportedOperationException(); - } - - public ListAccess getConnectionsWithListAccess(Identity identity) { - throw new UnsupportedOperationException(); - } - - public Profile getProfile(Identity identity) { - return identity.getProfile(); - } - - public InputStream getAvatarInputStream(Identity identity) { - throw new UnsupportedOperationException(); - } - - public InputStream getBannerInputStream(Identity identity) { - throw new UnsupportedOperationException(); - } - - public void updateProfile(Profile specificProfile) { - // empty - } - - public ListAccess getIdentitiesByProfileFilter(String providerId, - ProfileFilter profileFilter, - boolean isProfileLoaded) { - throw new UnsupportedOperationException(); - } - - public ListAccess getIdentitiesForUnifiedSearch(String providerId, ProfileFilter profileFilter) { - throw new UnsupportedOperationException(); - } - - public ListAccess getSpaceIdentityByProfileFilter(Space space, - ProfileFilter profileFilter, - Type type, - boolean isProfileLoaded) { - throw new UnsupportedOperationException(); - } - - public void addIdentityProvider(IdentityProvider identityProvider) { - throw new UnsupportedOperationException(); - } - - public void removeIdentityProvider(IdentityProvider identityProvider) { - throw new UnsupportedOperationException(); - } - - public void registerProfileListener(ProfileListenerPlugin profileListenerPlugin) { - throw new UnsupportedOperationException(); - } - - public void processEnabledIdentity(String remoteId, boolean isEnable) { - throw new UnsupportedOperationException(); - } - - public List getIdentitiesByProfileFilter(String providerId, ProfileFilter profileFilter) { - throw new UnsupportedOperationException(); - } - - public List getIdentitiesByProfileFilter(String providerId, ProfileFilter profileFilter, long offset, long limit) { - throw new UnsupportedOperationException(); - } - - public List getIdentitiesByProfileFilter(ProfileFilter profileFilter) { - throw new UnsupportedOperationException(); - } - - public List getIdentitiesByProfileFilter(ProfileFilter profileFilter, long offset, long limit) { - throw new UnsupportedOperationException(); - } - - public List getIdentitiesFilterByAlphaBet(String providerId, ProfileFilter profileFilter) { - throw new UnsupportedOperationException(); - } - - public List getIdentitiesFilterByAlphaBet(String providerId, ProfileFilter profileFilter, long offset, long limit) { - throw new UnsupportedOperationException(); - } - - public List getIdentitiesFilterByAlphaBet(ProfileFilter profileFilter) { - throw new UnsupportedOperationException(); - } - - public long getIdentitiesCount(String providerId) { - throw new UnsupportedOperationException(); - } - - public List getConnections(Identity ownerIdentity) { - throw new UnsupportedOperationException(); - } - - public IdentityStorage getIdentityStorage() { - throw new UnsupportedOperationException(); - } - - public IdentityStorage getStorage() { - throw new UnsupportedOperationException(); - } - - public void registerProfileListener(ProfileListener listener) { - throw new UnsupportedOperationException(); - } - - public void unregisterProfileListener(ProfileListener listener) { - throw new UnsupportedOperationException(); - } - -} diff --git a/gamification-github-services/src/test/java/io/meeds/gamification/github/mock/RuleServiceMock.java b/gamification-github-services/src/test/java/io/meeds/gamification/github/mock/RuleServiceMock.java deleted file mode 100644 index c4c6c4535..000000000 --- a/gamification-github-services/src/test/java/io/meeds/gamification/github/mock/RuleServiceMock.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * This file is part of the Meeds project (https://meeds.io/). - * - * Copyright (C) 2020 - 2024 Meeds Lab contact@meedslab.com - * - * 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.github.mock; - -import io.meeds.gamification.model.RuleDTO; -import io.meeds.gamification.model.filter.RuleFilter; -import io.meeds.gamification.service.RuleService; - -import java.util.List; - -public class RuleServiceMock implements RuleService { - @Override - public RuleDTO findRuleById(long id) { - return null; - } - - @Override - public RuleDTO findRuleById(long id, String username) { - return null; - } - - @Override - public RuleDTO findRuleByTitle(String ruleTitle) { - return null; - } - - @Override - public List getRules(RuleFilter ruleFilter, String username, int offset, int limit) { - return null; - } - - @Override - public List getRules(RuleFilter ruleFilter, int offset, int limit) { - return null; - } - - @Override - public int countRules(RuleFilter ruleFilter, String username) { - return 0; - } - - @Override - public int countRules(RuleFilter ruleFilter) { - return 0; - } - - @Override - public int countActiveRules(long programId) { - return 0; - } - - @Override - public RuleDTO deleteRuleById(long ruleId, String username) { - return null; - } - - @Override - public RuleDTO deleteRuleById(long ruleId) { - return null; - } - - @Override - public RuleDTO createRule(RuleDTO ruleDTO, String username) { - return null; - } - - @Override - public RuleDTO createRule(RuleDTO ruleDTO) { - return null; - } - - @Override - public RuleDTO updateRule(RuleDTO ruleDTO, String username) { - return null; - } - - @Override - public List getPrerequisiteRules(long ruleId) { - return null; - } -} diff --git a/gamification-github-services/src/test/java/io/meeds/gamification/github/mock/TriggerServiceMock.java b/gamification-github-services/src/test/java/io/meeds/gamification/github/mock/TriggerServiceMock.java deleted file mode 100644 index 28e5022af..000000000 --- a/gamification-github-services/src/test/java/io/meeds/gamification/github/mock/TriggerServiceMock.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * This file is part of the Meeds project (https://meeds.io/). - * - * Copyright (C) 2020 - 2024 Meeds Lab contact@meedslab.com - * - * 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.github.mock; - -import io.meeds.gamification.model.TriggerProperties; -import io.meeds.gamification.service.TriggerService; - -public class TriggerServiceMock implements TriggerService { - @Override - public TriggerProperties getTriggerProperties(String triggerName) { - return null; - } - - @Override - public void setTriggerEnabledForAccount(String triggerName, long accountId, boolean enabled, String currentUser) { - - } - - @Override - public boolean isTriggerEnabledForAccount(String triggerName, long accountId) { - return false; - } -} diff --git a/gamification-github-services/src/test/java/io/meeds/gamification/github/service/WebhookServiceTest.java b/gamification-github-services/src/test/java/io/meeds/gamification/github/service/WebhookServiceTest.java deleted file mode 100644 index 7fb827044..000000000 --- a/gamification-github-services/src/test/java/io/meeds/gamification/github/service/WebhookServiceTest.java +++ /dev/null @@ -1,197 +0,0 @@ -/* - * This file is part of the Meeds project (https://meeds.io/). - * - * Copyright (C) 2020 - 2024 Meeds Lab contact@meedslab.com - * - * 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.github.service; - -import static io.meeds.gamification.github.utils.Utils.AUTHORIZED_TO_ACCESS_GIT_HUB_HOOKS; -import static io.meeds.gamification.github.utils.Utils.GITHUB_TRIGGERS; -import static org.junit.Assert.assertThrows; -import static org.mockito.Mockito.when; - -import io.meeds.gamification.github.BaseGithubTest; -import io.meeds.gamification.github.model.RemoteOrganization; -import io.meeds.gamification.github.model.TokenStatus; -import io.meeds.gamification.github.model.WebHook; -import org.exoplatform.commons.ObjectAlreadyExistsException; -import org.exoplatform.commons.exception.ObjectNotFoundException; -import org.junit.Test; - -import java.util.Arrays; - -public class WebhookServiceTest extends BaseGithubTest { - - private static final String ADMIN_USER = "root1"; - - private static final String USER = "root"; - - @Override - public void setUp() throws Exception { - super.setUp(); - registerAdministratorUser(ADMIN_USER); - registerInternalUser(USER); - } - - @Test - public void testCreateWebhook() throws Exception { - Throwable exception = assertThrows(IllegalAccessException.class, - () -> webhookService.createWebhook("organizationName", "accessToken", USER)); - assertEquals("The user is not authorized to create GitHub hook", exception.getMessage()); - - TokenStatus tokenStatus = new TokenStatus(); - tokenStatus.setValid(false); - when(githubConsumerService.checkGitHubTokenStatus("tokenExpiredOrInvalid")).thenReturn(tokenStatus); - exception = assertThrows(IllegalAccessException.class, - () -> webhookService.createWebhook("organizationName", "tokenExpiredOrInvalid", ADMIN_USER)); - assertEquals("github.tokenExpiredOrInvalid", exception.getMessage()); - - tokenStatus = new TokenStatus(); - tokenStatus.setValid(true); - tokenStatus.setRemaining(0L); - when(githubConsumerService.checkGitHubTokenStatus("tokenRateLimitReached")).thenReturn(tokenStatus); - exception = assertThrows(IllegalAccessException.class, - () -> webhookService.createWebhook("organizationName", "tokenRateLimitReached", ADMIN_USER)); - assertEquals("github.tokenRateLimitReached", exception.getMessage()); - - tokenStatus = new TokenStatus(); - tokenStatus.setValid(true); - tokenStatus.setRemaining(11254545L); - when(githubConsumerService.checkGitHubTokenStatus("accessToken")).thenReturn(tokenStatus); - RemoteOrganization remoteOrganization = new RemoteOrganization(1, - "organizationName", - "organizationTitle", - "description", - "avatarUrl"); - when(githubConsumerService.retrieveRemoteOrganization("organizationName", "accessToken")).thenReturn(remoteOrganization); - WebHook webhook = new WebHook(); - webhook.setWebhookId(1245L); - webhook.setOrganizationId(11245L); - webhook.setOrganizationName("organizationName"); - webhook.setTriggers(Arrays.asList(GITHUB_TRIGGERS)); - webhook.setEnabled(true); - webhook.setToken("accessToken"); - webhook.setSecret("secret"); - when(githubConsumerService.createWebhook("organizationName", GITHUB_TRIGGERS, "accessToken")).thenReturn(webhook); - - // When - WebHook createdWebHook = webhookService.createWebhook("organizationName", "accessToken", ADMIN_USER); - - // Then - assertNotNull(webhookService.getWebhookId(createdWebHook.getId(), ADMIN_USER)); - exception = assertThrows(IllegalAccessException.class, () -> webhookService.getWebhookId(createdWebHook.getId(), USER)); - assertEquals(AUTHORIZED_TO_ACCESS_GIT_HUB_HOOKS, exception.getMessage()); - assertThrows(ObjectNotFoundException.class, () -> webhookService.getWebhookId(10, ADMIN_USER)); - assertThrows(IllegalArgumentException.class, () -> webhookService.getWebhookId(-10, ADMIN_USER)); - assertThrows(ObjectAlreadyExistsException.class, - () -> webhookService.createWebhook("organizationName", "accessToken", ADMIN_USER)); - - // When - exception = assertThrows(IllegalAccessException.class, - () -> webhookService.updateWebHookAccessToken(createdWebHook.getId(), "newAccessToken", USER)); - assertEquals(AUTHORIZED_TO_ACCESS_GIT_HUB_HOOKS, exception.getMessage()); - assertThrows(IllegalArgumentException.class, - () -> webhookService.updateWebHookAccessToken(-10, "newAccessToken", ADMIN_USER)); - assertThrows(ObjectNotFoundException.class, () -> webhookService.updateWebHookAccessToken(10, "newAccessToken", ADMIN_USER)); - webhookService.updateWebHookAccessToken(createdWebHook.getId(), "newAccessToken", ADMIN_USER); - - // Then - assertEquals("newAccessToken", webhookService.getWebhookId(createdWebHook.getId(), ADMIN_USER).getToken()); - - } - - @Test - public void testGetWebhooks() throws Exception { - Throwable exception = assertThrows(IllegalAccessException.class, () -> webhookService.getWebhooks(USER, 0, -1, false)); - assertEquals(AUTHORIZED_TO_ACCESS_GIT_HUB_HOOKS, exception.getMessage()); - exception = assertThrows(IllegalAccessException.class, () -> webhookService.countWebhooks(USER, false)); - assertEquals(AUTHORIZED_TO_ACCESS_GIT_HUB_HOOKS, exception.getMessage()); - - TokenStatus tokenStatus = new TokenStatus(); - tokenStatus.setValid(true); - tokenStatus.setRemaining(11254545L); - when(githubConsumerService.checkGitHubTokenStatus("accessToken")).thenReturn(tokenStatus); - RemoteOrganization remoteOrganization = new RemoteOrganization(1, - "organizationName", - "organizationTitle", - "description", - "avatarUrl"); - RemoteOrganization remoteOrganization1 = new RemoteOrganization(2, - "organizationName1", - "organizationTitle1", - "description1", - "avatarUrl1"); - when(githubConsumerService.retrieveRemoteOrganization("organizationName", "accessToken")).thenReturn(remoteOrganization); - when(githubConsumerService.retrieveRemoteOrganization("organizationName1", "accessToken")).thenReturn(remoteOrganization1); - WebHook webhook = new WebHook(); - webhook.setWebhookId(1245L); - webhook.setOrganizationId(11245L); - webhook.setOrganizationName("organizationName"); - webhook.setTriggers(Arrays.asList(GITHUB_TRIGGERS)); - webhook.setEnabled(true); - webhook.setToken("accessToken"); - webhook.setSecret("secret"); - WebHook webhook1 = new WebHook(); - webhook1.setWebhookId(222545L); - webhook1.setOrganizationId(888655L); - webhook1.setOrganizationName("organizationName1"); - webhook1.setTriggers(Arrays.asList(GITHUB_TRIGGERS)); - webhook1.setEnabled(true); - webhook1.setToken("accessToken"); - webhook1.setSecret("secret"); - when(githubConsumerService.createWebhook("organizationName", GITHUB_TRIGGERS, "accessToken")).thenReturn(webhook); - when(githubConsumerService.createWebhook("organizationName1", GITHUB_TRIGGERS, "accessToken")).thenReturn(webhook1); - - // When - WebHook webHook = webhookService.createWebhook("organizationName", "accessToken", ADMIN_USER); - webhookService.createWebhook("organizationName1", "accessToken", ADMIN_USER); - - // Then - assertNotNull(webhookService.getWebhooks(ADMIN_USER, 0, 10, false)); - assertEquals(2, webhookService.countWebhooks(ADMIN_USER, false)); - - // When - exception = assertThrows(IllegalAccessException.class, () -> webhookService.deleteWebhook(webHook.getOrganizationId(), USER)); - assertEquals("The user is not authorized to delete GitHub hook", exception.getMessage()); - assertThrows(ObjectNotFoundException.class, () -> webhookService.deleteWebhook(1000, ADMIN_USER)); - when(githubConsumerService.deleteWebhook(webHook)).thenReturn("response"); - webhookService.deleteWebhook(webHook.getOrganizationId(), ADMIN_USER); - - // Then - assertNotNull(webhookService.getWebhooks(ADMIN_USER, 0, 10, false)); - assertEquals(1, webhookService.countWebhooks(ADMIN_USER, false)); - } - - @Test - public void testIsWebHookRepositoryEnabled() throws Exception { - // When - String payload = "{\"organization\":{\"id\":\"14524\"},\"repository\":{\"id\":\"555564545\"}}"; - - // Then - assertTrue(webhookService.isWebHookRepositoryEnabled(payload)); - - // When - Exception exception = assertThrows(IllegalAccessException.class, - () -> webhookService.setWebHookRepositoryEnabled(14524L, 555564545L, false, USER)); - assertEquals("The user is not authorized to update repository status", exception.getMessage()); - - webhookService.setWebHookRepositoryEnabled(14524L, 555564545L, false, ADMIN_USER); - assertFalse(webhookService.isWebHookRepositoryEnabled(payload)); - - webhookService.setWebHookRepositoryEnabled(14524L, 555564545L, true, ADMIN_USER); - assertTrue(webhookService.isWebHookRepositoryEnabled(payload)); - } -} diff --git a/gamification-github-services/src/test/java/io/meeds/github/gamification/listener/GithubEventsListenerTest.java b/gamification-github-services/src/test/java/io/meeds/github/gamification/listener/GithubEventsListenerTest.java new file mode 100644 index 000000000..ad3ea819e --- /dev/null +++ b/gamification-github-services/src/test/java/io/meeds/github/gamification/listener/GithubEventsListenerTest.java @@ -0,0 +1,70 @@ +/* + * This file is part of the Meeds project (https://meeds.io/). + * + * Copyright (C) 2020 - 2024 Meeds Lab contact@meedslab.com + * + * 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.github.gamification.listener; + +import static io.meeds.github.gamification.listener.GithubEventsListener.GAMIFICATION_CANCEL_EVENT; +import static io.meeds.github.gamification.listener.GithubEventsListener.GAMIFICATION_GENERIC_EVENT; +import static io.meeds.github.gamification.utils.Utils.GITHUB_ACTION_EVENT; +import static io.meeds.github.gamification.utils.Utils.GITHUB_CANCEL_ACTION_EVENT; +import static org.mockito.Mockito.*; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; + +import org.exoplatform.services.listener.Event; +import org.exoplatform.services.listener.ListenerService; + +@SpringBootTest(classes = { GithubEventsListener.class, }) +class GithubEventsListenerTest { + + @MockBean + private ListenerService listenerService; + + @MockBean + private Event, String> event; + + @Autowired + private GithubEventsListener githubEventsListener; + + @Test + void createEvent() { + Map source = new HashMap<>(); + source.put("objectId", "objectId"); + source.put("objectType", "objectType"); + source.put("ruleTitle", "ruleTitle"); + source.put("senderId", "senderId"); + source.put("receiverId", "receiverId"); + source.put("eventDetails", "eventDetails"); + + when(event.getSource()).thenReturn(source); + when(event.getEventName()).thenReturn(GITHUB_ACTION_EVENT); + githubEventsListener.onEvent(event); + verify(listenerService, times(1)).broadcast(GAMIFICATION_GENERIC_EVENT, source, ""); + + when(event.getEventName()).thenReturn(GITHUB_CANCEL_ACTION_EVENT); + githubEventsListener.onEvent(event); + verify(listenerService, times(1)).broadcast(GAMIFICATION_CANCEL_EVENT, source, ""); + } +} diff --git a/gamification-github-services/src/test/java/io/meeds/github/gamification/plugin/GithubConnectorPluginTest.java b/gamification-github-services/src/test/java/io/meeds/github/gamification/plugin/GithubConnectorPluginTest.java new file mode 100644 index 000000000..273764319 --- /dev/null +++ b/gamification-github-services/src/test/java/io/meeds/github/gamification/plugin/GithubConnectorPluginTest.java @@ -0,0 +1,40 @@ +/* + * This file is part of the Meeds project (https://meeds.io/). + * + * Copyright (C) 2020 - 2024 Meeds Lab contact@meedslab.com + * + * 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.github.gamification.plugin; + +import io.meeds.github.gamification.utils.Utils; +import org.junit.Test; +import org.springframework.boot.test.context.SpringBootTest; + +import static org.junit.Assert.assertEquals; + +@SpringBootTest(classes = { GithubConnectorPlugin.class, }) +public class GithubConnectorPluginTest { + + @Test + public void testValidateToken() { + // When + GithubConnectorPlugin githubConnectorPlugin = new GithubConnectorPlugin(); + + // Then + assertEquals(Utils.CONNECTOR_NAME, githubConnectorPlugin.getConnectorName()); + assertEquals(Utils.CONNECTOR_NAME, githubConnectorPlugin.getName()); + } +} diff --git a/gamification-github-services/src/test/java/io/meeds/gamification/github/plugin/GithubEventPluginTest.java b/gamification-github-services/src/test/java/io/meeds/github/gamification/plugin/GithubEventPluginTest.java similarity index 84% rename from gamification-github-services/src/test/java/io/meeds/gamification/github/plugin/GithubEventPluginTest.java rename to gamification-github-services/src/test/java/io/meeds/github/gamification/plugin/GithubEventPluginTest.java index a94257500..546c50ea7 100644 --- a/gamification-github-services/src/test/java/io/meeds/gamification/github/plugin/GithubEventPluginTest.java +++ b/gamification-github-services/src/test/java/io/meeds/github/gamification/plugin/GithubEventPluginTest.java @@ -7,29 +7,32 @@ * 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 + * 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. - * + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package io.meeds.gamification.github.plugin; - -import io.meeds.gamification.github.BaseGithubTest; -import org.junit.Test; +package io.meeds.github.gamification.plugin; import java.util.HashMap; import java.util.List; import java.util.Map; -import static io.meeds.gamification.github.plugin.GithubEventPlugin.EVENT_TYPE; -import static io.meeds.gamification.github.utils.Utils.*; -import static io.meeds.gamification.github.utils.Utils.COMMENT_ISSUE_EVENT_NAME; +import org.junit.Test; +import org.springframework.boot.test.context.SpringBootTest; + +import static io.meeds.github.gamification.plugin.GithubEventPlugin.EVENT_TYPE; +import static io.meeds.github.gamification.utils.Utils.*; +import static io.meeds.github.gamification.utils.Utils.COMMENT_ISSUE_EVENT_NAME; +import static org.junit.Assert.*; -public class GithubEventPluginTest extends BaseGithubTest { +@SpringBootTest(classes = { GithubEventPlugin.class, }) +public class GithubEventPluginTest { @Test public void testIsValidEvent() { diff --git a/gamification-github-services/src/test/java/io/meeds/github/gamification/rest/GithubWebHookRestTest.java b/gamification-github-services/src/test/java/io/meeds/github/gamification/rest/GithubWebHookRestTest.java new file mode 100644 index 000000000..ccda0a25a --- /dev/null +++ b/gamification-github-services/src/test/java/io/meeds/github/gamification/rest/GithubWebHookRestTest.java @@ -0,0 +1,81 @@ +/* + * This file is part of the Meeds project (https://meeds.io/). + * + * Copyright (C) 2020 - 2024 Meeds Lab contact@meedslab.com + * + * 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.github.gamification.rest; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import io.meeds.github.gamification.services.GithubTriggerService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureWebMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultActions; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +import io.meeds.spring.web.security.PortalAuthenticationManager; +import io.meeds.spring.web.security.WebSecurityConfiguration; +import jakarta.servlet.Filter; +import org.springframework.web.context.WebApplicationContext; + +@SpringBootTest(classes = { GithubWebHookRest.class, PortalAuthenticationManager.class, }) +@ContextConfiguration(classes = { WebSecurityConfiguration.class }) +@AutoConfigureWebMvc +@AutoConfigureMockMvc(addFilters = false) +@ExtendWith(MockitoExtension.class) +class GithubWebHookRestTest { + + private static final String REST_PATH = "/webhooks"; // NOSONAR + + @MockBean + private GithubTriggerService githubTriggerService; + + @Autowired + private SecurityFilterChain filterChain; + + @Autowired + private WebApplicationContext context; + + private MockMvc mockMvc; + + @BeforeEach + void setup() { + mockMvc = MockMvcBuilders.webAppContextSetup(context).addFilters(filterChain.getFilters().toArray(new Filter[0])).build(); + } + + @Test + void githubEventAnonymously() throws Exception { + ResultActions response = mockMvc.perform(post(REST_PATH).header("x-github-event", "pushCode") + .header("x-hub-signature", "signature") + .content("content") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)); + response.andExpect(status().isOk()); + } +} diff --git a/gamification-github-services/src/test/java/io/meeds/github/gamification/rest/HooksManagementRestTest.java b/gamification-github-services/src/test/java/io/meeds/github/gamification/rest/HooksManagementRestTest.java new file mode 100644 index 000000000..77238cebe --- /dev/null +++ b/gamification-github-services/src/test/java/io/meeds/github/gamification/rest/HooksManagementRestTest.java @@ -0,0 +1,390 @@ +/* + * This file is part of the Meeds project (https://meeds.io/). + * + * Copyright (C) 2020 - 2024 Meeds Lab contact@meedslab.com + * + * 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.github.gamification.rest; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.when; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.List; + +import io.meeds.github.gamification.model.TokenStatus; +import io.meeds.github.gamification.model.WebHook; +import io.meeds.github.gamification.services.GithubConsumerService; +import io.meeds.github.gamification.services.WebhookService; +import org.exoplatform.commons.ObjectAlreadyExistsException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureWebMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.data.domain.PageImpl; +import org.springframework.http.MediaType; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultActions; +import org.springframework.test.web.servlet.request.RequestPostProcessor; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +import org.exoplatform.commons.exception.ObjectNotFoundException; + +import io.meeds.spring.web.security.PortalAuthenticationManager; +import io.meeds.spring.web.security.WebSecurityConfiguration; +import jakarta.servlet.Filter; + +@SpringBootTest(classes = { HooksManagementRest.class, PortalAuthenticationManager.class, }) +@ContextConfiguration(classes = { WebSecurityConfiguration.class }) +@AutoConfigureWebMvc +@AutoConfigureMockMvc(addFilters = false) +@ExtendWith(MockitoExtension.class) +class HooksManagementRestTest { + + private static final String REST_PATH = "/hooks"; // NOSONAR + + private static final String SIMPLE_USER = "simple"; + + private static final String TEST_PASSWORD = "testPassword"; + + @MockBean + private WebhookService webhookService; + + @MockBean + private GithubConsumerService githubConsumerService; + + @Autowired + private SecurityFilterChain filterChain; + + @Autowired + private WebApplicationContext context; + + private MockMvc mockMvc; + + @BeforeEach + void setup() { + mockMvc = MockMvcBuilders.webAppContextSetup(context).addFilters(filterChain.getFilters().toArray(new Filter[0])).build(); + } + + @Test + void getWebHooksAnonymously() throws Exception { + ResultActions response = mockMvc.perform(get(REST_PATH)); + response.andExpect(status().isForbidden()); + } + + @Test + void getWebHooksSimpleUser() throws Exception { + TokenStatus tokenStatus = new TokenStatus(true, 12L, 15454L); + when(webhookService.getWebhooks(eq(SIMPLE_USER), any())).thenReturn(new PageImpl<>(List.of(newWebHook()))); + when(githubConsumerService.checkGitHubTokenStatus(any())).thenReturn(tokenStatus); + + ResultActions response = mockMvc.perform(get(REST_PATH).with(testSimpleUser())); + response.andExpect(status().isOk()); + + doThrow(new IllegalAccessException()).when(webhookService).getWebhooks(eq(SIMPLE_USER), any()); + + response = mockMvc.perform(get(REST_PATH).with(testSimpleUser())); + response.andExpect(status().isUnauthorized()); + } + + @Test + void getWebHookByIdAnonymously() throws Exception { + ResultActions response = mockMvc.perform(get(REST_PATH + "/1")); + response.andExpect(status().isForbidden()); + } + + @Test + void getWebHookByIdSimpleUser() throws Exception { + TokenStatus tokenStatus = new TokenStatus(true, 12L, 15454L); + when(webhookService.getWebhooks(eq(SIMPLE_USER), any())).thenReturn(new PageImpl<>(List.of(newWebHook()))); + when(githubConsumerService.checkGitHubTokenStatus(any())).thenReturn(tokenStatus); + ResultActions response = mockMvc.perform(get(REST_PATH + "/1").with(testSimpleUser())); + response.andExpect(status().isOk()); + + response = mockMvc.perform(get(REST_PATH + "/0").with(testSimpleUser())); + response.andExpect(status().isBadRequest()); + + doThrow(new IllegalAccessException()).when(webhookService).getWebhookId(1, SIMPLE_USER); + + response = mockMvc.perform(get(REST_PATH + "/1").with(testSimpleUser())); + response.andExpect(status().isUnauthorized()); + + doThrow(new IllegalArgumentException()).when(webhookService).getWebhookId(1, SIMPLE_USER); + + response = mockMvc.perform(get(REST_PATH + "/1").with(testSimpleUser())); + response.andExpect(status().isBadRequest()); + + doThrow(new ObjectNotFoundException("Webhook doesn't exist")).when(webhookService).getWebhookId(1, SIMPLE_USER); + + response = mockMvc.perform(get(REST_PATH + "/1").with(testSimpleUser())); + response.andExpect(status().isNotFound()); + } + + @Test + void createWebhookHookAnonymously() throws Exception { + ResultActions response = mockMvc.perform(post(REST_PATH).param("organizationName", "organizationName") + .param("accessToken", "accessToken") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)); + response.andExpect(status().isForbidden()); + } + + @Test + void createWebhookHookSimpleUser() throws Exception { + ResultActions response = mockMvc.perform(post(REST_PATH).param("accessToken", "accessToken") + .param("organizationName", "") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .with(testSimpleUser())); + + response.andExpect(status().isBadRequest()); + + response = mockMvc.perform(post(REST_PATH).param("organizationName", "organizationName") + .param("accessToken", "") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .with(testSimpleUser())); + + response.andExpect(status().isBadRequest()); + + response = mockMvc.perform(post(REST_PATH).param("organizationName", "organizationName") + .param("accessToken", "accessToken") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .with(testSimpleUser())); + + response.andExpect(status().isOk()); + + doThrow(new IllegalAccessException()).when(webhookService).createWebhook("organizationName", "accessToken", SIMPLE_USER); + + response = mockMvc.perform(post(REST_PATH).param("organizationName", "organizationName") + .param("accessToken", "accessToken") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .with(testSimpleUser())); + + response.andExpect(status().isUnauthorized()); + + doThrow(new ObjectAlreadyExistsException(newWebHook())).when(webhookService) + .createWebhook("organizationName", "accessToken", SIMPLE_USER); + + response = mockMvc.perform(post(REST_PATH).param("organizationName", "organizationName") + .param("accessToken", "accessToken") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .with(testSimpleUser())); + + response.andExpect(status().isConflict()); + + doThrow(new ObjectNotFoundException("github.organizationNotFound")).when(webhookService) + .createWebhook("organizationName", + "accessToken", + SIMPLE_USER); + + response = mockMvc.perform(post(REST_PATH).param("organizationName", "organizationName") + .param("accessToken", "accessToken") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .with(testSimpleUser())); + + response.andExpect(status().isNotFound()); + } + + @Test + void updateWebHookAccessTokenAnonymously() throws Exception { + ResultActions response = mockMvc.perform(patch(REST_PATH + "/1").param("accessToken", "accessToken") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)); + response.andExpect(status().isForbidden()); + } + + @Test + void updateWebHookAccessTokenSimpleUser() throws Exception { + ResultActions response = mockMvc.perform(patch(REST_PATH + "/-1").param("accessToken", "accessToken") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .with(testSimpleUser())); + + response.andExpect(status().isBadRequest()); + + response = mockMvc.perform(patch(REST_PATH + "/1").param("accessToken", "") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .with(testSimpleUser())); + + response.andExpect(status().isBadRequest()); + + response = mockMvc.perform(patch(REST_PATH + "/1").param("accessToken", "accessToken") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .with(testSimpleUser())); + + response.andExpect(status().isOk()); + + doThrow(new IllegalAccessException()).when(webhookService).updateWebHookAccessToken(1L, "accessToken", SIMPLE_USER); + + response = mockMvc.perform(patch(REST_PATH + "/1").param("accessToken", "accessToken") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .with(testSimpleUser())); + + response.andExpect(status().isUnauthorized()); + + doThrow(new ObjectNotFoundException("github.organizationNotFound")).when(webhookService) + .updateWebHookAccessToken(1L, "accessToken", SIMPLE_USER); + + response = mockMvc.perform(patch(REST_PATH + "/1").param("accessToken", "accessToken") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .with(testSimpleUser())); + + response.andExpect(status().isNotFound()); + } + + @Test + void deleteWebhookAnonymously() throws Exception { + ResultActions response = mockMvc.perform(delete(REST_PATH + "/" + 1).contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)); + response.andExpect(status().isForbidden()); + } + + @Test + void deleteWebhookSimpleUser() throws Exception { + ResultActions response = mockMvc.perform(delete(REST_PATH + "/" + 1).with(testSimpleUser()) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)); + response.andExpect(status().isOk()); + + doThrow(new IllegalAccessException()).when(webhookService).deleteWebhook(1, SIMPLE_USER); + + response = mockMvc.perform(delete(REST_PATH + "/" + 1).with(testSimpleUser()) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)); + response.andExpect(status().isUnauthorized()); + + doThrow(new ObjectNotFoundException("github.organizationNotFound")).when(webhookService).deleteWebhook(1, SIMPLE_USER); + + response = mockMvc.perform(delete(REST_PATH + "/" + 1).with(testSimpleUser()) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)); + response.andExpect(status().isNotFound()); + } + + @Test + void getWebHookReposAnonymously() throws Exception { + ResultActions response = mockMvc.perform(get(REST_PATH + "/" + 1 + "/repos").param("page", "1") + .param("perPage", "5") + .param("keyword", "keyword")); + response.andExpect(status().isForbidden()); + } + + @Test + void getWebHookReposSimpleUser() throws Exception { + + ResultActions response = mockMvc.perform(get(REST_PATH + "/" + 1 + "/repos").param("page", "1") + .param("perPage", "5") + .param("keyword", "keyword") + .with(testSimpleUser())); + response.andExpect(status().isOk()); + + doThrow(new IllegalAccessException()).when(webhookService).retrieveOrganizationRepos(1, SIMPLE_USER, 1, 5, "keyword"); + + response = mockMvc.perform(get(REST_PATH + "/" + 1 + "/repos").param("page", "1") + .param("perPage", "5") + .param("keyword", "keyword") + .with(testSimpleUser())); + response.andExpect(status().isUnauthorized()); + + doThrow(new ObjectNotFoundException("github.organizationNotFound")).when(webhookService) + .retrieveOrganizationRepos(1, + SIMPLE_USER, + 1, + 5, + "keyword"); + + response = mockMvc.perform(get(REST_PATH + "/" + 1 + "/repos").param("page", "1") + .param("perPage", "5") + .param("keyword", "keyword") + .with(testSimpleUser())); + response.andExpect(status().isNotFound()); + } + + @Test + void updateWebHookRepoStatusAnonymously() throws Exception { + ResultActions response = mockMvc.perform(post(REST_PATH + "/repo/status").param("organizationId", "1") + .param("repositoryId", "125") + .param("enabled", "false") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)); + response.andExpect(status().isForbidden()); + } + + @Test + void updateWebHookRepoStatusSimpleUser() throws Exception { + ResultActions response = mockMvc.perform(post(REST_PATH + "/repo/status").param("organizationId", "1") + .param("repositoryId", "125") + .param("enabled", "false") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .with(testSimpleUser())); + + response.andExpect(status().isOk()); + + doThrow(new IllegalAccessException()).when(webhookService).setWebHookRepositoryEnabled(1L, 125L, false, SIMPLE_USER); + + response = mockMvc.perform(post(REST_PATH + "/repo/status").param("organizationId", "1") + .param("repositoryId", "125") + .param("enabled", "false") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .with(testSimpleUser())); + + response.andExpect(status().isUnauthorized()); + } + + private RequestPostProcessor testSimpleUser() { + return user(SIMPLE_USER).password(TEST_PASSWORD).authorities(new SimpleGrantedAuthority("users")); + } + + private WebHook newWebHook() { + return new WebHook(1, + 1234, + 12345, + "organizationName", + List.of("trigger1", "trigger2"), + true, + "watchedDate", + "watchedBy", + "updatedDate", + "refreshDate", + "token", + "secret"); + } + +} diff --git a/gamification-github-services/src/test/java/io/meeds/github/gamification/service/WebhookServiceTest.java b/gamification-github-services/src/test/java/io/meeds/github/gamification/service/WebhookServiceTest.java new file mode 100644 index 000000000..6748a0453 --- /dev/null +++ b/gamification-github-services/src/test/java/io/meeds/github/gamification/service/WebhookServiceTest.java @@ -0,0 +1,209 @@ +/* + * This file is part of the Meeds project (https://meeds.io/). + * + * Copyright (C) 2020 - 2023 Meeds Lab contact@meedslab.com + * + * 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.github.gamification.service; + +import static io.meeds.github.gamification.utils.Utils.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import io.meeds.gamification.model.filter.RuleFilter; +import io.meeds.gamification.service.RuleService; +import io.meeds.github.gamification.model.RemoteOrganization; +import io.meeds.github.gamification.model.TokenStatus; +import io.meeds.github.gamification.model.WebHook; +import io.meeds.github.gamification.services.GithubConsumerService; +import io.meeds.github.gamification.services.WebhookService; +import io.meeds.github.gamification.services.impl.WebhookServiceImpl; +import io.meeds.github.gamification.storage.WebHookStorage; +import org.exoplatform.commons.ObjectAlreadyExistsException; +import org.exoplatform.commons.api.settings.SettingService; +import org.exoplatform.commons.api.settings.data.Context; +import org.exoplatform.commons.api.settings.data.Scope; +import org.exoplatform.commons.exception.ObjectNotFoundException; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.data.domain.Pageable; + +@SpringBootTest(classes = { WebhookServiceImpl.class }) +class WebhookServiceTest { + + private static final String ADMIN_USER = "root"; + + private static final String USER = "user"; + + private static final Pageable PAGEABLE = Pageable.ofSize(2); + + @MockBean + private GithubConsumerService githubConsumerService; + + @MockBean + private WebHookStorage webHookStorage; + + @MockBean + private RuleService ruleService; + + @MockBean + private SettingService settingService; + + @Autowired + private WebhookService webhookService; + + @Test + void testGetWebhooks() throws Exception { + Throwable exception = assertThrows(IllegalAccessException.class, () -> webhookService.getWebhooks(USER, PAGEABLE)); + assertEquals(AUTHORIZED_TO_ACCESS_GIT_HUB_HOOKS, exception.getMessage()); + + webhookService.getWebhooks(ADMIN_USER, PAGEABLE); + verify(webHookStorage, times(1)).getWebhooks(PAGEABLE); + } + + @Test + void testGetWebhookId() throws Exception { + Throwable exception = assertThrows(IllegalAccessException.class, () -> webhookService.getWebhookId(1L, USER)); + assertEquals(AUTHORIZED_TO_ACCESS_GIT_HUB_HOOKS, exception.getMessage()); + + exception = assertThrows(IllegalArgumentException.class, () -> webhookService.getWebhookId(0L, ADMIN_USER)); + assertEquals("Webhook id is mandatory", exception.getMessage()); + + when(webHookStorage.getWebHookById(2L)).thenReturn(new WebHook()); + webhookService.getWebhookId(2L, ADMIN_USER); + verify(webHookStorage, times(1)).getWebHookById(2L); + + when(webHookStorage.getWebHookById(1L)).thenReturn(null); + exception = assertThrows(ObjectNotFoundException.class, () -> webhookService.getWebhookId(1L, ADMIN_USER)); + assertEquals("Webhook doesn't exist", exception.getMessage()); + } + + @Test + void testCreateWebhook() throws Exception { + + Throwable exception = assertThrows(IllegalAccessException.class, + () -> webhookService.createWebhook("organizationName", "accessToken", USER)); + assertEquals("The user is not authorized to create GitHub hook", exception.getMessage()); + + TokenStatus tokenStatus = new TokenStatus(false, 12L, 15454L); + when(githubConsumerService.checkGitHubTokenStatus(any())).thenReturn(tokenStatus); + + exception = assertThrows(IllegalAccessException.class, + () -> webhookService.createWebhook("organizationName", "accessToken", ADMIN_USER)); + assertEquals("github.tokenExpiredOrInvalid", exception.getMessage()); + + tokenStatus.setValid(true); + tokenStatus.setRemaining(0L); + when(githubConsumerService.checkGitHubTokenStatus(any())).thenReturn(tokenStatus); + + exception = assertThrows(IllegalAccessException.class, + () -> webhookService.createWebhook("organizationName", "accessToken", ADMIN_USER)); + assertEquals("github.tokenRateLimitReached", exception.getMessage()); + + RemoteOrganization remoteOrganization = new RemoteOrganization(12345, "name", "title", "description", "avatarUrl"); + WebHook existsWebHook = new WebHook(); + when(githubConsumerService.retrieveRemoteOrganization("organizationName", "accessToken")).thenReturn(remoteOrganization); + when(webHookStorage.getWebhookByOrganizationId(12345)).thenReturn(existsWebHook); + tokenStatus.setRemaining(1221544L); + when(githubConsumerService.checkGitHubTokenStatus(any())).thenReturn(tokenStatus); + + assertThrows(ObjectAlreadyExistsException.class, + () -> webhookService.createWebhook("organizationName", "accessToken", ADMIN_USER)); + + when(webHookStorage.getWebhookByOrganizationId(12345)).thenReturn(null); + WebHook webHook = new WebHook(); + + when(githubConsumerService.createWebhook("organizationName", GITHUB_TRIGGERS, "accessToken")).thenReturn(webHook); + + webHook.setOrganizationId(remoteOrganization.getId()); + webHook.setWatchedBy(ADMIN_USER); + webhookService.createWebhook("organizationName", "accessToken", ADMIN_USER); + verify(webHookStorage, times(1)).saveWebHook(webHook); + } + + @Test + void testUpdateWebHookAccessToken() throws Exception { + Throwable exception = assertThrows(IllegalAccessException.class, + () -> webhookService.updateWebHookAccessToken(124L, "accessToken", USER)); + assertEquals(AUTHORIZED_TO_ACCESS_GIT_HUB_HOOKS, exception.getMessage()); + + exception = assertThrows(IllegalArgumentException.class, + () -> webhookService.updateWebHookAccessToken(0L, "accessToken", ADMIN_USER)); + assertEquals("webHook id must be positive", exception.getMessage()); + + when(webHookStorage.getWebHookById(2L)).thenReturn(new WebHook()); + webhookService.updateWebHookAccessToken(2L, "accessToken", ADMIN_USER); + verify(webHookStorage, times(1)).updateWebHookAccessToken(anyLong(), anyString()); + + when(webHookStorage.getWebHookById(1L)).thenReturn(null); + exception = assertThrows(ObjectNotFoundException.class, + () -> webhookService.updateWebHookAccessToken(1L, "accessToken", ADMIN_USER)); + assertEquals("webhook with id : 1 wasn't found", exception.getMessage()); + } + + @Test + void testDeleteWebhook() throws ObjectNotFoundException, IllegalAccessException { + Throwable exception = assertThrows(IllegalAccessException.class, () -> webhookService.deleteWebhook(124L, USER)); + assertEquals("The user is not authorized to delete GitHub hook", exception.getMessage()); + + when(webHookStorage.getWebhookByOrganizationId(124L)).thenReturn(null); + exception = assertThrows(ObjectNotFoundException.class, () -> webhookService.deleteWebhook(124L, ADMIN_USER)); + assertEquals("Github hook for organization id : 124 wasn't found", exception.getMessage()); + + WebHook webHook = new WebHook(); + when(webHookStorage.getWebhookByOrganizationId(124L)).thenReturn(webHook); + when(githubConsumerService.deleteWebhook(webHook)).thenReturn("Deleted"); + + webhookService.deleteWebhook(124L, ADMIN_USER); + verify(webHookStorage, times(1)).deleteWebHook(124L); + RuleFilter ruleFilter = new RuleFilter(true); + ruleFilter.setEventType(CONNECTOR_NAME); + ruleFilter.setIncludeDeleted(true); + verify(ruleService, times(1)).getRules(ruleFilter, 0, -1); + } + + @Test + void testVerifyWebhookSecret() { + String payload = "{\"organization\":{\"id\":\"14524\"},\"repository\":{\"id\":\"555564545\"}}"; + + when(webHookStorage.getWebhookByOrganizationId(14524L)).thenReturn(null); + assertFalse(webhookService.verifyWebhookSecret(payload, "signature")); + } + + @Test + void testIsWebHookRepositoryEnabled() throws Exception { + // When + String payload = "{\"organization\":{\"id\":\"14524\"},\"repository\":{\"id\":\"555564545\"}}"; + + // Then + assertTrue(webhookService.isWebHookRepositoryEnabled(payload)); + + // When + Exception exception = assertThrows(IllegalAccessException.class, + () -> webhookService.setWebHookRepositoryEnabled(14525L, 555564545L, false, USER)); + assertEquals("The user is not authorized to update repository status", exception.getMessage()); + + webhookService.setWebHookRepositoryEnabled(14524L, 555564545L, false, ADMIN_USER); + verify(settingService, times(2)).get(Context.GLOBAL.id("githubWebhook"), Scope.APPLICATION.id("disabledRepos"), "14524"); + verify(settingService, times(1)).set(any(), any(), anyString(), any()); + + webhookService.isWebHookRepositoryEnabled(payload); + + webhookService.setWebHookRepositoryEnabled(145211L, 555564545L, true, ADMIN_USER); + verify(settingService, times(1)).get(Context.GLOBAL.id("githubWebhook"), Scope.APPLICATION.id("disabledRepos"), "145211"); + } +} diff --git a/gamification-github-services/src/test/java/io/meeds/github/gamification/storage/WebHookStorageTest.java b/gamification-github-services/src/test/java/io/meeds/github/gamification/storage/WebHookStorageTest.java new file mode 100644 index 000000000..4ec1a6816 --- /dev/null +++ b/gamification-github-services/src/test/java/io/meeds/github/gamification/storage/WebHookStorageTest.java @@ -0,0 +1,134 @@ +/* + * This file is part of the Meeds project (https://meeds.io/). + * + * Copyright (C) 2020 - 2023 Meeds Lab contact@meedslab.com + * + * 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.github.gamification.storage; + +import static org.junit.Assert.assertThrows; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; +import static org.mockito.Mockito.when; + +import java.util.List; +import java.util.Optional; + +import io.meeds.github.gamification.dao.WebHookDAO; +import io.meeds.github.gamification.entity.WebhookEntity; +import io.meeds.github.gamification.model.WebHook; +import org.exoplatform.commons.api.settings.SettingService; +import org.exoplatform.web.security.codec.CodecInitializer; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; + +import org.exoplatform.commons.ObjectAlreadyExistsException; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.Pageable; + +@SpringBootTest(classes = { WebHookStorage.class, }) +@ExtendWith(MockitoExtension.class) +class WebHookStorageTest { + + private static final Long ID = 2L; + + private static final Long ORGANIZATION_ID = 1232L; + + private static final Pageable PAGEABLE = Pageable.ofSize(2); + + @Autowired + private WebHookStorage webHookStorage; + + @MockBean + private WebHookDAO webHookDAO; + + @MockBean + private SettingService settingService; + + @MockBean + private CodecInitializer codecInitializer; + + @BeforeEach + void setup() { + when(webHookDAO.save(any())).thenAnswer(invocation -> { + WebhookEntity entity = invocation.getArgument(0); + if (entity.getId() == null) { + entity.setId(ID); + } + when(webHookDAO.findById(ID)).thenReturn(Optional.of(entity)); + when(webHookDAO.findWebhookEntityByOrganizationId(ORGANIZATION_ID)).thenReturn(entity); + when(webHookDAO.findAll(PAGEABLE)).thenReturn(new PageImpl<>(List.of(entity))); + when(webHookDAO.count()).thenReturn(1L); + return entity; + }); + doAnswer(invocation -> { + WebhookEntity entity = invocation.getArgument(0); + when(webHookDAO.findById(entity.getId())).thenReturn(Optional.empty()); + return null; + }).when(webHookDAO).delete(any()); + } + + @Test + void testAddWebHook() throws Exception { + // Given + WebHook webHook = createWebHookInstance(); + + // When + WebHook createdWebHook = webHookStorage.saveWebHook(webHook); + + // Then + assertNotNull(createdWebHook); + assertEquals(createdWebHook.getEnabled(), webHook.getEnabled()); + assertEquals(createdWebHook.getOrganizationName(), webHook.getOrganizationName()); + assertEquals(createdWebHook.getOrganizationId(), webHook.getOrganizationId()); + + assertThrows(ObjectAlreadyExistsException.class, () -> webHookStorage.saveWebHook(webHook)); + } + + @Test + void testGetWebHooks() throws Exception { + // Given + WebHook webHook = createWebHookInstance(); + + // When + WebHook createdWebHook = webHookStorage.saveWebHook(webHook); + + // Then + assertNotNull(createdWebHook); + assertEquals(new PageImpl<>(List.of(createdWebHook)), webHookStorage.getWebhooks(PAGEABLE)); + assertEquals(1L, webHookStorage.countWebhooks()); + } + + protected WebHook createWebHookInstance() { + return new WebHook(0, + 1234, + ORGANIZATION_ID, + "organizationName", + List.of("trigger"), + true, + "watchedDate", + null, + "updatedDate", + "refreshDate", + "token", + "secret"); + } +} diff --git a/gamification-github-services/src/test/resources/conf/portal/github-test-configuration.xml b/gamification-github-services/src/test/resources/conf/portal/github-test-configuration.xml index b0c0b76e9..498680d74 100644 --- a/gamification-github-services/src/test/resources/conf/portal/github-test-configuration.xml +++ b/gamification-github-services/src/test/resources/conf/portal/github-test-configuration.xml @@ -25,32 +25,32 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. org.exoplatform.social.core.manager.IdentityManager - io.meeds.gamification.github.mock.IdentityManagerMock + io.meeds.github.gamification.mock.IdentityManagerMock io.meeds.gamification.service.RuleService - io.meeds.gamification.github.mock.RuleServiceMock + io.meeds.github.gamification.mock.RuleServiceMock io.meeds.gamification.service.ConnectorService - io.meeds.gamification.github.mock.ConnectorServiceMock + io.meeds.github.gamification.mock.ConnectorServiceMock io.meeds.gamification.service.ConnectorSettingService - io.meeds.gamification.github.mock.ConnectorSettingServiceMock + io.meeds.github.gamification.mock.ConnectorSettingServiceMock io.meeds.gamification.service.EventService - io.meeds.gamification.github.mock.EventServiceMock + io.meeds.github.gamification.mock.EventServiceMock io.meeds.gamification.service.TriggerService - io.meeds.gamification.github.mock.TriggerServiceMock + io.meeds.github.gamification.mock.TriggerServiceMock diff --git a/gamification-github-webapp/pom.xml b/gamification-github-webapp/pom.xml index 38d593c53..df23d4ef0 100644 --- a/gamification-github-webapp/pom.xml +++ b/gamification-github-webapp/pom.xml @@ -30,6 +30,11 @@ war Gamification - Github Connector - Webapp + + ${project.groupId} + gamification-github-services + provided + io.meeds.platform-ui platform-ui-skin diff --git a/gamification-github-webapp/src/main/java/io/meeds/github/gamification/GamificationGithubApplication.java b/gamification-github-webapp/src/main/java/io/meeds/github/gamification/GamificationGithubApplication.java new file mode 100644 index 000000000..31b61aec4 --- /dev/null +++ b/gamification-github-webapp/src/main/java/io/meeds/github/gamification/GamificationGithubApplication.java @@ -0,0 +1,44 @@ +/* + * This file is part of the Meeds project (https://meeds.io/). + * + * Copyright (C) 2020 - 2024 Meeds Lab contact@meedslab.com + * + * 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.github.gamification; + +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.PropertySource; + +import io.meeds.spring.AvailableIntegration; +import io.meeds.spring.kernel.PortalApplicationContextInitializer; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; + +@SpringBootApplication(scanBasePackages = { + GamificationGithubApplication.MODULE_NAME, + AvailableIntegration.KERNEL_MODULE, + AvailableIntegration.JPA_MODULE, + AvailableIntegration.LIQUIBASE_MODULE, + AvailableIntegration.WEB_MODULE, + }) +@EnableCaching +@EnableJpaRepositories(basePackages = GamificationGithubApplication.MODULE_NAME) +@PropertySource("classpath:application.properties") +@PropertySource("classpath:application-common.properties") +@PropertySource("classpath:github.properties") +public class GamificationGithubApplication extends PortalApplicationContextInitializer { + + public static final String MODULE_NAME = "io.meeds.github.gamification"; +} diff --git a/gamification-github-webapp/src/main/resources/github.properties b/gamification-github-webapp/src/main/resources/github.properties new file mode 100644 index 000000000..4c1ca43ac --- /dev/null +++ b/gamification-github-webapp/src/main/resources/github.properties @@ -0,0 +1,20 @@ +# +# This file is part of the Meeds project (https://meeds.io/). +# +# Copyright (C) 2020 - 2024 Meeds Lab contact@meedslab.com +# +# 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. + +spring.liquibase.change-log=classpath:db/changelog/github-connector.db.changelog-1.0.0.xml diff --git a/gamification-github-webapp/src/main/webapp/html/gitHubWebHookManagement.html b/gamification-github-webapp/src/main/webapp/html/gitHubWebHookManagement.html deleted file mode 100644 index db9519b90..000000000 --- a/gamification-github-webapp/src/main/webapp/html/gitHubWebHookManagement.html +++ /dev/null @@ -1,7 +0,0 @@ -
-
- -
-
\ No newline at end of file diff --git a/gamification-github-webapp/src/main/webapp/skin/less/gitHubWebHookManagement.less b/gamification-github-webapp/src/main/webapp/skin/less/gitHubWebHookManagement.less deleted file mode 100644 index 24b8b91dd..000000000 --- a/gamification-github-webapp/src/main/webapp/skin/less/gitHubWebHookManagement.less +++ /dev/null @@ -1,144 +0,0 @@ -@import "./variables.less"; - -#gitHubWebHookManagementApp { - - /* switch */ - .switch { - position: relative; - display: inline-block; - width: 53px; - height: 32px; - /* zoom: 30%; */ - top: 0.4rem; - } - - .switch input { - display: none; - } - - .slider { - position: absolute; - cursor: pointer; - overflow: hidden; - top: 5px; - left: 0; - right: 0; - bottom: 0; - width: 60px; - height: 20px; - background-color: #f2f2f2; - -webkit-transition: .4s; - transition: .4s; - } - - .slider:before { - position: absolute; - z-index: 2; - content: ""; - height: 14px; - width: 14px; - left: 5px; - bottom: 3px; - background-color: darkgrey; - -webkit-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.22); - box-shadow: 0 2px 5px rgba(0, 0, 0, 0.22); - -webkit-transition: .4s; - transition: all 0.4s ease-in-out; - } - - .slider:after { - position: absolute; - left: -20px; - z-index: 1; - content: "YES"; - font-size: 13px; - text-align: left !important; - line-height: 19px; - padding-left: 0; - width: 95px; - height: 26px !important; - color: #f9f9f9; - background-color: #477ab3; - background-image: -moz-linear-gradient(top, #578dc9, #2f5e92); - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#578dc9), to(#2f5e92)); - background-image: -webkit-linear-gradient(top, #578dc9, #2f5e92); - background-image: -o-linear-gradient(top, #578dc9, #2f5e92); - background-image: linear-gradient(to bottom, #578dc9, #2f5e92); - background-repeat: repeat-x; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff578dc9', endColorstr='#ff2f5e92', GradientType=0); - -webkit-box-shadow: inset 0px 3px 5px #224469; - -moz-box-shadow: inset 0px 3px 5px #224469; - box-shadow: inset 0px 3px 5px #224469; - -webkit-border-top-left-radius: 9px; - -moz-border-radius-topleft: 9px; - border-top-left-radius: 9px; - -webkit-border-bottom-left-radius: 9px; - -moz-border-radius-bottomleft: 9px; - border-bottom-left-radius: 9px; - height: 57px; - border-radius: 100px; - background-color: #578dc9; - -webkit-transform: translateX(-190px); - -ms-transform: translateX(-190px); - transform: translateX(-190px); - transition: all 0.4s ease-in-out; - } - - input:checked+.slider:after { - -webkit-transform: translateX(0px); - -ms-transform: translateX(0px); - transform: translateX(0px); - padding-left: 25px; - } - - input:checked+.slider:before { - background-color: #fff; - -webkit-transform: translateX(38px); - -ms-transform: translateX(38px); - transform: translateX(38px); - } - - input:checked+.slider:before { - -webkit-transform: translateX(38px); - -ms-transform: translateX(38px); - transform: translateX(38px); - } - - /* Rounded sliders */ - .slider.round { - border-radius: 100px; - } - - .slider.round:before { - border-radius: 50%; - } - - .absolute-no { - position: absolute; - left: 27px; - color: DarkGrey; - text-align: right !important; - font-size: 16px; - width: calc(100% - 25px); - line-height: 30px; - cursor: pointer; - } - - .container { - flex: 1 1 100%; - padding: 0px !important; - width: 100%; - } - - .v-text-field__slot { - display: flex; - flex: 1 1 auto; - position: relative; - border: none !important; - border-radius: 2px; - } - - .theme--light.v-data-table { - width: 100% !important; - } -} \ No newline at end of file diff --git a/gamification-github-webapp/src/main/webapp/vue-app/connectorEventExtensions/components/GithubEventForm.vue b/gamification-github-webapp/src/main/webapp/vue-app/connectorEventExtensions/components/GithubEventForm.vue index 094daca3e..3b51f7970 100644 --- a/gamification-github-webapp/src/main/webapp/vue-app/connectorEventExtensions/components/GithubEventForm.vue +++ b/gamification-github-webapp/src/main/webapp/vue-app/connectorEventExtensions/components/GithubEventForm.vue @@ -126,9 +126,12 @@ export default { methods: { retrieveOrganizations() { this.loadingOrganizations = true; - return this.$githubConnectorService.getGithubWebHooks() + return this.$githubConnectorService.getGithubWebHooks({ + page: 0, + size: 5, + }) .then(data => { - this.organizations = data.webhooks; + this.organizations = data?._embedded?.webHookRestEntityList; }).finally(() => { if (this.properties) { this.selected = this.organizations.find(r => Number(r.organizationId) === Number(this.properties.organizationId)); diff --git a/gamification-github-webapp/src/main/webapp/vue-app/githubAdminConnectorExtension/components/GithubAdminConnectorHookList.vue b/gamification-github-webapp/src/main/webapp/vue-app/githubAdminConnectorExtension/components/GithubAdminConnectorHookList.vue index e01b15a88..55d71bede 100644 --- a/gamification-github-webapp/src/main/webapp/vue-app/githubAdminConnectorExtension/components/GithubAdminConnectorHookList.vue +++ b/gamification-github-webapp/src/main/webapp/vue-app/githubAdminConnectorExtension/components/GithubAdminConnectorHookList.vue @@ -105,10 +105,13 @@ export default { methods: { refreshHooks() { this.loading = true; - return this.$githubConnectorService.getGithubWebHooks(this.offset, this.limit) + return this.$githubConnectorService.getGithubWebHooks({ + page: 0, + size: 5, + }) .then(data => { - this.hooks = data.webhooks; - this.hooksCount = data.size || 0; + this.hooks = data?._embedded?.webHookRestEntityList; + this.hooksCount = data?.page?.totalElements || 0; return this.$nextTick() .then(() => { this.$emit('updated', this.hooks); diff --git a/gamification-github-webapp/src/main/webapp/vue-app/githubAdminConnectorExtension/initComponents.js b/gamification-github-webapp/src/main/webapp/vue-app/githubAdminConnectorExtension/initComponents.js index fe898300c..d9e63a1b0 100644 --- a/gamification-github-webapp/src/main/webapp/vue-app/githubAdminConnectorExtension/initComponents.js +++ b/gamification-github-webapp/src/main/webapp/vue-app/githubAdminConnectorExtension/initComponents.js @@ -1,7 +1,7 @@ /* * This file is part of the Meeds project (https://meeds.io/). * - * Copyright (C) 2020 - 2023 Meeds Association contact@meedslab.com + * Copyright (C) 2020 - 2023 Meeds Lab contact@meedslab.com * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public diff --git a/gamification-github-webapp/src/main/webapp/vue-app/githubAdminConnectorExtension/js/GithubConnectorService.js b/gamification-github-webapp/src/main/webapp/vue-app/githubAdminConnectorExtension/js/GithubConnectorService.js index 944cb3f00..a8c5e8b0d 100644 --- a/gamification-github-webapp/src/main/webapp/vue-app/githubAdminConnectorExtension/js/GithubConnectorService.js +++ b/gamification-github-webapp/src/main/webapp/vue-app/githubAdminConnectorExtension/js/GithubConnectorService.js @@ -17,8 +17,20 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -export function getGithubWebHooks(offset, limit) { - return fetch(`${eXo.env.portal.context}/${eXo.env.portal.rest}/gamification/connectors/github/hooks?offset=${offset || 0}&limit=${limit|| 10}&returnSize=true`, { +export function getGithubWebHooks(paramsObj) { + const formData = new FormData(); + if (paramsObj) { + Object.keys(paramsObj).forEach(key => { + const value = paramsObj[key]; + if (window.Array && Array.isArray && Array.isArray(value)) { + value.forEach(val => formData.append(key, val)); + } else { + formData.append(key, value); + } + }); + } + const params = new URLSearchParams(formData).toString(); + return fetch(`/gamification-github/rest/hooks?${params}`, { method: 'GET', credentials: 'include', }).then((resp) => { @@ -31,7 +43,7 @@ export function getGithubWebHooks(offset, limit) { } export function getGithubWebHookById(hookId) { - return fetch(`${eXo.env.portal.context}/${eXo.env.portal.rest}/gamification/connectors/github/hooks/${hookId}`, { + return fetch(`/gamification-github/rest/hooks/${hookId}`, { method: 'GET', credentials: 'include', }).then((resp) => { @@ -47,7 +59,7 @@ export function saveGithubWebHook(organizationName, accessToken) { const formData = new FormData(); formData.append('organizationName', organizationName); formData.append('accessToken', accessToken); - return fetch(`${eXo.env.portal.context}/${eXo.env.portal.rest}/gamification/connectors/github/hooks`, { + return fetch('/gamification-github/rest/hooks', { method: 'POST', credentials: 'include', headers: { @@ -69,9 +81,8 @@ export function saveGithubWebHook(organizationName, accessToken) { export function updateWebHookAccessToken(webHookId, accessToken) { const formData = new FormData(); - formData.append('webHookId', webHookId); formData.append('accessToken', accessToken); - return fetch(`${eXo.env.portal.context}/${eXo.env.portal.rest}/gamification/connectors/github/hooks`, { + return fetch(`/gamification-github/rest/hooks/${webHookId}`, { method: 'PATCH', credentials: 'include', headers: { @@ -86,7 +97,7 @@ export function updateWebHookAccessToken(webHookId, accessToken) { } export function deleteGithubWebHook(organizationId) { - return fetch(`${eXo.env.portal.context}/${eXo.env.portal.rest}/gamification/connectors/github/hooks/${organizationId}`, { + return fetch(`/gamification-github/rest/hooks/${organizationId}`, { method: 'DELETE', credentials: 'include', }).then(resp => { @@ -97,7 +108,7 @@ export function deleteGithubWebHook(organizationId) { } export function getWebHookRepos(organizationId, page, perPage, keyword) { - return fetch(`${eXo.env.portal.context}/${eXo.env.portal.rest}/gamification/connectors/github/hooks/${organizationId}/repos?page=${page || 0}&perPage=${perPage|| 10}&keyword=${keyword || ''}`, { + return fetch(`/gamification-github/rest/hooks/${organizationId}/repos?page=${page || 0}&perPage=${perPage|| 10}&keyword=${keyword || ''}`, { method: 'GET', credentials: 'include', }).then((resp) => { @@ -115,25 +126,7 @@ export function saveRepositoryStatus(repositoryId, organizationId, enabled) { formData.append('organizationId', organizationId); formData.append('enabled', enabled); - return fetch(`${eXo.env.portal.context}/${eXo.env.portal.rest}/gamification/connectors/github/hooks/repo/status`, { - method: 'POST', - credentials: 'include', - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - }, - body: new URLSearchParams(formData).toString(), - }).then(resp => { - if (!resp?.ok) { - throw new Error('Response code indicates a server error', resp); - } - }); -} - -export function enableDisableWatchScope(organizationId, enabled) { - const formData = new FormData(); - formData.append('organizationId', organizationId); - formData.append('enabled', enabled); - return fetch(`${eXo.env.portal.context}/${eXo.env.portal.rest}/gamification/connectors/github/hooks/watchScope/status`, { + return fetch('/gamification-github/rest/hooks/repo/status', { method: 'POST', credentials: 'include', headers: { @@ -148,7 +141,7 @@ export function enableDisableWatchScope(organizationId, enabled) { } export function forceUpdateWebhooks() { - return fetch(`${eXo.env.portal.context}/${eXo.env.portal.rest}/gamification/connectors/github/hooks/forceUpdate`, { + return fetch('/gamification-github/rest/hooks/forceUpdate', { method: 'PATCH', credentials: 'include', headers: {