diff --git a/gamification-twitter-services/pom.xml b/gamification-twitter-services/pom.xml index 63092b79..30020c2b 100644 --- a/gamification-twitter-services/pom.xml +++ b/gamification-twitter-services/pom.xml @@ -30,23 +30,20 @@ jar Meeds:: Gamification Twitter - Service - 0.36 + 0.38 io.meeds.social social-component-core - provided io.meeds.social social-component-oauth-auth - provided io.meeds.gamification gamification-services - provided diff --git a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/dao/TwitterAccountDAO.java b/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/dao/TwitterAccountDAO.java deleted file mode 100644 index f92e733e..00000000 --- a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/dao/TwitterAccountDAO.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.twitter.dao; - -import io.meeds.gamification.twitter.entity.TwitterAccountEntity; -import org.exoplatform.commons.persistence.impl.GenericDAOJPAImpl; - -import jakarta.persistence.NoResultException; -import jakarta.persistence.TypedQuery; -import java.util.List; - -public class TwitterAccountDAO extends GenericDAOJPAImpl { - - public static final String REMOTE_ID = "remoteId"; - - public TwitterAccountEntity getAccountByRemoteId(long remoteId) { - TypedQuery query = getEntityManager().createNamedQuery("TwitterAccounts.getTwitterAccountByRemoteId", - TwitterAccountEntity.class); - query.setParameter(REMOTE_ID, remoteId); - try { - return query.getSingleResult(); - } catch (NoResultException e) { - return null; - } - } - - public List getAccountsIds(int offset, int limit) { - TypedQuery query = getEntityManager().createNamedQuery("TwitterAccounts.getAccountsIds", Long.class); - if (offset > 0) { - query.setFirstResult(offset); - } - if (limit > 0) { - query.setMaxResults(limit); - } - return query.getResultList(); - } -} diff --git a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/dao/TwitterTweetDAO.java b/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/dao/TwitterTweetDAO.java deleted file mode 100644 index 7a588ae8..00000000 --- a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/dao/TwitterTweetDAO.java +++ /dev/null @@ -1,54 +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.twitter.dao; - -import io.meeds.gamification.twitter.entity.TwitterTweetEntity; -import jakarta.persistence.NoResultException; -import jakarta.persistence.TypedQuery; -import org.exoplatform.commons.persistence.impl.GenericDAOJPAImpl; - -import java.util.List; - -public class TwitterTweetDAO extends GenericDAOJPAImpl { - - public static final String TWEET_LINK = "tweetLink"; - - public List getTweetsIds(int offset, int limit) { - TypedQuery query = getEntityManager().createNamedQuery("TwitterTweets.getTweetsIds", Long.class); - if (offset > 0) { - query.setFirstResult(offset); - } - if (limit > 0) { - query.setMaxResults(limit); - } - return query.getResultList(); - } - - public TwitterTweetEntity getTweetByLink(String tweetLink) { - TypedQuery query = getEntityManager().createNamedQuery("TwitterTweets.getTweetByLink", - TwitterTweetEntity.class); - query.setParameter(TWEET_LINK, tweetLink); - try { - return query.getSingleResult(); - } catch (NoResultException e) { - return null; - } - } - -} diff --git a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/entity/TwitterTweetEntity.java b/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/entity/TwitterTweetEntity.java deleted file mode 100644 index cb26c04c..00000000 --- a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/entity/TwitterTweetEntity.java +++ /dev/null @@ -1,59 +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.twitter.entity; - -import java.io.Serializable; -import java.util.Set; -import jakarta.persistence.*; -import lombok.Data; - -@Entity(name = "TwitterTweets") -@Table(name = "TWITTER_TWEETS") - -@NamedQuery(name = "TwitterTweets.getTweetByLink", - query = "SELECT tweet FROM TwitterTweets tweet" - + " WHERE tweet.tweetLink = :tweetLink") -@NamedQuery(name = "TwitterTweets.getTweetsIds", - query = "SELECT tweet.tweetId FROM TwitterTweets tweet" - + " ORDER BY tweet.tweetId ASC") - -@Data -public class TwitterTweetEntity implements Serializable { - - private static final long serialVersionUID = -4871930064565777769L; - - @Id - @SequenceGenerator(name = "SEQ_TWITTER_ACCOUNTS_ID", sequenceName = "SEQ_TWITTER_ACCOUNTS_ID", allocationSize = 1) - @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_TWITTER_ACCOUNTS_ID") - @Column(name = "TWEET_ID") - private Long tweetId; - - @Column(name = "TWEET_LINK") - private String tweetLink; - - @ElementCollection(fetch = FetchType.EAGER) - @CollectionTable(name = "TWITTER_TWEET_LIKERS", joinColumns = @JoinColumn(name = "TWEET_ID")) - @Column(name = "LIKER_USERNAME") - private Set likers; - - @ElementCollection(fetch = FetchType.EAGER) - @CollectionTable(name = "TWITTER_TWEET_RETWEETERS", joinColumns = @JoinColumn(name = "TWEET_ID")) - @Column(name = "RETWEETER_USERNAME") - private Set retweeters; -} diff --git a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/rest/TwitterServiceRest.java b/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/rest/TwitterServiceRest.java deleted file mode 100644 index 47737f8a..00000000 --- a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/rest/TwitterServiceRest.java +++ /dev/null @@ -1,264 +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.twitter.rest; - -import javax.annotation.security.RolesAllowed; -import javax.ws.rs.*; -import javax.ws.rs.core.*; - -import io.meeds.gamification.twitter.model.TokenStatus; -import io.meeds.gamification.twitter.model.Tweet; -import io.meeds.gamification.twitter.model.TwitterAccount; -import io.meeds.gamification.twitter.rest.builder.TwitterAccountBuilder; -import io.meeds.gamification.twitter.rest.model.EntityList; -import io.meeds.gamification.twitter.rest.model.TwitterAccountRestEntity; -import io.meeds.gamification.twitter.service.TwitterService; -import io.meeds.gamification.twitter.service.TwitterConsumerService; -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 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/twitter") -public class TwitterServiceRest implements ResourceContainer { - - public static final String TWITTER_ACCOUNT_NOT_FOUND = "The TWitter account doesn't exit"; - - private final TwitterService twitterService; - - private final TwitterConsumerService twitterConsumerService; - - public TwitterServiceRest(TwitterService twitterAccountService, TwitterConsumerService twitterConsumerService) { - this.twitterService = twitterAccountService; - this.twitterConsumerService = twitterConsumerService; - } - - @GET - @Produces(MediaType.APPLICATION_JSON) - @Path("account") - @RolesAllowed("users") - @Operation(summary = "Retrieves the list of twitter watched accounts", method = "GET") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Request fulfilled"), - @ApiResponse(responseCode = "401", description = "Unauthorized operation"), }) - public Response getWatchedAccounts(@QueryParam("offset") int offset, - @Parameter(description = "Query results limit", required = true) @QueryParam("limit") int limit, - @Parameter(description = "Force update accounts") @Schema(defaultValue = "false") @QueryParam("forceUpdate") boolean forceUpdate, - @Parameter(description = "Watched accounts total size") @Schema(defaultValue = "false") @QueryParam("returnSize") boolean returnSize) { - - String currentUser = getCurrentUser(); - List twitterAccountRestEntities; - try { - EntityList accountEntityList = new EntityList<>(); - twitterAccountRestEntities = getTwitterAccountRestEntities(currentUser, offset, limit, forceUpdate); - accountEntityList.setEntities(twitterAccountRestEntities); - accountEntityList.setOffset(offset); - accountEntityList.setLimit(limit); - if (returnSize) { - int twitterAccountsSize = twitterService.countTwitterAccounts(currentUser); - accountEntityList.setSize(twitterAccountsSize); - } - return Response.ok(accountEntityList).build(); - } catch (IllegalAccessException e) { - return Response.status(Response.Status.UNAUTHORIZED).build(); - } - } - - @GET - @Produces(MediaType.APPLICATION_JSON) - @Path("account/{accountId}") - @RolesAllowed("users") - @Operation(summary = "Retrieves a twitter watched account 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 getWatchedAccountById(@Parameter(description = "Account technical identifier", required = true) @PathParam("accountId") long accountId) { - if (accountId == 0) { - return Response.status(Response.Status.BAD_REQUEST).entity("Account Id must be not null").build(); - } - String currentUser = getCurrentUser(); - try { - TwitterAccount twitterAccount = twitterService.getTwitterAccountById(accountId, currentUser); - return Response.ok(twitterAccount).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) - @Path("account") - @RolesAllowed("users") - @Operation(summary = "Create a watched Twitter account.", description = "Create a watched Twitter account.", 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 createWatchedAccount(@Parameter(description = "Twitter username", required = true) @FormParam("twitterUsername") String twitterUsername) { - - if (StringUtils.isBlank(twitterUsername)) { - return Response.status(Response.Status.BAD_REQUEST).entity("'twitterUsername' parameter is mandatory").build(); - } - String currentUser = ConversationState.getCurrent().getIdentity().getUserId(); - try { - twitterService.addTwitterAccount(twitterUsername, 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(); - } - } - - @DELETE - @Path("account/{accountId}") - @RolesAllowed("users") - @Operation(summary = "Deletes watched Twitter account.", description = "Deletes watched Twitter account.", 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 deleteWatchedAccount(@Parameter(description = "Twitter account id", required = true) @PathParam("accountId") long accountId) { - if (accountId <= 0) { - return Response.status(Response.Status.BAD_REQUEST).entity("'accountId' parameter is mandatory").build(); - } - String currentUser = ConversationState.getCurrent().getIdentity().getUserId(); - try { - twitterService.deleteTwitterAccount(accountId, 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(TWITTER_ACCOUNT_NOT_FOUND).build(); - } - } - - @GET - @Produces(MediaType.APPLICATION_JSON) - @Path("tweet") - @RolesAllowed("users") - @Operation(summary = "Retrieves the list of twitter watched tweet", method = "GET") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Request fulfilled"), - @ApiResponse(responseCode = "401", description = "Unauthorized operation"), }) - public Response getWatchedTweets(@QueryParam("offset") int offset, - @Parameter(description = "Query results limit", required = true) @QueryParam("limit") int limit, - @Parameter(description = "Watched tweet total size") @Schema(defaultValue = "false") @QueryParam("returnSize") boolean returnSize) { - List tweet = twitterService.getTweets(offset, limit); - EntityList tweetEntityList = new EntityList<>(); - tweetEntityList.setEntities(tweet); - tweetEntityList.setOffset(offset); - tweetEntityList.setLimit(limit); - if (returnSize) { - tweetEntityList.setSize(twitterService.countTweets()); - } - return Response.ok(tweetEntityList).build(); - } - - @POST - @Consumes(MediaType.APPLICATION_FORM_URLENCODED) - @Path("/bearerToken") - @RolesAllowed("users") - @Operation(summary = "Saves a Twitter bearer token.", description = "Saves a Twitter bearer token.", 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 saveBearerToken(@Parameter(description = "Twitter bearer token", required = true) @FormParam("bearerToken") String bearerToken) { - - if (StringUtils.isBlank(bearerToken)) { - return Response.status(Response.Status.BAD_REQUEST).entity("'bearerToken' parameter is mandatory").build(); - } - String currentUser = ConversationState.getCurrent().getIdentity().getUserId(); - try { - twitterService.saveTwitterBearerToken(bearerToken, currentUser); - return Response.status(Response.Status.CREATED).build(); - } catch (IllegalAccessException e) { - return Response.status(Response.Status.UNAUTHORIZED).entity(e.getMessage()).build(); - } - } - - @DELETE - @Path("/bearerToken") - @RolesAllowed("users") - @Operation(summary = "Deletes Twitter bearer token.", description = "Deletes Twitter bearer token.", method = "DELETE") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Request fulfilled"), - @ApiResponse(responseCode = "401", description = "Unauthorized operation"), - @ApiResponse(responseCode = "500", description = "Internal server error"), }) - public Response deleteTwitterBearerToken() { - String currentUser = ConversationState.getCurrent().getIdentity().getUserId(); - try { - twitterService.deleteTwitterBearerToken(currentUser); - return Response.noContent().build(); - } catch (IllegalAccessException e) { - return Response.status(Response.Status.UNAUTHORIZED).entity(e.getMessage()).type(MediaType.TEXT_PLAIN).build(); - } - } - - @GET - @Produces(MediaType.APPLICATION_JSON) - @Path("/bearerToken") - @RolesAllowed("users") - @Operation(summary = "Checks if a twitter bearer token is stored", description = "This returns if twitter bearer token is stored or not", method = "GET") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Request fulfilled"), - @ApiResponse(responseCode = "500", description = "Internal server error"), - @ApiResponse(responseCode = "404", description = "Resource not found"), - @ApiResponse(responseCode = "400", description = "Invalid query input") }) - public Response checkTwitterTokenStatus() { - String currentUser = ConversationState.getCurrent().getIdentity().getUserId(); - try { - String bearerToken = twitterService.getTwitterBearerToken(currentUser); - TokenStatus tokenStatus = twitterConsumerService.checkTwitterTokenStatus(bearerToken); - return Response.ok(tokenStatus).build(); - } catch (IllegalAccessException e) { - return Response.status(Response.Status.UNAUTHORIZED).entity(e.getMessage()).build(); - } - } - - private List getTwitterAccountRestEntities(String username, int offset, int limit, boolean forceUpdate) throws IllegalAccessException { - Collection twitterAccounts = twitterService.getTwitterAccounts(username, offset, limit, forceUpdate); - return TwitterAccountBuilder.toRestEntities(twitterService, twitterConsumerService, twitterAccounts); - } -} diff --git a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/storage/TwitterAccountStorage.java b/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/storage/TwitterAccountStorage.java deleted file mode 100644 index 8116c858..00000000 --- a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/storage/TwitterAccountStorage.java +++ /dev/null @@ -1,83 +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.twitter.storage; - -import java.util.Date; -import java.util.List; - -import io.meeds.gamification.twitter.dao.TwitterAccountDAO; -import io.meeds.gamification.twitter.entity.TwitterAccountEntity; -import io.meeds.gamification.twitter.model.TwitterAccount; -import org.exoplatform.commons.ObjectAlreadyExistsException; - -import static io.meeds.gamification.twitter.storage.mapper.TwitterAccountMapper.fromEntity; -import static io.meeds.gamification.twitter.storage.mapper.TwitterAccountMapper.toEntity; - -public class TwitterAccountStorage { - - private final TwitterAccountDAO twitterAccountDAO; - - public TwitterAccountStorage(TwitterAccountDAO twitterAccountDAO) { - this.twitterAccountDAO = twitterAccountDAO; - } - - public TwitterAccount addTwitterAccount(TwitterAccount twitterAccount) throws ObjectAlreadyExistsException { - TwitterAccount existsAccount = getTwitterAccountByRemoteId(twitterAccount.getRemoteId()); - if (existsAccount == null) { - TwitterAccountEntity twitterAccountEntity = toEntity(twitterAccount); - twitterAccountEntity.setWatchedDate(new Date()); - twitterAccountEntity.setUpdatedDate(new Date()); - twitterAccountEntity.setRefreshDate(new Date()); - twitterAccountEntity = twitterAccountDAO.create(twitterAccountEntity); - return fromEntity(twitterAccountEntity); - } else { - throw new ObjectAlreadyExistsException(existsAccount); - } - } - - public TwitterAccount getTwitterAccountById(Long id) { - return fromEntity(twitterAccountDAO.find(id)); - } - - public List getTwitterAccountIds(int offset, int limit) { - return twitterAccountDAO.getAccountsIds(offset, limit); - } - - public int countTwitterAccounts() { - return twitterAccountDAO.count().intValue(); - } - - public TwitterAccount getTwitterAccountByRemoteId(long remoteId) { - TwitterAccountEntity twitterAccountEntity = twitterAccountDAO.getAccountByRemoteId(remoteId); - return fromEntity(twitterAccountEntity); - } - - public TwitterAccount updateAccountLastMentionTweetId(long accountId, long lastMentionTweetId) { - TwitterAccountEntity twitterAccountEntity = twitterAccountDAO.find(accountId); - twitterAccountEntity.setLastMentionTweetId(lastMentionTweetId); - return fromEntity(twitterAccountDAO.update(twitterAccountEntity)); - } - - public TwitterAccount deleteTwitterAccount(long accountId) { - TwitterAccountEntity twitterAccountEntity = twitterAccountDAO.find(accountId); - if (twitterAccountEntity != null) { - twitterAccountDAO.delete(twitterAccountEntity); - } - return fromEntity(twitterAccountEntity); - } -} diff --git a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/storage/cached/TwitterConsumerCachedStorage.java b/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/storage/cached/TwitterConsumerCachedStorage.java deleted file mode 100644 index f61364d7..00000000 --- a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/storage/cached/TwitterConsumerCachedStorage.java +++ /dev/null @@ -1,64 +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.twitter.storage.cached; - -import java.io.Serializable; - -import io.meeds.gamification.twitter.model.RemoteTwitterAccount; -import io.meeds.gamification.twitter.model.TwitterAccount; -import io.meeds.gamification.twitter.storage.TwitterConsumerStorage; -import io.meeds.gamification.twitter.storage.cached.model.CacheKey; -import org.exoplatform.commons.cache.future.FutureExoCache; -import org.exoplatform.services.cache.CacheService; -import org.exoplatform.services.cache.ExoCache; - -public class TwitterConsumerCachedStorage extends TwitterConsumerStorage { - - public static final String TWITTER_CACHE_NAME = "twitter.connector"; - - private static final int ACCOUNT_BY_ID_CONTEXT = 1; - - private final FutureExoCache twitterFutureCache; - - public TwitterConsumerCachedStorage(CacheService cacheService) { - ExoCache cacheInstance = cacheService.getCacheInstance(TWITTER_CACHE_NAME); - this.twitterFutureCache = new FutureExoCache<>((context, key) -> { - if (ACCOUNT_BY_ID_CONTEXT == context.getContext()) { - return TwitterConsumerCachedStorage.super.retrieveTwitterAccount(context.getRemoteId(), context.getBearerToken()); - } else { - throw new UnsupportedOperationException(); - } - }, cacheInstance); - } - - @Override - public RemoteTwitterAccount retrieveTwitterAccount(long twitterRemoteId, String bearerToken) { - CacheKey cacheKey = new CacheKey(ACCOUNT_BY_ID_CONTEXT, twitterRemoteId, bearerToken); - return (RemoteTwitterAccount) this.twitterFutureCache.get(cacheKey, cacheKey.hashCode()); - } - - @Override - public void clearCache() { - this.twitterFutureCache.clear(); - } - - @Override - public void clearCache(TwitterAccount twitterAccount, String bearerToken) { - this.twitterFutureCache.remove(new CacheKey(ACCOUNT_BY_ID_CONTEXT, twitterAccount.getRemoteId(), bearerToken).hashCode()); - } -} diff --git a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/storage/cached/model/CacheKey.java b/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/storage/cached/model/CacheKey.java deleted file mode 100644 index e3861911..00000000 --- a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/storage/cached/model/CacheKey.java +++ /dev/null @@ -1,44 +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.twitter.storage.cached.model; - -import java.io.Serializable; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -@AllArgsConstructor -@NoArgsConstructor -@Data -public class CacheKey implements Serializable { - - private static final long serialVersionUID = -7490772779963803443L; - - private long remoteId; - - private String bearerToken; - - private Integer context; - - public CacheKey(Integer context, long remoteId, String bearerToken) { - this.remoteId = remoteId; - this.bearerToken = bearerToken; - this.context = context; - } -} diff --git a/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/dao/TwitterAccountDAO.java b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/dao/TwitterAccountDAO.java new file mode 100644 index 00000000..29fca58e --- /dev/null +++ b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/dao/TwitterAccountDAO.java @@ -0,0 +1,27 @@ +/* + * This file is part of the Meeds project (https://meeds.io/). + * + * Copyright (C) 2020 - 2024 Meeds Association contact@meeds.io + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package io.meeds.twitter.gamification.dao; + +import io.meeds.twitter.gamification.entity.TwitterAccountEntity; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface TwitterAccountDAO extends JpaRepository { + + TwitterAccountEntity findTwitterAccountEntityByRemoteId(long remoteId); +} diff --git a/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/dao/TwitterTweetDAO.java b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/dao/TwitterTweetDAO.java new file mode 100644 index 00000000..e7d59103 --- /dev/null +++ b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/dao/TwitterTweetDAO.java @@ -0,0 +1,28 @@ +/* + * This file is part of the Meeds project (https://meeds.io/). + * + * Copyright (C) 2020 - 2024 Meeds Association contact@meeds.io + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package io.meeds.twitter.gamification.dao; + +import io.meeds.twitter.gamification.entity.TwitterTweetEntity; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface TwitterTweetDAO extends JpaRepository { + + TwitterTweetEntity findTwitterTweetEntityByTweetLink(String tweetLink); + +} diff --git a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/entity/TwitterAccountEntity.java b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/entity/TwitterAccountEntity.java similarity index 71% rename from gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/entity/TwitterAccountEntity.java rename to gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/entity/TwitterAccountEntity.java index c5d2c629..b54b62d4 100644 --- a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/entity/TwitterAccountEntity.java +++ b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/entity/TwitterAccountEntity.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.twitter.entity; +package io.meeds.twitter.gamification.entity; import java.io.Serializable; import java.util.Date; @@ -27,13 +27,6 @@ @Entity(name = "TwitterAccounts") @Table(name = "TWITTER_ACCOUNTS") - -@NamedQuery(name = "TwitterAccounts.getTwitterAccountByRemoteId", - query = "SELECT twitterAccount FROM TwitterAccounts twitterAccount" - + " WHERE twitterAccount.remoteId = :remoteId") -@NamedQuery(name = "TwitterAccounts.getAccountsIds", - query = "SELECT twitterAccount.id FROM TwitterAccounts twitterAccount" - + " ORDER BY twitterAccount.id ASC") @Data public class TwitterAccountEntity implements Serializable { @@ -43,29 +36,29 @@ public class TwitterAccountEntity implements Serializable { @SequenceGenerator(name = "SEQ_TWITTER_ACCOUNTS_ID", sequenceName = "SEQ_TWITTER_ACCOUNTS_ID", allocationSize = 1) @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_TWITTER_ACCOUNTS_ID") @Column(name = "ID") - private Long id; + private Long id; @Column(name = "REMOTE_ID") - private Long remoteId; + private Long remoteId; @Column(name = "IDENTIFIER", nullable = false) - private String identifier; + private String identifier; @Column(name = "NAME", nullable = false) - private String name; + private String name; @Column(name = "WATCHED_DATE", nullable = false) - private Date watchedDate; + private Date watchedDate; @Column(name = "WATCHED_BY", nullable = false) - private Long watchedBy; + private Long watchedBy; @Column(name = "UPDATED_DATE", nullable = false) - private Date updatedDate; + private Date updatedDate; @Column(name = "REFRESH_DATE", nullable = false) - private Date refreshDate; + private Date refreshDate; @Column(name = "LAST_MENTION_TWEET_ID") - private Long lastMentionTweetId; + private Long lastMentionTweetId; } diff --git a/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/entity/TwitterTweetEntity.java b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/entity/TwitterTweetEntity.java new file mode 100644 index 00000000..98ccd42d --- /dev/null +++ b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/entity/TwitterTweetEntity.java @@ -0,0 +1,51 @@ +/* + * This file is part of the Meeds project (https://meeds.io/). + * + * Copyright (C) 2020 - 2024 Meeds Association contact@meeds.io + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package io.meeds.twitter.gamification.entity; + +import java.io.Serializable; +import java.util.Set; +import jakarta.persistence.*; +import lombok.Data; + +@Entity(name = "TwitterTweets") +@Table(name = "TWITTER_TWEETS") +@Data +public class TwitterTweetEntity implements Serializable { + + private static final long serialVersionUID = -4871930064565777769L; + + @Id + @SequenceGenerator(name = "SEQ_TWITTER_ACCOUNTS_ID", sequenceName = "SEQ_TWITTER_ACCOUNTS_ID", allocationSize = 1) + @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_TWITTER_ACCOUNTS_ID") + @Column(name = "TWEET_ID") + private Long id; + + @Column(name = "TWEET_LINK") + private String tweetLink; + + @ElementCollection(fetch = FetchType.EAGER) + @CollectionTable(name = "TWITTER_TWEET_LIKERS", joinColumns = @JoinColumn(name = "TWEET_ID")) + @Column(name = "LIKER_USERNAME") + private Set likers; + + @ElementCollection(fetch = FetchType.EAGER) + @CollectionTable(name = "TWITTER_TWEET_RETWEETERS", joinColumns = @JoinColumn(name = "TWEET_ID")) + @Column(name = "RETWEETER_USERNAME") + private Set retweeters; +} diff --git a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/exception/TwitterConnectionException.java b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/exception/TwitterConnectionException.java similarity index 95% rename from gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/exception/TwitterConnectionException.java rename to gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/exception/TwitterConnectionException.java index 577f70f2..f7b6a909 100644 --- a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/exception/TwitterConnectionException.java +++ b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/exception/TwitterConnectionException.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.twitter.exception; +package io.meeds.twitter.gamification.exception; public class TwitterConnectionException extends Exception { diff --git a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/listener/RuleUpdateTwitterListener.java b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/listener/RuleUpdateTwitterListener.java similarity index 69% rename from gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/listener/RuleUpdateTwitterListener.java rename to gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/listener/RuleUpdateTwitterListener.java index 40688f62..d9ea638c 100644 --- a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/listener/RuleUpdateTwitterListener.java +++ b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/listener/RuleUpdateTwitterListener.java @@ -16,45 +16,58 @@ * 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.twitter.listener; +package io.meeds.twitter.gamification.listener; import io.meeds.gamification.constant.DateFilterType; import io.meeds.gamification.constant.EntityStatusType; import io.meeds.gamification.model.filter.RuleFilter; import io.meeds.gamification.service.RuleService; -import io.meeds.gamification.twitter.model.Tweet; -import io.meeds.gamification.twitter.service.TwitterService; +import io.meeds.twitter.gamification.model.Tweet; +import io.meeds.twitter.gamification.service.TwitterService; +import io.meeds.twitter.gamification.utils.Utils; import org.apache.commons.lang3.StringUtils; import org.exoplatform.commons.api.persistence.ExoTransactional; import org.exoplatform.services.listener.Event; import org.exoplatform.services.listener.Listener; import io.meeds.gamification.model.RuleDTO; +import org.exoplatform.services.listener.ListenerService; 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 javax.annotation.PostConstruct; import java.util.List; -import static io.meeds.gamification.twitter.utils.Utils.*; - +@Component public class RuleUpdateTwitterListener extends Listener { - private static final Log LOG = ExoLogger.getLogger(RuleUpdateTwitterListener.class); + private static final Log LOG = ExoLogger.getLogger(RuleUpdateTwitterListener.class); + + private static final String[] LISTENER_EVENTS = { "rule.created", "rule.deleted", "rule.updated" }; + + @Autowired + private TwitterService twitterAccountService; - private final TwitterService twitterAccountService; + @Autowired + private RuleService ruleService; - private final RuleService ruleService; + @Autowired + private ListenerService listenerService; - public RuleUpdateTwitterListener(TwitterService twitterAccountService, RuleService ruleService) { - this.twitterAccountService = twitterAccountService; - this.ruleService = ruleService; + @PostConstruct + public void init() { + for (String eventName : LISTENER_EVENTS) { + listenerService.addListener(eventName, this); + } } @Override @ExoTransactional public void onEvent(Event event) { RuleFilter ruleFilter = new RuleFilter(); - ruleFilter.setEventType(CONNECTOR_NAME); + ruleFilter.setEventType(Utils.CONNECTOR_NAME); ruleFilter.setStatus(EntityStatusType.ENABLED); ruleFilter.setDateFilterType(DateFilterType.ACTIVE); ruleFilter.setAllSpaces(true); @@ -62,11 +75,11 @@ public void onEvent(Event event) { List watchedTweets = rules.stream() .filter(r -> !r.getEvent().getProperties().isEmpty() - && StringUtils.isNotBlank(r.getEvent().getProperties().get(TWEET_LINK))) - .map(r -> r.getEvent().getProperties().get(TWEET_LINK)) + && StringUtils.isNotBlank(r.getEvent().getProperties().get(Utils.TWEET_LINK))) + .map(r -> r.getEvent().getProperties().get(Utils.TWEET_LINK)) .toList(); - List tweets = twitterAccountService.getTweets(0, -1); + List tweets = twitterAccountService.getTweets(); String bearerToken = twitterAccountService.getTwitterBearerToken(); watchedTweets.forEach(watchedTweet -> { @@ -75,7 +88,8 @@ public void onEvent(Event event) { if (StringUtils.isNotBlank(bearerToken)) { twitterAccountService.addTweetToWatch(watchedTweet); } else { - LOG.warn("The Tweet {} could not be viewed, because the Twitter bearer token was not configured", extractTweetId(watchedTweet)); + LOG.warn("The Tweet {} could not be viewed, because the Twitter bearer token was not configured", + Utils.extractTweetId(watchedTweet)); } } }); diff --git a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/model/RemoteTwitterAccount.java b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/model/RemoteTwitterAccount.java similarity index 96% rename from gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/model/RemoteTwitterAccount.java rename to gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/model/RemoteTwitterAccount.java index 79e63fe2..8a8a93a3 100644 --- a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/model/RemoteTwitterAccount.java +++ b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/model/RemoteTwitterAccount.java @@ -17,7 +17,7 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package io.meeds.gamification.twitter.model; +package io.meeds.twitter.gamification.model; import lombok.AllArgsConstructor; import lombok.Getter; diff --git a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/model/TokenStatus.java b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/model/TokenStatus.java similarity index 96% rename from gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/model/TokenStatus.java rename to gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/model/TokenStatus.java index 8eb841c1..e091c9d9 100644 --- a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/model/TokenStatus.java +++ b/gamification-twitter-services/src/main/java/io/meeds/twitter/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.twitter.model; +package io.meeds.twitter.gamification.model; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/model/Tweet.java b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/model/Tweet.java similarity index 96% rename from gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/model/Tweet.java rename to gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/model/Tweet.java index 181b303f..d9746efd 100644 --- a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/model/Tweet.java +++ b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/model/Tweet.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.twitter.model; +package io.meeds.twitter.gamification.model; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/model/TwitterAccessTokenContext.java b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/model/TwitterAccessTokenContext.java similarity index 61% rename from gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/model/TwitterAccessTokenContext.java rename to gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/model/TwitterAccessTokenContext.java index 3972b6f0..8c655bac 100644 --- a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/model/TwitterAccessTokenContext.java +++ b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/model/TwitterAccessTokenContext.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.twitter.model; +package io.meeds.twitter.gamification.model; import java.io.Serializable; import java.util.Objects; @@ -27,28 +27,28 @@ public class TwitterAccessTokenContext extends AccessTokenContext implements Serializable { - public final OAuth2AccessToken accessToken; + public final OAuth2AccessToken accessToken; - public TwitterAccessTokenContext(OAuth2AccessToken accessToken) { - this.accessToken = accessToken; - } - - @Override - public String getAccessToken() { - return accessToken.getAccessToken(); - } + public TwitterAccessTokenContext(OAuth2AccessToken accessToken) { + this.accessToken = accessToken; + } - @Override - public boolean equals(Object obj) { - if (!super.equals(obj)) { - return false; - } - TwitterAccessTokenContext accessTokenContext = (TwitterAccessTokenContext) obj; - return StringUtils.equals(this.accessToken.getAccessToken(), accessTokenContext.getAccessToken()); - } + @Override + public String getAccessToken() { + return accessToken.getAccessToken(); + } - @Override - public int hashCode() { - return super.hashCode() * 13 + Objects.hash(accessToken); + @Override + public boolean equals(Object obj) { + if (!super.equals(obj)) { + return false; } + TwitterAccessTokenContext accessTokenContext = (TwitterAccessTokenContext) obj; + return StringUtils.equals(this.accessToken.getAccessToken(), accessTokenContext.getAccessToken()); + } + + @Override + public int hashCode() { + return super.hashCode() * 13 + Objects.hash(accessToken); + } } diff --git a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/model/TwitterAccount.java b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/model/TwitterAccount.java similarity index 74% rename from gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/model/TwitterAccount.java rename to gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/model/TwitterAccount.java index f23831c4..eaf7b828 100644 --- a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/model/TwitterAccount.java +++ b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/model/TwitterAccount.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.twitter.model; +package io.meeds.twitter.gamification.model; import lombok.AllArgsConstructor; import lombok.Data; @@ -43,10 +43,18 @@ public class TwitterAccount implements Cloneable { private String refreshDate; - private long lastMentionTweetId; + private long lastMentionTweetId; public TwitterAccount clone() { // NOSONAR - return new TwitterAccount(id, remoteId, identifier, name, watchedDate, watchedBy, updatedDate, refreshDate, lastMentionTweetId); + return new TwitterAccount(id, + remoteId, + identifier, + name, + watchedDate, + watchedBy, + updatedDate, + refreshDate, + lastMentionTweetId); } } diff --git a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/model/TwitterOAuth20Api.java b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/model/TwitterOAuth20Api.java similarity index 94% rename from gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/model/TwitterOAuth20Api.java rename to gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/model/TwitterOAuth20Api.java index da07c58e..9a477e39 100644 --- a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/model/TwitterOAuth20Api.java +++ b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/model/TwitterOAuth20Api.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.twitter.model; +package io.meeds.twitter.gamification.model; import com.github.scribejava.core.builder.api.DefaultApi20; @@ -36,7 +36,7 @@ protected String getAuthorizationBaseUrl() { return "https://twitter.com/i/oauth2/authorize"; } - public String getRevokeTokenEndpoint() { + public String getRevokeTokenEndpoint() { // NOSONAR return "https://api.twitter.com/2/oauth2/revoke"; } diff --git a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/model/TwitterTrigger.java b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/model/TwitterTrigger.java similarity index 96% rename from gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/model/TwitterTrigger.java rename to gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/model/TwitterTrigger.java index 3fb8bb43..495d6f14 100644 --- a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/model/TwitterTrigger.java +++ b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/model/TwitterTrigger.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.twitter.model; +package io.meeds.twitter.gamification.model; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/plugin/TwitterConnectorPlugin.java b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/plugin/TwitterConnectorPlugin.java similarity index 81% rename from gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/plugin/TwitterConnectorPlugin.java rename to gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/plugin/TwitterConnectorPlugin.java index 628f338e..37e3a9e2 100644 --- a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/plugin/TwitterConnectorPlugin.java +++ b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/plugin/TwitterConnectorPlugin.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.twitter.plugin; +package io.meeds.twitter.gamification.plugin; import com.github.scribejava.core.builder.ServiceBuilder; import com.github.scribejava.core.model.OAuth2AccessToken; @@ -26,45 +26,56 @@ import com.github.scribejava.core.pkce.PKCECodeChallengeMethod; import io.meeds.gamification.model.RemoteConnectorSettings; import io.meeds.gamification.plugin.ConnectorPlugin; +import io.meeds.gamification.service.ConnectorService; import io.meeds.gamification.service.ConnectorSettingService; -import io.meeds.gamification.twitter.model.TwitterAccessTokenContext; -import io.meeds.gamification.twitter.model.TwitterOAuth20Api; +import io.meeds.twitter.gamification.model.TwitterAccessTokenContext; +import io.meeds.twitter.gamification.model.TwitterOAuth20Api; import io.meeds.oauth.exception.OAuthException; import io.meeds.oauth.exception.OAuthExceptionCode; import io.meeds.oauth.utils.HttpResponseContext; import io.meeds.oauth.utils.OAuthUtils; +import io.meeds.twitter.gamification.utils.Utils; +import jakarta.annotation.PostConstruct; import org.apache.commons.lang3.StringUtils; 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.stereotype.Component; import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; import java.util.concurrent.ExecutionException; -import static io.meeds.gamification.twitter.utils.Utils.CONNECTOR_NAME; - +@Component public class TwitterConnectorPlugin extends ConnectorPlugin { - private static final Log LOG = ExoLogger.getLogger(TwitterConnectorPlugin.class); + private static final Log LOG = ExoLogger.getLogger(TwitterConnectorPlugin.class); + + private static final String NAME = "twitter"; + + private long remoteConnectorId; - private final ConnectorSettingService connectorSettingService; + private OAuth20Service oAuthService; - private OAuth20Service oAuthService; + @Autowired + private ConnectorSettingService connectorSettingService; - private long remoteConnectorId; + @Autowired + private ConnectorService connectorService; - public TwitterConnectorPlugin(ConnectorSettingService connectorSettingService) { - this.connectorSettingService = connectorSettingService; + @PostConstruct + public void initData() { + connectorService.addPlugin(this); } @Override public String validateToken(String accessToken) { - RemoteConnectorSettings remoteConnectorSettings = connectorSettingService.getConnectorSettings(CONNECTOR_NAME); - remoteConnectorSettings.setSecretKey(connectorSettingService.getConnectorSecretKey(CONNECTOR_NAME)); + RemoteConnectorSettings remoteConnectorSettings = connectorSettingService.getConnectorSettings(Utils.CONNECTOR_NAME); + remoteConnectorSettings.setSecretKey(connectorSettingService.getConnectorSecretKey(Utils.CONNECTOR_NAME)); if (StringUtils.isBlank(remoteConnectorSettings.getApiKey()) || StringUtils.isBlank(remoteConnectorSettings.getSecretKey())) { - LOG.warn("Missing '{}' connector settings", CONNECTOR_NAME); + LOG.warn("Missing '{}' connector settings", Utils.CONNECTOR_NAME); return null; } try { @@ -91,7 +102,12 @@ public String validateToken(String accessToken) { @Override public String getConnectorName() { - return CONNECTOR_NAME; + return Utils.CONNECTOR_NAME; + } + + @Override + public String getName() { + return NAME; } private OAuth20Service getOAuthService(RemoteConnectorSettings remoteConnectorSettings) { diff --git a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/plugin/TwitterEventPlugin.java b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/plugin/TwitterEventPlugin.java similarity index 59% rename from gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/plugin/TwitterEventPlugin.java rename to gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/plugin/TwitterEventPlugin.java index 12e2bdf0..bb67aac6 100644 --- a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/plugin/TwitterEventPlugin.java +++ b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/plugin/TwitterEventPlugin.java @@ -16,36 +16,47 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ -package io.meeds.gamification.twitter.plugin; +package io.meeds.twitter.gamification.plugin; import io.meeds.gamification.plugin.EventPlugin; +import io.meeds.gamification.service.EventService; +import io.meeds.twitter.gamification.utils.Utils; +import jakarta.annotation.PostConstruct; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; import java.util.List; import java.util.Map; -import static io.meeds.gamification.twitter.utils.Utils.*; -import static io.meeds.gamification.twitter.utils.Utils.extractTweetId; - +@Component public class TwitterEventPlugin extends EventPlugin { public static final String EVENT_TYPE = "twitter"; + @Autowired + private EventService eventService; + + @PostConstruct + public void init() { + eventService.addPlugin(this); + } + @Override public String getEventType() { return EVENT_TYPE; } public List getTriggers() { - return List.of(MENTION_ACCOUNT_EVENT_NAME, LIKE_TWEET_EVENT_NAME, RETWEET_TWEET_EVENT_NAME); + return List.of(Utils.MENTION_ACCOUNT_EVENT_NAME, Utils.LIKE_TWEET_EVENT_NAME, Utils.RETWEET_TWEET_EVENT_NAME); } @Override public boolean isValidEvent(Map eventProperties, String triggerDetails) { - String desiredAccountId = eventProperties.get(ACCOUNT_ID); - String desiredTweetLink = eventProperties.get(TWEET_LINK); - String desiredTweetId = desiredTweetLink != null ? extractTweetId(desiredTweetLink) : null; - Map triggerDetailsMop = stringToMap(triggerDetails); - return (desiredAccountId != null && desiredAccountId.equals(triggerDetailsMop.get(ACCOUNT_ID))) - || (desiredTweetId != null && desiredTweetId.equals(triggerDetailsMop.get(TWEET_ID))); + String desiredAccountId = eventProperties.get(Utils.ACCOUNT_ID); + String desiredTweetLink = eventProperties.get(Utils.TWEET_LINK); + String desiredTweetId = desiredTweetLink != null ? Utils.extractTweetId(desiredTweetLink) : null; + Map triggerDetailsMop = Utils.stringToMap(triggerDetails); + return (desiredAccountId != null && desiredAccountId.equals(triggerDetailsMop.get(Utils.ACCOUNT_ID))) + || (desiredTweetId != null && desiredTweetId.equals(triggerDetailsMop.get(Utils.TWEET_ID))); } } diff --git a/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/rest/TwitterAccountRest.java b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/rest/TwitterAccountRest.java new file mode 100644 index 00000000..b7f3f304 --- /dev/null +++ b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/rest/TwitterAccountRest.java @@ -0,0 +1,154 @@ +/* + * This file is part of the Meeds project (https://meeds.io/). + * + * Copyright (C) 2020 - 2022 Meeds Association contact@meeds.io + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * + * Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package io.meeds.twitter.gamification.rest; + +import io.meeds.twitter.gamification.model.TwitterAccount; +import io.meeds.twitter.gamification.rest.builder.TwitterAccountBuilder; +import io.meeds.twitter.gamification.rest.model.TwitterAccountRestEntity; +import io.meeds.twitter.gamification.service.TwitterConsumerService; +import io.meeds.twitter.gamification.service.TwitterService; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import jakarta.servlet.http.HttpServletRequest; +import org.apache.commons.lang3.StringUtils; +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.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 org.springframework.hateoas.EntityModel; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.tags.Tag; + +import org.exoplatform.commons.ObjectAlreadyExistsException; +import org.exoplatform.commons.exception.ObjectNotFoundException; + +@RestController +@RequestMapping("accounts") +@Tag(name = "accounts", description = "Manage and access twitter watched accounts") // NOSONAR +public class TwitterAccountRest { + + @Autowired + private TwitterService twitterService; + + @Autowired + private TwitterConsumerService twitterConsumerService; + + @GetMapping + @Secured("users") + @Operation(summary = "Retrieves the list of twitter watched accounts", method = "GET") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Request fulfilled"), + @ApiResponse(responseCode = "401", description = "Unauthorized operation"), + @ApiResponse(responseCode = "500", description = "Internal server error") }) + public PagedModel> getWatchedAccounts(HttpServletRequest request, + Pageable pageable, + PagedResourcesAssembler assembler) { + + try { + Page twitterAccountRestEntities = + getTwitterAccountRestEntities(request.getRemoteUser(), pageable); + return assembler.toModel(twitterAccountRestEntities); + } catch (IllegalAccessException e) { + throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, e.getMessage()); + } + } + + @GetMapping(path = "{accountId}") + @Secured("users") + @Operation(summary = "Retrieves a twitter watched account 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 TwitterAccount getWatchedAccountById(HttpServletRequest request, + @Parameter(description = "Account technical identifier", required = true) + @PathVariable("accountId") + long accountId) { + if (accountId == 0) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Account Id must be not null"); + } + try { + return twitterService.getTwitterAccountById(accountId, request.getRemoteUser()); + } 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 watched Twitter account.", description = "Create a watched Twitter account.", 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 createWatchedAccount(HttpServletRequest request, + @Parameter(description = "Twitter username", required = true) + @RequestParam("twitterUsername") + String twitterUsername) { + + if (StringUtils.isBlank(twitterUsername)) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "'twitterUsername' parameter is mandatory"); + } + try { + twitterService.addTwitterAccount(twitterUsername, 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()); + } + } + + @DeleteMapping(path = "{accountId}") + @Secured("users") + @Operation(summary = "Deletes watched Twitter account.", description = "Deletes watched Twitter account.", 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 deleteWatchedAccount(HttpServletRequest request, + @Parameter(description = "Twitter account id", required = true) + @PathVariable("accountId") + long accountId) { + try { + twitterService.deleteTwitterAccount(accountId, request.getRemoteUser()); + } catch (IllegalAccessException e) { + throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, e.getMessage()); + } catch (ObjectNotFoundException e) { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, e.getMessage()); + } + } + + private Page getTwitterAccountRestEntities(String username, + Pageable pageable) throws IllegalAccessException { + Page twitterAccounts = twitterService.getTwitterAccounts(username, pageable); + return TwitterAccountBuilder.toRestEntities(twitterService, twitterConsumerService, twitterAccounts); + } +} diff --git a/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/rest/TwitterSettingsRest.java b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/rest/TwitterSettingsRest.java new file mode 100644 index 00000000..0a4ce848 --- /dev/null +++ b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/rest/TwitterSettingsRest.java @@ -0,0 +1,100 @@ +/* + * This file is part of the Meeds project (https://meeds.io/). + * + * Copyright (C) 2020 - 2022 Meeds Association contact@meeds.io + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * + * Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package io.meeds.twitter.gamification.rest; + +import io.meeds.twitter.gamification.model.TokenStatus; +import io.meeds.twitter.gamification.service.TwitterConsumerService; +import io.meeds.twitter.gamification.service.TwitterService; +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.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.security.access.annotation.Secured; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.server.ResponseStatusException; + +@RestController +@RequestMapping("settings") +@Tag(name = "twitter/settings", description = "Manage and access twitter settings") // NOSONAR +public class TwitterSettingsRest { + + @Autowired + private TwitterService twitterService; + + @Autowired + private TwitterConsumerService twitterConsumerService; + + @PostMapping + @Secured("rewarding") + @Operation(summary = "Saves a Twitter bearer token.", description = "Saves a Twitter bearer token.", 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 saveBearerToken(HttpServletRequest request, + @Parameter(description = "Twitter bearer token", required = true) + @RequestParam("bearerToken") + String bearerToken) { + + if (StringUtils.isBlank(bearerToken)) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "'bearerToken' parameter is mandatory"); + } + try { + twitterService.saveTwitterBearerToken(bearerToken, request.getRemoteUser()); + } catch (IllegalAccessException e) { + throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, e.getMessage()); + } + } + + @DeleteMapping + @Secured("rewarding") + @Operation(summary = "Deletes Twitter bearer token.", description = "Deletes Twitter bearer token.", method = "DELETE") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Request fulfilled"), + @ApiResponse(responseCode = "401", description = "Unauthorized operation"), + @ApiResponse(responseCode = "500", description = "Internal server error"), }) + public void deleteTwitterBearerToken(HttpServletRequest request) { + try { + twitterService.deleteTwitterBearerToken(request.getRemoteUser()); + } catch (IllegalAccessException e) { + throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, e.getMessage()); + } + } + + @GetMapping + @Secured("rewarding") + @Operation(summary = "Checks if a twitter bearer token is stored", description = "This returns if twitter bearer token is stored or not", method = "GET") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Request fulfilled"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "404", description = "Resource not found"), + @ApiResponse(responseCode = "400", description = "Invalid query input") }) + public TokenStatus checkTwitterTokenStatus(HttpServletRequest request) { + try { + String bearerToken = twitterService.getTwitterBearerToken(request.getRemoteUser()); + return twitterConsumerService.checkTwitterTokenStatus(bearerToken); + } catch (IllegalAccessException e) { + throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, e.getMessage()); + } + } +} diff --git a/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/rest/TwitterTweetRest.java b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/rest/TwitterTweetRest.java new file mode 100644 index 00000000..2467dc62 --- /dev/null +++ b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/rest/TwitterTweetRest.java @@ -0,0 +1,54 @@ +/* + * This file is part of the Meeds project (https://meeds.io/). + * + * Copyright (C) 2020 - 2022 Meeds Association contact@meeds.io + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * + * Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package io.meeds.twitter.gamification.rest; + +import io.meeds.twitter.gamification.model.Tweet; +import io.meeds.twitter.gamification.service.TwitterService; +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.security.access.annotation.Secured; +import org.springframework.web.bind.annotation.*; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; + +@RestController +@RequestMapping("tweets") +@Tag(name = "twitter/tweets", description = "Manage and access twitter watched tweets") // NOSONAR +public class TwitterTweetRest { + + @Autowired + private TwitterService twitterService; + + @GetMapping + @Secured("users") + @Operation(summary = "Retrieves the list of twitter watched tweet", method = "GET") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Request fulfilled"), + @ApiResponse(responseCode = "401", description = "Unauthorized operation"), }) + public PagedModel> getWatchedTweets(Pageable pageable, PagedResourcesAssembler assembler) { + Page tweets = twitterService.getTweets(pageable); + return assembler.toModel(tweets); + } +} diff --git a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/rest/builder/TwitterAccountBuilder.java b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/rest/builder/TwitterAccountBuilder.java similarity index 80% rename from gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/rest/builder/TwitterAccountBuilder.java rename to gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/rest/builder/TwitterAccountBuilder.java index 96f11300..3b6049ec 100644 --- a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/rest/builder/TwitterAccountBuilder.java +++ b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/rest/builder/TwitterAccountBuilder.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.twitter.rest.builder; +package io.meeds.twitter.gamification.rest.builder; -import java.util.Collection; -import java.util.List; - -import io.meeds.gamification.twitter.model.RemoteTwitterAccount; -import io.meeds.gamification.twitter.model.TokenStatus; -import io.meeds.gamification.twitter.model.TwitterAccount; -import io.meeds.gamification.twitter.rest.model.TwitterAccountRestEntity; -import io.meeds.gamification.twitter.service.TwitterService; -import io.meeds.gamification.twitter.service.TwitterConsumerService; +import io.meeds.twitter.gamification.model.RemoteTwitterAccount; +import io.meeds.twitter.gamification.model.TokenStatus; +import io.meeds.twitter.gamification.model.TwitterAccount; +import io.meeds.twitter.gamification.rest.model.TwitterAccountRestEntity; +import io.meeds.twitter.gamification.service.TwitterService; +import io.meeds.twitter.gamification.service.TwitterConsumerService; +import org.springframework.data.domain.Page; public class TwitterAccountBuilder { @@ -58,17 +56,15 @@ public static TwitterAccountRestEntity toRestEntity(String twitterBearerToken, remoteTwitterAccount != null ? remoteTwitterAccount.getAvatarUrl() : null); } - public static List toRestEntities(TwitterService twitterAccountService, + public static Page toRestEntities(TwitterService twitterAccountService, TwitterConsumerService twitterConsumerService, - Collection twitterAccounts) { + Page twitterAccounts) { String twitterBearerToken = twitterAccountService.getTwitterBearerToken(); TokenStatus tokenStatus = twitterConsumerService.checkTwitterTokenStatus(twitterBearerToken); - return twitterAccounts.stream() - .map(twitterAccount -> toRestEntity(twitterBearerToken, + return twitterAccounts.map(twitterAccount -> toRestEntity(twitterBearerToken, tokenStatus, twitterConsumerService, - twitterAccount)) - .toList(); + twitterAccount)); } } diff --git a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/rest/model/EntityList.java b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/rest/model/EntityList.java similarity index 93% rename from gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/rest/model/EntityList.java rename to gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/rest/model/EntityList.java index 84989763..9cec840c 100644 --- a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/rest/model/EntityList.java +++ b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/rest/model/EntityList.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.twitter.rest.model; +package io.meeds.twitter.gamification.rest.model; import java.util.List; @@ -34,5 +34,5 @@ public class EntityList { private int limit; - private int size; + private long size; } diff --git a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/rest/model/TwitterAccountRestEntity.java b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/rest/model/TwitterAccountRestEntity.java similarity index 96% rename from gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/rest/model/TwitterAccountRestEntity.java rename to gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/rest/model/TwitterAccountRestEntity.java index 43cfba4d..a9b96610 100644 --- a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/rest/model/TwitterAccountRestEntity.java +++ b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/rest/model/TwitterAccountRestEntity.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.twitter.rest.model; +package io.meeds.twitter.gamification.rest.model; import lombok.*; diff --git a/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/scheduling/SchedulingConfig.java b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/scheduling/SchedulingConfig.java new file mode 100644 index 00000000..34c1257d --- /dev/null +++ b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/scheduling/SchedulingConfig.java @@ -0,0 +1,24 @@ +/* + * This file is part of the Meeds project (https://meeds.io/). + * Copyright (C) 2020 - 2024 Meeds Association contact@meeds.io + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package io.meeds.twitter.gamification.scheduling; + +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableScheduling; + +@Configuration +@EnableScheduling +public class SchedulingConfig { +} diff --git a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/scheduled/TwitterRemoteUpdateJob.java b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/scheduling/task/TwitterRemoteUpdateTask.java similarity index 73% rename from gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/scheduled/TwitterRemoteUpdateJob.java rename to gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/scheduling/task/TwitterRemoteUpdateTask.java index cc90d2a1..2ea067d0 100644 --- a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/scheduled/TwitterRemoteUpdateJob.java +++ b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/scheduling/task/TwitterRemoteUpdateTask.java @@ -15,64 +15,59 @@ * 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.twitter.scheduled; +package io.meeds.twitter.gamification.scheduling.task; -import io.meeds.gamification.twitter.model.Tweet; -import io.meeds.gamification.twitter.model.TwitterAccount; -import io.meeds.gamification.twitter.model.TwitterTrigger; -import io.meeds.gamification.twitter.service.TwitterService; -import io.meeds.gamification.twitter.service.TwitterConsumerService; -import io.meeds.gamification.twitter.service.TwitterTriggerService; +import io.meeds.twitter.gamification.model.Tweet; +import io.meeds.twitter.gamification.model.TwitterAccount; +import io.meeds.twitter.gamification.model.TwitterTrigger; +import io.meeds.twitter.gamification.service.TwitterConsumerService; +import io.meeds.twitter.gamification.service.TwitterService; +import io.meeds.twitter.gamification.service.TwitterTriggerService; +import io.meeds.twitter.gamification.utils.Utils; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.exoplatform.commons.exception.ObjectNotFoundException; import org.exoplatform.services.log.ExoLogger; import org.exoplatform.services.log.Log; -import org.quartz.DisallowConcurrentExecution; -import org.quartz.Job; -import org.quartz.JobExecutionContext; import org.exoplatform.commons.api.persistence.ExoTransactional; -import org.exoplatform.container.ExoContainerContext; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; import java.util.List; import java.util.Set; -import static io.meeds.gamification.twitter.utils.Utils.extractTweetId; - /** * A service that will manage the periodic updating of twitter events. */ -@DisallowConcurrentExecution -public class TwitterRemoteUpdateJob implements Job { - - private static final Log LOG = ExoLogger.getLogger(TwitterRemoteUpdateJob.class); +@Component +public class TwitterRemoteUpdateTask { - private final TwitterConsumerService twitterConsumerService; + private static final Log LOG = ExoLogger.getLogger(TwitterRemoteUpdateTask.class); - private final TwitterService twitterAccountService; + @Autowired + private TwitterConsumerService twitterConsumerService; - private final TwitterTriggerService twitterTriggerService; + @Autowired + private TwitterService twitterAccountService; - public TwitterRemoteUpdateJob() { - this.twitterTriggerService = ExoContainerContext.getService(TwitterTriggerService.class); - this.twitterConsumerService = ExoContainerContext.getService(TwitterConsumerService.class); - this.twitterAccountService = ExoContainerContext.getService(TwitterService.class); - } + @Autowired + private TwitterTriggerService twitterTriggerService; - @Override @ExoTransactional - public void execute(JobExecutionContext context) { + @Scheduled(cron = "${io.meeds.gamification.TwitterAccountRemoteUpdate.expression:0 */15 * * * ?}") + public void execute() { String bearerToken = twitterAccountService.getTwitterBearerToken(); if (StringUtils.isBlank(bearerToken)) { return; } - List twitterAccounts = twitterAccountService.getTwitterAccounts(0, -1); - if (CollectionUtils.isNotEmpty(twitterAccounts)) { + List twitterAccounts = twitterAccountService.getTwitterAccounts(); + if (!twitterAccounts.isEmpty()) { twitterAccounts.forEach(twitterAccount -> processTwitterAccount(twitterAccount, bearerToken)); } - List tweets = twitterAccountService.getTweets(0, -1); - if (CollectionUtils.isNotEmpty(tweets)) { + List tweets = twitterAccountService.getTweets(); + if (!tweets.isEmpty()) { tweets.forEach(tweet -> processTweetReactionsUpdate(tweet, bearerToken)); } } @@ -108,7 +103,7 @@ private void processTweetReactionsUpdate(Tweet tweet, String bearerToken) { twitterTrigger.setType("tweet"); twitterTrigger.setTrigger("likeTweet"); twitterTrigger.setTwitterUsername(liker); - String tweetId = extractTweetId(tweet.getTweetLink()); + String tweetId = Utils.extractTweetId(tweet.getTweetLink()); if (StringUtils.isNotBlank(tweetId)) { twitterTrigger.setTweetId(Long.parseLong(tweetId)); } @@ -121,7 +116,7 @@ private void processTweetReactionsUpdate(Tweet tweet, String bearerToken) { twitterTrigger.setType("tweet"); twitterTrigger.setTrigger("retweet"); twitterTrigger.setTwitterUsername(retweeter); - String tweetId = extractTweetId(tweet.getTweetLink()); + String tweetId = Utils.extractTweetId(tweet.getTweetLink()); if (StringUtils.isNotBlank(tweetId)) { twitterTrigger.setTweetId(Long.parseLong(tweetId)); } diff --git a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/service/TwitterConsumerService.java b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/service/TwitterConsumerService.java similarity index 82% rename from gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/service/TwitterConsumerService.java rename to gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/service/TwitterConsumerService.java index 91419c1e..75155050 100644 --- a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/service/TwitterConsumerService.java +++ b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/service/TwitterConsumerService.java @@ -15,12 +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.twitter.service; +package io.meeds.twitter.gamification.service; -import io.meeds.gamification.twitter.model.RemoteTwitterAccount; -import io.meeds.gamification.twitter.model.TokenStatus; -import io.meeds.gamification.twitter.model.TwitterAccount; -import io.meeds.gamification.twitter.model.TwitterTrigger; +import io.meeds.twitter.gamification.model.RemoteTwitterAccount; +import io.meeds.twitter.gamification.model.TokenStatus; +import io.meeds.twitter.gamification.model.TwitterAccount; +import io.meeds.twitter.gamification.model.TwitterTrigger; import org.exoplatform.commons.exception.ObjectNotFoundException; import java.util.List; @@ -83,17 +83,4 @@ public interface TwitterConsumerService { * @param bearerToken Twitter bearer token */ List getMentionEvents(TwitterAccount twitterAccount, long lastMentionTweetId, String bearerToken); - - /** - * clear remote twitter account entities cache - */ - void clearCache(); - - /** - * clear remote twitter account entity cache - * - * @param twitterAccount Twitter account - * @param bearerToken Twitter bearer token - */ - void clearCache(TwitterAccount twitterAccount, String bearerToken); } diff --git a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/service/TwitterService.java b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/service/TwitterService.java similarity index 83% rename from gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/service/TwitterService.java rename to gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/service/TwitterService.java index c920a9ef..3c706cbd 100644 --- a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/service/TwitterService.java +++ b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/service/TwitterService.java @@ -16,33 +16,32 @@ * 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.twitter.service; +package io.meeds.twitter.gamification.service; -import io.meeds.gamification.twitter.model.Tweet; -import io.meeds.gamification.twitter.model.TwitterAccount; +import io.meeds.twitter.gamification.model.Tweet; +import io.meeds.twitter.gamification.model.TwitterAccount; import org.exoplatform.commons.ObjectAlreadyExistsException; import org.exoplatform.commons.exception.ObjectNotFoundException; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; import java.util.List; import java.util.Set; +@Service public interface TwitterService { /** - * Get available watched twitter accounts using offset and limit. + * Get available watched twitter accounts using page. * * @param currentUser user name attempting to access watched twitter accounts - * @param offset Offset of result - * @param limit Limit of result - * @param forceUpdate force Load remote accounts or not. + * @param pageable {@link Pageable} the page to be returned. * @return {@link List} of {@link TwitterAccount} * @throws IllegalAccessException when user is not authorized to access watched * twitter accounts */ - List getTwitterAccounts(String currentUser, - int offset, - int limit, - boolean forceUpdate) throws IllegalAccessException; + Page getTwitterAccounts(String currentUser, Pageable pageable) throws IllegalAccessException; /** * Retrieves a watched twitter account identified by its technical identifier. @@ -66,13 +65,19 @@ List getTwitterAccounts(String currentUser, TwitterAccount getTwitterAccountById(long accountId, String username) throws IllegalAccessException, ObjectNotFoundException; /** - * Get available watched twitter accounts using offset and limit. + * Get available watched twitter accounts using page. * - * @param offset Offset of result - * @param limit Limit of result + * @param pageable {@link Pageable} the page to be returned. * @return {@link List} of {@link TwitterAccount} */ - List getTwitterAccounts(int offset, int limit); + Page getTwitterAccounts(Pageable pageable); + + /** + * Get all watched twitter accounts. + * + * @return {@link List} of {@link TwitterAccount} + */ + List getTwitterAccounts(); /** * Count all watched twitter accounts @@ -82,7 +87,7 @@ List getTwitterAccounts(String currentUser, * @throws IllegalAccessException when user is not authorized to get watched * twitter accounts */ - int countTwitterAccounts(String currentUser) throws IllegalAccessException; + long countTwitterAccounts(String currentUser) throws IllegalAccessException; /** * Add watched Twitter account. @@ -120,20 +125,26 @@ TwitterAccount addTwitterAccount(String twitterUsername, String currentUser) thr Tweet addTweetToWatch(String tweetLink); /** - * Get available watched tweets using offset and limit. + * Get available watched tweets using page. + * + * @param pageable {@link Pageable} the page to be returned. + * @return {@link List} of {@link Tweet} + */ + Page getTweets(Pageable pageable); + + /** + * Get all watched tweets. * - * @param offset Offset of result - * @param limit Limit of result * @return {@link List} of {@link Tweet} */ - List getTweets(int offset, int limit); + List getTweets(); /** * Count all watched tweets * * @return Watched tweets count */ - int countTweets(); + long countTweets(); /** * Retrieves a watched tweet identified by its link diff --git a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/service/TwitterTriggerService.java b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/service/TwitterTriggerService.java similarity index 88% rename from gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/service/TwitterTriggerService.java rename to gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/service/TwitterTriggerService.java index 1889836b..30ae8e32 100644 --- a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/service/TwitterTriggerService.java +++ b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/service/TwitterTriggerService.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.twitter.service; +package io.meeds.twitter.gamification.service; -import io.meeds.gamification.twitter.model.TwitterTrigger; +import io.meeds.twitter.gamification.model.TwitterTrigger; +import org.springframework.stereotype.Service; +@Service public interface TwitterTriggerService { /** diff --git a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/service/impl/TwitterConsumerServiceImpl.java b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/service/impl/TwitterConsumerServiceImpl.java similarity index 71% rename from gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/service/impl/TwitterConsumerServiceImpl.java rename to gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/service/impl/TwitterConsumerServiceImpl.java index f9443f22..2591139b 100644 --- a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/service/impl/TwitterConsumerServiceImpl.java +++ b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/service/impl/TwitterConsumerServiceImpl.java @@ -15,26 +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.twitter.service.impl; +package io.meeds.twitter.gamification.service.impl; -import io.meeds.gamification.twitter.model.RemoteTwitterAccount; -import io.meeds.gamification.twitter.model.TokenStatus; -import io.meeds.gamification.twitter.model.TwitterAccount; -import io.meeds.gamification.twitter.model.TwitterTrigger; -import io.meeds.gamification.twitter.service.TwitterConsumerService; -import io.meeds.gamification.twitter.storage.TwitterConsumerStorage; +import io.meeds.twitter.gamification.model.RemoteTwitterAccount; +import io.meeds.twitter.gamification.model.TokenStatus; +import io.meeds.twitter.gamification.model.TwitterAccount; +import io.meeds.twitter.gamification.model.TwitterTrigger; +import io.meeds.twitter.gamification.service.TwitterConsumerService; +import io.meeds.twitter.gamification.storage.TwitterConsumerStorage; import org.exoplatform.commons.exception.ObjectNotFoundException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; import java.util.List; import java.util.Set; +@Service public class TwitterConsumerServiceImpl implements TwitterConsumerService { - private final TwitterConsumerStorage twitterConsumerStorage; - - public TwitterConsumerServiceImpl(TwitterConsumerStorage twitterConsumerStorage) { - this.twitterConsumerStorage = twitterConsumerStorage; - } + @Autowired + private TwitterConsumerStorage twitterConsumerStorage; @Override public RemoteTwitterAccount retrieveTwitterAccount(String twitterUsername, String bearerToken) throws ObjectNotFoundException { @@ -63,14 +63,4 @@ public TokenStatus checkTwitterTokenStatus(String bearerToken) { public List getMentionEvents(TwitterAccount twitterAccount, long lastMentionTweetId, String bearerToken) { return twitterConsumerStorage.getMentionEvents(twitterAccount, lastMentionTweetId, bearerToken); } - - @Override - public void clearCache() { - twitterConsumerStorage.clearCache(); - } - - @Override - public void clearCache(TwitterAccount twitterAccount, String bearerToken) { - twitterConsumerStorage.clearCache(twitterAccount, bearerToken); - } } diff --git a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/service/impl/TwitterServiceImpl.java b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/service/impl/TwitterServiceImpl.java similarity index 66% rename from gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/service/impl/TwitterServiceImpl.java rename to gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/service/impl/TwitterServiceImpl.java index 318aef7f..3ed7cd64 100644 --- a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/service/impl/TwitterServiceImpl.java +++ b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/service/impl/TwitterServiceImpl.java @@ -16,85 +16,65 @@ * 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.twitter.service.impl; +package io.meeds.twitter.gamification.service.impl; import io.meeds.gamification.model.RuleDTO; import io.meeds.gamification.model.filter.RuleFilter; import io.meeds.gamification.service.RuleService; -import io.meeds.gamification.twitter.model.RemoteTwitterAccount; -import io.meeds.gamification.twitter.model.Tweet; -import io.meeds.gamification.twitter.model.TwitterAccount; -import io.meeds.gamification.twitter.model.TwitterTrigger; -import io.meeds.gamification.twitter.service.TwitterService; -import io.meeds.gamification.twitter.service.TwitterConsumerService; -import io.meeds.gamification.twitter.storage.TwitterAccountStorage; -import io.meeds.gamification.twitter.storage.TwitterTweetStorage; +import io.meeds.twitter.gamification.model.RemoteTwitterAccount; +import io.meeds.twitter.gamification.model.Tweet; +import io.meeds.twitter.gamification.model.TwitterAccount; +import io.meeds.twitter.gamification.model.TwitterTrigger; +import io.meeds.twitter.gamification.service.TwitterConsumerService; +import io.meeds.twitter.gamification.service.TwitterService; +import io.meeds.twitter.gamification.storage.TwitterAccountStorage; +import io.meeds.twitter.gamification.storage.TwitterTweetStorage; import io.meeds.gamification.utils.Utils; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.exoplatform.commons.ObjectAlreadyExistsException; -import org.exoplatform.commons.api.settings.SettingService; -import org.exoplatform.commons.api.settings.SettingValue; -import org.exoplatform.commons.api.settings.data.Context; -import org.exoplatform.commons.api.settings.data.Scope; import org.exoplatform.commons.exception.ObjectNotFoundException; import org.exoplatform.services.log.ExoLogger; import org.exoplatform.services.log.Log; -import org.exoplatform.web.security.codec.CodecInitializer; -import org.exoplatform.web.security.security.TokenServiceInitializationException; +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 java.util.List; import java.util.Set; -import static io.meeds.gamification.twitter.utils.Utils.ACCOUNT_ID; -import static io.meeds.gamification.twitter.utils.Utils.CONNECTOR_NAME; +import static io.meeds.twitter.gamification.utils.Utils.ACCOUNT_ID; +import static io.meeds.twitter.gamification.utils.Utils.CONNECTOR_NAME; +@Primary +@Service public class TwitterServiceImpl implements TwitterService { - private static final Log LOG = ExoLogger.getLogger(TwitterServiceImpl.class); + private static final Log LOG = ExoLogger.getLogger(TwitterServiceImpl.class); - private static final Scope TWITTER_CONNECTOR_SCOPE = Scope.APPLICATION.id("twitterConnector"); + public static final String NOT_FOUND = " wasn't found"; - private static final String BEARER_TOKEN_KEY = "BEARER_TOKEN"; + @Autowired + private TwitterConsumerService twitterConsumerService; - private final SettingService settingService; + @Autowired + private TwitterAccountStorage twitterAccountStorage; - private final TwitterConsumerService twitterConsumerService; + @Autowired + private TwitterTweetStorage twitterTweetStorage; - private final TwitterAccountStorage twitterAccountStorage; - - private final TwitterTweetStorage twitterTweetStorage; - - private final RuleService ruleService; - - private final CodecInitializer codecInitializer; - - public TwitterServiceImpl(SettingService settingService, - TwitterConsumerService twitterConsumerService, - TwitterAccountStorage twitterAccountStorage, - TwitterTweetStorage twitterTweetStorage, - RuleService ruleService, - CodecInitializer codecInitializer) { - this.settingService = settingService; - this.twitterConsumerService = twitterConsumerService; - this.twitterAccountStorage = twitterAccountStorage; - this.twitterTweetStorage = twitterTweetStorage; - this.ruleService = ruleService; - this.codecInitializer = codecInitializer; - } + @Autowired + private RuleService ruleService; @Override - public List getTwitterAccounts(String currentUser, - int offset, - int limit, - boolean forceUpdate) throws IllegalAccessException { + public Page getTwitterAccounts(String currentUser, + Pageable pageable) throws IllegalAccessException { if (!Utils.isRewardingManager(currentUser)) { throw new IllegalAccessException("The user is not authorized to access Twitter watched accounts"); } - if (forceUpdate) { - twitterConsumerService.clearCache(); - } - return getTwitterAccounts(offset, limit); + return getTwitterAccounts(pageable); } @Override @@ -119,13 +99,17 @@ public TwitterAccount getTwitterAccountById(long accountId, String username) thr } @Override - public List getTwitterAccounts(int offset, int limit) { - List hooksIds = twitterAccountStorage.getTwitterAccountIds(offset, limit); - return hooksIds.stream().map(twitterAccountStorage::getTwitterAccountById).toList(); + public Page getTwitterAccounts(Pageable pageable) { + return twitterAccountStorage.getTwitterAccounts(pageable); + } + + @Override + public List getTwitterAccounts() { + return twitterAccountStorage.getTwitterAccounts(); } @Override - public int countTwitterAccounts(String currentUser) throws IllegalAccessException { + public long countTwitterAccounts(String currentUser) throws IllegalAccessException { if (!Utils.isRewardingManager(currentUser)) { throw new IllegalAccessException("The user is not authorized to access Twitter watched accounts"); } @@ -134,8 +118,8 @@ public int countTwitterAccounts(String currentUser) throws IllegalAccessExceptio @Override public TwitterAccount addTwitterAccount(String twitterUsername, String currentUser) throws ObjectAlreadyExistsException, - IllegalAccessException, - ObjectNotFoundException { + IllegalAccessException, + ObjectNotFoundException { if (!Utils.isRewardingManager(currentUser)) { throw new IllegalAccessException("The user is not authorized to add a twitter watched account"); } @@ -173,10 +157,9 @@ public void deleteTwitterAccount(long twitterAccountId, String currentUser) thro } TwitterAccount twitterAccount = twitterAccountStorage.getTwitterAccountById(twitterAccountId); if (twitterAccount == null) { - throw new ObjectNotFoundException("Twitter account with remote id : " + twitterAccountId + " wasn't found"); + throw new ObjectNotFoundException("Twitter account with remote id : " + twitterAccountId + NOT_FOUND); } twitterAccountStorage.deleteTwitterAccount(twitterAccountId); - twitterConsumerService.clearCache(twitterAccount, getTwitterBearerToken()); RuleFilter ruleFilter = new RuleFilter(true); ruleFilter.setEventType(CONNECTOR_NAME); ruleFilter.setIncludeDeleted(true); @@ -194,6 +177,7 @@ public void deleteTwitterAccount(long twitterAccountId, String currentUser) thro }); } + @Override public Tweet addTweetToWatch(String tweetLink) { Tweet existsTweet = twitterTweetStorage.getTweetByLink(tweetLink); if (existsTweet != null) { @@ -213,13 +197,17 @@ public Tweet addTweetToWatch(String tweetLink) { } @Override - public List getTweets(int offset, int limit) { - List tweetsIds = twitterTweetStorage.getTweets(offset, limit); - return tweetsIds.stream().map(twitterTweetStorage::getTweetById).toList(); - } - + public Page getTweets(Pageable pageable) { + return twitterTweetStorage.getTweets(pageable); + } + + @Override + public List getTweets() { + return twitterTweetStorage.getTweets(); + } + @Override - public int countTweets() { + public long countTweets() { return twitterTweetStorage.countTweets(); } @@ -235,7 +223,7 @@ public Tweet getTweetByLink(String tweetLink) { public void deleteTweet(long tweetId) throws ObjectNotFoundException { Tweet tweet = twitterTweetStorage.getTweetById(tweetId); if (tweet == null) { - throw new ObjectNotFoundException("Tweet with id : " + tweetId + " wasn't found"); + throw new ObjectNotFoundException("Tweet with id : " + tweetId + NOT_FOUND); } twitterTweetStorage.deleteTweet(tweetId); } @@ -254,15 +242,15 @@ public void saveTwitterBearerToken(String bearerToken, String currentUser) throw if (!Utils.isRewardingManager(currentUser)) { throw new IllegalAccessException("The user is not authorized to save or update Twitter Bearer Token"); } - String encodedBearerToken = encode(bearerToken); - this.settingService.set(Context.GLOBAL, TWITTER_CONNECTOR_SCOPE, BEARER_TOKEN_KEY, SettingValue.create(encodedBearerToken)); + twitterAccountStorage.saveTwitterBearerToken(bearerToken); } + @Override public void deleteTwitterBearerToken(String currentUser) throws IllegalAccessException { if (!Utils.isRewardingManager(currentUser)) { throw new IllegalAccessException("The user is not authorized to delete Twitter Bearer Token"); } - this.settingService.remove(Context.GLOBAL, TWITTER_CONNECTOR_SCOPE, BEARER_TOKEN_KEY); + twitterAccountStorage.deleteTwitterBearerToken(); } @Override @@ -275,48 +263,30 @@ public String getTwitterBearerToken(String currentUser) throws IllegalAccessExce @Override public String getTwitterBearerToken() { - SettingValue settingValue = settingService.get(Context.GLOBAL, TWITTER_CONNECTOR_SCOPE, BEARER_TOKEN_KEY); - if (settingValue != null && settingValue.getValue() != null && StringUtils.isNotBlank(settingValue.getValue().toString())) { - return decode(settingValue.getValue().toString()); - } - return null; + return twitterAccountStorage.getTwitterBearerToken(); } + @Override public void updateAccountLastMentionTweetId(long accountId, long lastMentionTweetId) throws ObjectNotFoundException { if (accountId <= 0) { throw new IllegalArgumentException("Account id must be positive"); } TwitterAccount account = twitterAccountStorage.getTwitterAccountById(accountId); if (account == null) { - throw new ObjectNotFoundException("Twitter account with id : " + accountId + " wasn't found"); + throw new ObjectNotFoundException("Twitter account with id : " + accountId + NOT_FOUND); } twitterAccountStorage.updateAccountLastMentionTweetId(accountId, lastMentionTweetId); } + @Override public void updateTweetReactions(long tweetId, Set likers, Set retweeters) throws ObjectNotFoundException { if (tweetId <= 0) { throw new IllegalArgumentException("Tweet id must be positive"); } Tweet tweet = twitterTweetStorage.getTweetById(tweetId); if (tweet == null) { - throw new ObjectNotFoundException("Tweet with id : " + tweetId + " wasn't found"); + throw new ObjectNotFoundException("Tweet with id : " + tweetId + NOT_FOUND); } twitterTweetStorage.updateTweetReactions(tweetId, likers, retweeters); } - - private String encode(String token) { - try { - return codecInitializer.getCodec().encode(token); - } catch (TokenServiceInitializationException e) { - throw new IllegalStateException("Error encrypting token", e); - } - } - - private String decode(String encryptedToken) { - try { - return codecInitializer.getCodec().decode(encryptedToken); - } catch (TokenServiceInitializationException e) { - throw new IllegalStateException("Error decrypting token", e); - } - } } diff --git a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/service/impl/TwitterTriggerServiceImpl.java b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/service/impl/TwitterTriggerServiceImpl.java similarity index 70% rename from gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/service/impl/TwitterTriggerServiceImpl.java rename to gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/service/impl/TwitterTriggerServiceImpl.java index cd85b3a1..65d3cd64 100644 --- a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/service/impl/TwitterTriggerServiceImpl.java +++ b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/service/impl/TwitterTriggerServiceImpl.java @@ -16,21 +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.twitter.service.impl; +package io.meeds.twitter.gamification.service.impl; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import io.meeds.gamification.service.TriggerService; -import io.meeds.gamification.twitter.model.TwitterTrigger; -import io.meeds.gamification.twitter.service.TwitterTriggerService; +import io.meeds.twitter.gamification.model.TwitterTrigger; +import io.meeds.twitter.gamification.service.TwitterTriggerService; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; -import org.eclipse.jetty.util.thread.QueuedThreadPool; -import org.picocontainer.Startable; import org.exoplatform.commons.api.persistence.ExoTransactional; import org.exoplatform.services.listener.ListenerService; @@ -42,55 +38,41 @@ import io.meeds.gamification.model.EventDTO; import io.meeds.gamification.service.ConnectorService; import io.meeds.gamification.service.EventService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Primary; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.springframework.stereotype.Service; -import static io.meeds.gamification.twitter.utils.Utils.*; +import static io.meeds.twitter.gamification.utils.Utils.*; -public class TwitterTriggerServiceImpl implements TwitterTriggerService, Startable { +@Primary +@Service +public class TwitterTriggerServiceImpl implements TwitterTriggerService { private static final Log LOG = ExoLogger.getLogger(TwitterTriggerServiceImpl.class); public static final String GAMIFICATION_GENERIC_EVENT = "exo.gamification.generic.action"; - private final ConnectorService connectorService; + @Autowired + private ConnectorService connectorService; - private final EventService eventService; + @Autowired + private EventService eventService; - private final TriggerService triggerService; + @Autowired + private TriggerService triggerService; - private final IdentityManager identityManager; + @Autowired + private IdentityManager identityManager; - private final ListenerService listenerService; + @Autowired + private ListenerService listenerService; - private ExecutorService executorService; - - public TwitterTriggerServiceImpl(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); - threadFactory.setName("Gamification - Twitter connector"); - executorService = Executors.newCachedThreadPool(threadFactory); - } - - @Override - public void stop() { - if (executorService != null) { - executorService.shutdownNow(); - } - } + @Autowired + private ThreadPoolTaskExecutor threadPoolTaskExecutor; public void handleTriggerAsync(TwitterTrigger twitterTrigger) { - executorService.execute(() -> handleTriggerAsyncInternal(twitterTrigger)); + threadPoolTaskExecutor.execute(() -> handleTriggerAsyncInternal(twitterTrigger)); } @ExoTransactional diff --git a/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/storage/TwitterAccountStorage.java b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/storage/TwitterAccountStorage.java new file mode 100644 index 00000000..94a92a46 --- /dev/null +++ b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/storage/TwitterAccountStorage.java @@ -0,0 +1,145 @@ +/* + * This file is part of the Meeds project (https://meeds.io/). + * + * Copyright (C) 2020 - 2024 Meeds Association contact@meeds.io + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package io.meeds.twitter.gamification.storage; + +import java.util.Date; +import java.util.List; + +import io.meeds.twitter.gamification.dao.TwitterAccountDAO; +import io.meeds.twitter.gamification.entity.TwitterAccountEntity; +import io.meeds.twitter.gamification.model.TwitterAccount; +import io.meeds.twitter.gamification.storage.mapper.TwitterAccountMapper; +import org.apache.commons.lang3.StringUtils; +import org.exoplatform.commons.ObjectAlreadyExistsException; +import org.exoplatform.commons.api.settings.SettingService; +import org.exoplatform.commons.api.settings.SettingValue; +import org.exoplatform.commons.api.settings.data.Context; +import org.exoplatform.commons.api.settings.data.Scope; +import org.exoplatform.web.security.codec.CodecInitializer; +import org.exoplatform.web.security.security.TokenServiceInitializationException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Repository; + +import static io.meeds.twitter.gamification.storage.mapper.TwitterAccountMapper.fromEntity; +import static io.meeds.twitter.gamification.storage.mapper.TwitterAccountMapper.toEntity; + +@Repository +public class TwitterAccountStorage { + + private static final Scope TWITTER_CONNECTOR_SCOPE = Scope.APPLICATION.id("twitterConnector"); + + private static final String BEARER_TOKEN_KEY = "BEARER_TOKEN"; + + @Autowired + private TwitterAccountDAO twitterAccountDAO; + + @Autowired + private SettingService settingService; + + @Autowired + private CodecInitializer codecInitializer; + + public TwitterAccount addTwitterAccount(TwitterAccount twitterAccount) throws ObjectAlreadyExistsException { + TwitterAccount existsAccount = getTwitterAccountByRemoteId(twitterAccount.getRemoteId()); + if (existsAccount == null) { + TwitterAccountEntity twitterAccountEntity = toEntity(twitterAccount); + twitterAccountEntity.setWatchedDate(new Date()); + twitterAccountEntity.setUpdatedDate(new Date()); + twitterAccountEntity.setRefreshDate(new Date()); + twitterAccountEntity = twitterAccountDAO.save(twitterAccountEntity); + return fromEntity(twitterAccountEntity); + } else { + throw new ObjectAlreadyExistsException(existsAccount); + } + } + + public TwitterAccount getTwitterAccountById(Long id) { + return fromEntity(twitterAccountDAO.findById(id).orElse(null)); + } + + public Page getTwitterAccounts(Pageable pageable) { + Page page = twitterAccountDAO.findAll(pageable); + return page.map(TwitterAccountMapper::fromEntity); + } + + public List getTwitterAccounts() { + List twitterAccountEntities = twitterAccountDAO.findAll(); + return twitterAccountEntities.stream().map(TwitterAccountMapper::fromEntity).toList(); + } + + public long countTwitterAccounts() { + return twitterAccountDAO.count(); + } + + public TwitterAccount getTwitterAccountByRemoteId(long remoteId) { + TwitterAccountEntity twitterAccountEntity = twitterAccountDAO.findTwitterAccountEntityByRemoteId(remoteId); + return fromEntity(twitterAccountEntity); + } + + public TwitterAccount updateAccountLastMentionTweetId(long accountId, long lastMentionTweetId) { + TwitterAccountEntity twitterAccountEntity = twitterAccountDAO.findById(accountId).orElse(null); + if (twitterAccountEntity == null) { + return null; + } + twitterAccountEntity.setLastMentionTweetId(lastMentionTweetId); + return fromEntity(twitterAccountDAO.save(twitterAccountEntity)); + } + + public TwitterAccount deleteTwitterAccount(long accountId) { + TwitterAccountEntity twitterAccountEntity = twitterAccountDAO.findById(accountId).orElse(null); + if (twitterAccountEntity != null) { + twitterAccountDAO.delete(twitterAccountEntity); + } + return fromEntity(twitterAccountEntity); + } + + public void saveTwitterBearerToken(String bearerToken) { + String encodedBearerToken = encode(bearerToken); + this.settingService.set(Context.GLOBAL, TWITTER_CONNECTOR_SCOPE, BEARER_TOKEN_KEY, SettingValue.create(encodedBearerToken)); + } + + public void deleteTwitterBearerToken() { + this.settingService.remove(Context.GLOBAL, TWITTER_CONNECTOR_SCOPE, BEARER_TOKEN_KEY); + } + + public String getTwitterBearerToken() { + SettingValue settingValue = settingService.get(Context.GLOBAL, TWITTER_CONNECTOR_SCOPE, BEARER_TOKEN_KEY); + if (settingValue != null && settingValue.getValue() != null && StringUtils.isNotBlank(settingValue.getValue().toString())) { + return decode(settingValue.getValue().toString()); + } + return null; + } + + private String encode(String token) { + try { + return codecInitializer.getCodec().encode(token); + } catch (TokenServiceInitializationException e) { + throw new IllegalStateException("Error encrypting token", e); + } + } + + private String decode(String encryptedToken) { + try { + return codecInitializer.getCodec().decode(encryptedToken); + } catch (TokenServiceInitializationException e) { + throw new IllegalStateException("Error decrypting token", e); + } + } +} diff --git a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/storage/TwitterConsumerStorage.java b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/storage/TwitterConsumerStorage.java similarity index 94% rename from gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/storage/TwitterConsumerStorage.java rename to gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/storage/TwitterConsumerStorage.java index 95bb2a5c..cf5a4ada 100644 --- a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/storage/TwitterConsumerStorage.java +++ b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/storage/TwitterConsumerStorage.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.twitter.storage; +package io.meeds.twitter.gamification.storage; import java.io.IOException; import java.io.InputStream; @@ -27,11 +27,12 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import io.meeds.gamification.twitter.exception.TwitterConnectionException; -import io.meeds.gamification.twitter.model.RemoteTwitterAccount; -import io.meeds.gamification.twitter.model.TokenStatus; -import io.meeds.gamification.twitter.model.TwitterAccount; -import io.meeds.gamification.twitter.model.TwitterTrigger; +import io.meeds.twitter.gamification.exception.TwitterConnectionException; +import io.meeds.twitter.gamification.model.RemoteTwitterAccount; +import io.meeds.twitter.gamification.model.TokenStatus; +import io.meeds.twitter.gamification.model.TwitterAccount; +import io.meeds.twitter.gamification.model.TwitterTrigger; +import io.meeds.twitter.gamification.utils.Utils; import org.apache.commons.httpclient.HttpStatus; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; @@ -51,10 +52,10 @@ import org.exoplatform.commons.exception.ObjectNotFoundException; import org.exoplatform.services.log.ExoLogger; import org.exoplatform.services.log.Log; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Repository; -import static io.meeds.gamification.twitter.utils.Utils.MENTION_ACCOUNT_EVENT_NAME; -import static io.meeds.gamification.twitter.utils.Utils.extractTweetId; - +@Repository public class TwitterConsumerStorage { private static final Log LOG = ExoLogger.getLogger(TwitterConsumerStorage.class); @@ -105,6 +106,7 @@ public RemoteTwitterAccount retrieveTwitterAccount(String twitterUsername, Strin return remoteTwitterAccount; } + @Cacheable(value = "gamification.twitter.remoteAccount") public RemoteTwitterAccount retrieveTwitterAccount(long twitterRemoteId, String bearerToken) { URI uri = URI.create(TWITTER_API_URL + "/users/" + twitterRemoteId + "?user.fields=profile_image_url,description"); String response; @@ -175,7 +177,7 @@ public List getMentionEvents(TwitterAccount twitterAccount, long break; // Break the loop if the item is found } } - TwitterTrigger twitterEvent = new TwitterTrigger(MENTION_ACCOUNT_EVENT_NAME, + TwitterTrigger twitterEvent = new TwitterTrigger(Utils.MENTION_ACCOUNT_EVENT_NAME, username, tweetId, "tweet", @@ -186,7 +188,7 @@ public List getMentionEvents(TwitterAccount twitterAccount, long } public Set retrieveTweetLikers(String tweetLink, String bearerToken) { - String tweetId = extractTweetId(tweetLink); + String tweetId = Utils.extractTweetId(tweetLink); if (StringUtils.isNotBlank(tweetId)) { String builder = TWITTER_API_URL + "/tweets/" + tweetId + "/liking_users"; URI uri = URI.create(builder); @@ -214,7 +216,7 @@ public Set retrieveTweetLikers(String tweetLink, String bearerToken) { } public Set retrieveTweetRetweeters(String tweetLink, String bearerToken) { - String tweetId = extractTweetId(tweetLink); + String tweetId = Utils.extractTweetId(tweetLink); if (StringUtils.isNotBlank(tweetId)) { String builder = TWITTER_API_URL + "/tweets/" + tweetId + "/retweeted_by"; URI uri = URI.create(builder); @@ -356,14 +358,6 @@ private HttpClientConnectionManager getClientConnectionManager() { return connectionManager; } - public void clearCache() { // NOSONAR - // implemented in cached storage - } - - public void clearCache(TwitterAccount twitterAccount, String bearerToken) { - // implemented in cached storage - } - @SuppressWarnings("unchecked") private Map fromJsonStringToMap(String jsonString) { try { diff --git a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/storage/TwitterTweetStorage.java b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/storage/TwitterTweetStorage.java similarity index 55% rename from gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/storage/TwitterTweetStorage.java rename to gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/storage/TwitterTweetStorage.java index 836bd8a7..d5b03afd 100644 --- a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/storage/TwitterTweetStorage.java +++ b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/storage/TwitterTweetStorage.java @@ -15,31 +15,34 @@ * 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.twitter.storage; +package io.meeds.twitter.gamification.storage; -import io.meeds.gamification.twitter.dao.TwitterTweetDAO; -import io.meeds.gamification.twitter.entity.TwitterTweetEntity; -import io.meeds.gamification.twitter.model.Tweet; +import io.meeds.twitter.gamification.dao.TwitterTweetDAO; +import io.meeds.twitter.gamification.entity.TwitterTweetEntity; +import io.meeds.twitter.gamification.model.Tweet; +import io.meeds.twitter.gamification.storage.mapper.TwitterTweetMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Repository; import java.util.List; import java.util.Set; -import static io.meeds.gamification.twitter.storage.mapper.TwitterTweetMapper.fromEntity; -import static io.meeds.gamification.twitter.storage.mapper.TwitterTweetMapper.toEntity; +import static io.meeds.twitter.gamification.storage.mapper.TwitterTweetMapper.fromEntity; +import static io.meeds.twitter.gamification.storage.mapper.TwitterTweetMapper.toEntity; +@Repository public class TwitterTweetStorage { - private final TwitterTweetDAO twitterTweetDAO; - - public TwitterTweetStorage(TwitterTweetDAO twitterTweetDAO) { - this.twitterTweetDAO = twitterTweetDAO; - } + @Autowired + private TwitterTweetDAO twitterTweetDAO; public Tweet addTweetToWatch(Tweet tweet) { Tweet existsTweet = getTweetByLink(tweet.getTweetLink()); if (existsTweet == null) { TwitterTweetEntity twitterTweetEntity = toEntity(tweet); - twitterTweetEntity = twitterTweetDAO.create(twitterTweetEntity); + twitterTweetEntity = twitterTweetDAO.save(twitterTweetEntity); return fromEntity(twitterTweetEntity); } else { return null; @@ -47,31 +50,40 @@ public Tweet addTweetToWatch(Tweet tweet) { } public Tweet updateTweetReactions(long tweetId, Set likers, Set retweeters) { - TwitterTweetEntity twitterTweetEntity = twitterTweetDAO.find(tweetId); + TwitterTweetEntity twitterTweetEntity = twitterTweetDAO.findById(tweetId).orElse(null); + if (twitterTweetEntity == null) { + return null; + } twitterTweetEntity.setLikers(likers); twitterTweetEntity.setRetweeters(retweeters); - return fromEntity(twitterTweetDAO.update(twitterTweetEntity)); + return fromEntity(twitterTweetDAO.save(twitterTweetEntity)); + } + + public Page getTweets(Pageable pageable) { + Page page = twitterTweetDAO.findAll(pageable); + return page.map(TwitterTweetMapper::fromEntity); } - public List getTweets(int offset, int limit) { - return twitterTweetDAO.getTweetsIds(offset, limit); + public List getTweets() { + List twitterTweetEntities = twitterTweetDAO.findAll(); + return twitterTweetEntities.stream().map(TwitterTweetMapper::fromEntity).toList(); } - public int countTweets() { - return twitterTweetDAO.count().intValue(); + public long countTweets() { + return twitterTweetDAO.count(); } public Tweet getTweetById(Long tweetId) { - return fromEntity(twitterTweetDAO.find(tweetId)); + return fromEntity(twitterTweetDAO.findById(tweetId).orElse(null)); } public Tweet getTweetByLink(String tweetLink) { - TwitterTweetEntity twitterTweetEntity = twitterTweetDAO.getTweetByLink(tweetLink); + TwitterTweetEntity twitterTweetEntity = twitterTweetDAO.findTwitterTweetEntityByTweetLink(tweetLink); return fromEntity(twitterTweetEntity); } public Tweet deleteTweet(long tweetId) { - TwitterTweetEntity twitterTweetEntity = twitterTweetDAO.find(tweetId); + TwitterTweetEntity twitterTweetEntity = twitterTweetDAO.findById(tweetId).orElse(null); if (twitterTweetEntity != null) { twitterTweetDAO.delete(twitterTweetEntity); } diff --git a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/storage/mapper/TwitterAccountMapper.java b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/storage/mapper/TwitterAccountMapper.java similarity index 86% rename from gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/storage/mapper/TwitterAccountMapper.java rename to gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/storage/mapper/TwitterAccountMapper.java index 1e7dd075..52bc8ea6 100644 --- a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/storage/mapper/TwitterAccountMapper.java +++ b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/storage/mapper/TwitterAccountMapper.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.twitter.storage.mapper; +package io.meeds.twitter.gamification.storage.mapper; -import io.meeds.gamification.twitter.entity.TwitterAccountEntity; -import io.meeds.gamification.twitter.model.TwitterAccount; +import io.meeds.twitter.gamification.entity.TwitterAccountEntity; +import io.meeds.twitter.gamification.model.TwitterAccount; import org.apache.commons.lang3.StringUtils; import org.exoplatform.commons.utils.CommonsUtils; @@ -66,8 +66,11 @@ public static TwitterAccount fromEntity(TwitterAccountEntity twitterAccountEntit if (twitterAccountEntity == null) { return null; } - IdentityManager identityManager = CommonsUtils.getService(IdentityManager.class); - String watchedBy = identityManager.getIdentity(String.valueOf(twitterAccountEntity.getWatchedBy())).getRemoteId(); + String watchedBy = null; + if (twitterAccountEntity.getWatchedBy() != null) { + IdentityManager identityManager = CommonsUtils.getService(IdentityManager.class); + watchedBy = identityManager.getIdentity(String.valueOf(twitterAccountEntity.getWatchedBy())).getRemoteId(); + } return new TwitterAccount(twitterAccountEntity.getId(), twitterAccountEntity.getRemoteId(), twitterAccountEntity.getIdentifier(), @@ -79,7 +82,8 @@ public static TwitterAccount fromEntity(TwitterAccountEntity twitterAccountEntit : null, twitterAccountEntity.getRefreshDate() != null ? Utils.toSimpleDateFormat(twitterAccountEntity.getRefreshDate()) : null, - twitterAccountEntity.getLastMentionTweetId() != null ? twitterAccountEntity.getLastMentionTweetId() : 0); + twitterAccountEntity.getLastMentionTweetId() != null ? twitterAccountEntity.getLastMentionTweetId() + : 0); } } diff --git a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/storage/mapper/TwitterTweetMapper.java b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/storage/mapper/TwitterTweetMapper.java similarity index 78% rename from gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/storage/mapper/TwitterTweetMapper.java rename to gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/storage/mapper/TwitterTweetMapper.java index 594469fe..9fa8ff48 100644 --- a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/storage/mapper/TwitterTweetMapper.java +++ b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/storage/mapper/TwitterTweetMapper.java @@ -16,20 +16,13 @@ * 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.twitter.storage.mapper; +package io.meeds.twitter.gamification.storage.mapper; -import io.meeds.gamification.twitter.entity.TwitterTweetEntity; -import io.meeds.gamification.twitter.model.Tweet; +import io.meeds.twitter.gamification.entity.TwitterTweetEntity; +import io.meeds.twitter.gamification.model.Tweet; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; -import org.exoplatform.commons.utils.CommonsUtils; -import org.exoplatform.social.core.manager.IdentityManager; - -import io.meeds.gamification.twitter.entity.TwitterAccountEntity; -import io.meeds.gamification.twitter.model.TwitterAccount; -import io.meeds.gamification.utils.Utils; - public class TwitterTweetMapper { private TwitterTweetMapper() { @@ -43,7 +36,7 @@ public static TwitterTweetEntity toEntity(Tweet tweet) { TwitterTweetEntity twitterTweetEntity = new TwitterTweetEntity(); if (tweet.getTweetId() > 0) { - twitterTweetEntity.setTweetId(tweet.getTweetId()); + twitterTweetEntity.setId(tweet.getTweetId()); } if (StringUtils.isNotBlank(tweet.getTweetLink())) { twitterTweetEntity.setTweetLink(tweet.getTweetLink()); @@ -61,7 +54,7 @@ public static Tweet fromEntity(TwitterTweetEntity twitterTweetEntity) { if (twitterTweetEntity == null) { return null; } - return new Tweet(twitterTweetEntity.getTweetId(), + return new Tweet(twitterTweetEntity.getId(), twitterTweetEntity.getTweetLink(), twitterTweetEntity.getLikers(), twitterTweetEntity.getRetweeters()); diff --git a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/utils/Utils.java b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/utils/Utils.java similarity index 98% rename from gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/utils/Utils.java rename to gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/utils/Utils.java index 8595877d..fe38b2f9 100644 --- a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/utils/Utils.java +++ b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/utils/Utils.java @@ -16,7 +16,7 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ -package io.meeds.gamification.twitter.utils; +package io.meeds.twitter.gamification.utils; import java.util.HashMap; import java.util.Map; diff --git a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/web/TwitterConnectorFilter.java b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/web/TwitterConnectionFilter.java similarity index 57% rename from gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/web/TwitterConnectorFilter.java rename to gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/web/TwitterConnectionFilter.java index 2bbe3aa0..a248d21d 100644 --- a/gamification-twitter-services/src/main/java/io/meeds/gamification/twitter/web/TwitterConnectorFilter.java +++ b/gamification-twitter-services/src/main/java/io/meeds/twitter/gamification/web/TwitterConnectionFilter.java @@ -16,9 +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.twitter.web; - -import java.io.IOException; +package io.meeds.twitter.gamification.web; import org.apache.commons.lang3.StringUtils; @@ -28,58 +26,40 @@ import com.github.scribejava.core.pkce.PKCECodeChallengeMethod; import org.exoplatform.commons.utils.CommonsUtils; -import org.exoplatform.services.log.ExoLogger; -import org.exoplatform.services.log.Log; -import org.exoplatform.web.filter.Filter; import io.meeds.gamification.model.RemoteConnectorSettings; import io.meeds.gamification.service.ConnectorSettingService; -import io.meeds.gamification.twitter.model.TwitterOAuth20Api; -import io.meeds.oauth.exception.OAuthException; -import io.meeds.oauth.exception.OAuthExceptionCode; - -import jakarta.servlet.FilterChain; -import jakarta.servlet.ServletRequest; -import jakarta.servlet.ServletResponse; -import jakarta.servlet.http.HttpServletResponse; +import io.meeds.twitter.gamification.model.TwitterOAuth20Api; -import static io.meeds.gamification.twitter.utils.Utils.CONNECTOR_NAME; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.servlet.ModelAndView; -public class TwitterConnectorFilter implements Filter { +import static io.meeds.twitter.gamification.utils.Utils.CONNECTOR_NAME; - private static final Log LOG = ExoLogger.getLogger(TwitterConnectorFilter.class); +@Controller +@RequestMapping("/") +public class TwitterConnectionFilter { - private OAuth20Service oAuthService; + private OAuth20Service oAuthService; - private long remoteConnectorId; + private long remoteConnectorId; - @Override - public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) { + @GetMapping("/oauth") + public ModelAndView redirectToAuthorization() { ConnectorSettingService connectorSettingService = CommonsUtils.getService(ConnectorSettingService.class); RemoteConnectorSettings remoteConnectorSettings = connectorSettingService.getConnectorSettings(CONNECTOR_NAME); remoteConnectorSettings.setSecretKey(connectorSettingService.getConnectorSecretKey(CONNECTOR_NAME)); + if (StringUtils.isBlank(remoteConnectorSettings.getApiKey()) || StringUtils.isBlank(remoteConnectorSettings.getSecretKey())) { - LOG.warn("Missing '{}' connector settings", CONNECTOR_NAME); - return; - } - HttpServletResponse httpResponse = (HttpServletResponse) response; - try { - String secretState = "state"; - PKCE pkce = new PKCE(); - pkce.setCodeChallenge("challenge"); - pkce.setCodeChallengeMethod(PKCECodeChallengeMethod.PLAIN); - pkce.setCodeVerifier("challenge"); - String authorizationUrl = getOAuthService(remoteConnectorSettings).createAuthorizationUrlBuilder() - .pkce(pkce) - .state(secretState) - .build(); - if (StringUtils.isNotBlank(authorizationUrl)) { - // Redirect to twitter to perform authentication - httpResponse.sendRedirect(authorizationUrl); - } - } catch (IOException e) { // NOSONAR - throw new OAuthException(OAuthExceptionCode.IO_ERROR, e); + // Handle missing connector settings, perhaps by showing an error page or + // message + return new ModelAndView("errorPage"); // Assume errorPage is a valid view } + + String authorizationUrl = getAuthorizationUrl(remoteConnectorSettings); + return new ModelAndView("redirect:" + authorizationUrl); } private OAuth20Service getOAuthService(RemoteConnectorSettings remoteConnectorSettings) { @@ -92,4 +72,14 @@ private OAuth20Service getOAuthService(RemoteConnectorSettings remoteConnectorSe } return oAuthService; } + + private String getAuthorizationUrl(RemoteConnectorSettings remoteConnectorSettings) { + String secretState = "state"; + PKCE pkce = new PKCE(); + pkce.setCodeChallenge("challenge"); + pkce.setCodeChallengeMethod(PKCECodeChallengeMethod.PLAIN); + pkce.setCodeVerifier("challenge"); + + return getOAuthService(remoteConnectorSettings).createAuthorizationUrlBuilder().pkce(pkce).state(secretState).build(); + } } diff --git a/gamification-twitter-services/src/main/resources/conf/portal/configuration.xml b/gamification-twitter-services/src/main/resources/conf/portal/configuration.xml index b49f390c..a8464688 100644 --- a/gamification-twitter-services/src/main/resources/conf/portal/configuration.xml +++ b/gamification-twitter-services/src/main/resources/conf/portal/configuration.xml @@ -22,146 +22,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.twitter.dao.TwitterAccountDAO - - - - io.meeds.gamification.twitter.dao.TwitterTweetDAO - - - - io.meeds.gamification.twitter.storage.TwitterAccountStorage - - - - io.meeds.gamification.twitter.storage.TwitterTweetStorage - - - - io.meeds.gamification.twitter.storage.TwitterConsumerStorage - io.meeds.gamification.twitter.storage.cached.TwitterConsumerCachedStorage - - - - io.meeds.gamification.twitter.service.TwitterConsumerService - io.meeds.gamification.twitter.service.impl.TwitterConsumerServiceImpl - - - - io.meeds.gamification.twitter.service.TwitterTriggerService - io.meeds.gamification.twitter.service.impl.TwitterTriggerServiceImpl - - - - io.meeds.gamification.twitter.service.TwitterService - io.meeds.gamification.twitter.service.impl.TwitterServiceImpl - - - - io.meeds.gamification.twitter.rest.TwitterServiceRest - - - - io.meeds.gamification.service.ConnectorService - - twitter - addPlugin - io.meeds.gamification.twitter.plugin.TwitterConnectorPlugin - - - - - io.meeds.gamification.service.EventService - - twitter - addPlugin - io.meeds.gamification.twitter.plugin.TwitterEventPlugin - - - - - org.exoplatform.web.filter.ExtensibleFilter - - Twitter Oauth Redirect Filter - addFilterDefinitions - org.exoplatform.web.filter.FilterDefinitionPlugin - - - Twitter Oauth Redirect Filter - - - - - - - - /twitterOauth - - - - - - - - - - - org.exoplatform.commons.api.persistence.DataInitializer - - GamificationChangeLogsPlugin - addChangeLogsPlugin - org.exoplatform.commons.persistence.impl.ChangeLogsPlugin - - - changelogs - Change logs of Twitter Connector - db/changelog/twitter-connector.db.changelog-1.0.0.xml - - - - - - - org.exoplatform.services.scheduler.JobSchedulerService - - TwitterAccountRemoteUpdate - addCronJob - org.exoplatform.services.scheduler.CronJob - Configuration to manage the periodic updating of twitter account events - - - cronjob.info - Configuration to manage the periodic updating of twitter account events - - - - - - - - - - - org.exoplatform.services.listener.ListenerService - - rule.created - addListener - io.meeds.gamification.twitter.listener.RuleUpdateTwitterListener - - - rule.deleted - addListener - io.meeds.gamification.twitter.listener.RuleUpdateTwitterListener - - - rule.updated - addListener - io.meeds.gamification.twitter.listener.RuleUpdateTwitterListener - - - jar:/conf/portal/gamification-twitter-connector-configuration.xml \ No newline at end of file diff --git a/gamification-twitter-services/src/main/resources/jpa-entities.idx b/gamification-twitter-services/src/main/resources/jpa-entities.idx index d6aa1da5..5dfa8354 100644 --- a/gamification-twitter-services/src/main/resources/jpa-entities.idx +++ b/gamification-twitter-services/src/main/resources/jpa-entities.idx @@ -1,2 +1,2 @@ -io.meeds.gamification.twitter.entity.TwitterAccountEntity -io.meeds.gamification.twitter.entity.TwitterTweetEntity +io.meeds.twitter.gamification.entity.TwitterAccountEntity +io.meeds.twitter.gamification.entity.TwitterTweetEntity diff --git a/gamification-twitter-services/src/test/java/io/meeds/gamification/twitter/BaseTwitterTest.java b/gamification-twitter-services/src/test/java/io/meeds/gamification/twitter/BaseTwitterTest.java deleted file mode 100644 index 7252f471..00000000 --- a/gamification-twitter-services/src/test/java/io/meeds/gamification/twitter/BaseTwitterTest.java +++ /dev/null @@ -1,155 +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.twitter; - -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.twitter.dao.TwitterAccountDAO; -import io.meeds.gamification.twitter.dao.TwitterTweetDAO; -import io.meeds.gamification.twitter.service.TwitterConsumerService; -import io.meeds.gamification.twitter.service.TwitterService; -import io.meeds.gamification.twitter.service.TwitterTriggerService; -import io.meeds.gamification.twitter.service.impl.TwitterServiceImpl; -import io.meeds.gamification.twitter.service.impl.TwitterTriggerServiceImpl; -import io.meeds.gamification.twitter.storage.TwitterAccountStorage; -import io.meeds.gamification.twitter.storage.TwitterTweetStorage; -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/configuration.xml"), - @ConfigurationUnit(scope = ContainerScope.PORTAL, path = "conf/twitter-test-configuration.xml"), }) -public abstract class BaseTwitterTest extends BaseExoTestCase { // NOSONAR - - protected TwitterService twitterService; - - protected TwitterTriggerService twitterTriggerService; - - protected TwitterAccountDAO twitterAccountDAO; - - protected SettingService settingService; - - protected TwitterAccountStorage twitterAccountStorage; - - protected TwitterTweetStorage twitterTweetStorage; - - @Mock - protected TwitterConsumerService twitterConsumerService; - - @Mock - protected RuleService ruleService; - - @Mock - protected ConnectorService connectorService; - - @Mock - protected TriggerService triggerService; - - @Mock - protected ListenerService listenerService; - - @Mock - protected EventService eventService; - - protected CodecInitializer codecInitializer; - - protected TwitterTweetDAO twitterTweetDAO; - - protected IdentityManager identityManager; - - protected IdentityRegistry identityRegistry; - - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - ExoContainerContext.setCurrentContainer(getContainer()); - twitterAccountDAO = ExoContainerContext.getService(TwitterAccountDAO.class); - twitterTweetDAO = ExoContainerContext.getService(TwitterTweetDAO.class); - settingService = ExoContainerContext.getService(SettingService.class); - twitterAccountStorage = ExoContainerContext.getService(TwitterAccountStorage.class); - twitterTweetStorage = ExoContainerContext.getService(TwitterTweetStorage.class); - codecInitializer = ExoContainerContext.getService(CodecInitializer.class); - identityRegistry = ExoContainerContext.getService(IdentityRegistry.class); - identityManager = ExoContainerContext.getService(IdentityManager.class); - twitterTriggerService = new TwitterTriggerServiceImpl(listenerService, - connectorService, - identityManager, - eventService, - triggerService); - twitterService = new TwitterServiceImpl(settingService, - twitterConsumerService, - twitterAccountStorage, - twitterTweetStorage, - ruleService, - codecInitializer); - resetUserSession(); - begin(); - } - - @Override - @After - public void tearDown() { - restartTransaction(); - twitterTweetDAO.deleteAll(); - twitterAccountDAO.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-twitter-services/src/test/java/io/meeds/gamification/twitter/mock/ConnectorServiceMock.java b/gamification-twitter-services/src/test/java/io/meeds/gamification/twitter/mock/ConnectorServiceMock.java deleted file mode 100644 index a0b2b765..00000000 --- a/gamification-twitter-services/src/test/java/io/meeds/gamification/twitter/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.twitter.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-twitter-services/src/test/java/io/meeds/gamification/twitter/mock/ConnectorSettingServiceMock.java b/gamification-twitter-services/src/test/java/io/meeds/gamification/twitter/mock/ConnectorSettingServiceMock.java deleted file mode 100644 index 9d1d57cf..00000000 --- a/gamification-twitter-services/src/test/java/io/meeds/gamification/twitter/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.twitter.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-twitter-services/src/test/java/io/meeds/gamification/twitter/mock/EventServiceMock.java b/gamification-twitter-services/src/test/java/io/meeds/gamification/twitter/mock/EventServiceMock.java deleted file mode 100644 index 8ce855c1..00000000 --- a/gamification-twitter-services/src/test/java/io/meeds/gamification/twitter/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.twitter.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-twitter-services/src/test/java/io/meeds/gamification/twitter/mock/IdentityManagerMock.java b/gamification-twitter-services/src/test/java/io/meeds/gamification/twitter/mock/IdentityManagerMock.java deleted file mode 100644 index aa61dd0e..00000000 --- a/gamification-twitter-services/src/test/java/io/meeds/gamification/twitter/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.twitter.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-twitter-services/src/test/java/io/meeds/gamification/twitter/mock/RuleServiceMock.java b/gamification-twitter-services/src/test/java/io/meeds/gamification/twitter/mock/RuleServiceMock.java deleted file mode 100644 index 35432593..00000000 --- a/gamification-twitter-services/src/test/java/io/meeds/gamification/twitter/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.twitter.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-twitter-services/src/test/java/io/meeds/gamification/twitter/service/TwitterServiceTest.java b/gamification-twitter-services/src/test/java/io/meeds/gamification/twitter/service/TwitterServiceTest.java deleted file mode 100644 index 496e6a67..00000000 --- a/gamification-twitter-services/src/test/java/io/meeds/gamification/twitter/service/TwitterServiceTest.java +++ /dev/null @@ -1,188 +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.twitter.service; - -import static io.meeds.gamification.twitter.utils.Utils.MENTION_ACCOUNT_EVENT_NAME; -import static org.junit.Assert.assertThrows; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.when; - -import io.meeds.gamification.twitter.BaseTwitterTest; -import io.meeds.gamification.twitter.model.RemoteTwitterAccount; -import io.meeds.gamification.twitter.model.Tweet; -import io.meeds.gamification.twitter.model.TwitterAccount; -import io.meeds.gamification.twitter.model.TwitterTrigger; -import org.exoplatform.commons.ObjectAlreadyExistsException; -import org.exoplatform.commons.exception.ObjectNotFoundException; -import org.gatein.common.util.Tools; -import org.junit.Test; - -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -public class TwitterServiceTest extends BaseTwitterTest { - - 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 testAddTwitterAccount() throws Exception { - assertThrows(IllegalAccessException.class, () -> twitterService.addTwitterAccount("twitterUsername", "root")); - - twitterService.saveTwitterBearerToken("bearerToken", "root1"); - RemoteTwitterAccount remoteTwitterAccount = new RemoteTwitterAccount(1, "username", "name", "description", "avatarUrl"); - RemoteTwitterAccount remoteTwitterAccount1 = new RemoteTwitterAccount(2, "username1", "name1", "description1", "avatarUrl1"); - when(twitterConsumerService.retrieveTwitterAccount("twitterUsername", "bearerToken")).thenReturn(remoteTwitterAccount); - when(twitterConsumerService.retrieveTwitterAccount("twitterUsername1", "bearerToken")).thenReturn(remoteTwitterAccount1); - List twitterTriggers = new ArrayList<>(); - TwitterTrigger twitterTrigger = new TwitterTrigger(MENTION_ACCOUNT_EVENT_NAME, "user1", 1254555L, "tweet", 11222121L); - TwitterTrigger twitterTrigger1 = new TwitterTrigger(MENTION_ACCOUNT_EVENT_NAME, "user2", 12548855L, "tweet", 11222121L); - twitterTriggers.add(twitterTrigger); - twitterTriggers.add(twitterTrigger1); - when(twitterConsumerService.getMentionEvents(any(), anyLong(), anyString())).thenReturn(twitterTriggers); - - // When - TwitterAccount twitterAccount = twitterService.addTwitterAccount("twitterUsername", "root1"); - - // Then - assertThrows(IllegalAccessException.class, () -> twitterService.getTwitterAccounts("root", 0, 10, true)); - assertNotNull(twitterService.getTwitterAccounts("root1", 0, 10, true)); - assertThrows(IllegalAccessException.class, () -> twitterService.countTwitterAccounts("root")); - assertEquals(1, twitterService.countTwitterAccounts("root1")); - assertEquals(1254555L, twitterService.getTwitterAccountById(twitterAccount.getId()).getLastMentionTweetId()); - - assertThrows(IllegalAccessException.class, () -> twitterService.getTwitterAccountById(twitterAccount.getId(), "root")); - assertThrows(IllegalArgumentException.class, () -> twitterService.getTwitterAccountById(-10L)); - assertThrows(ObjectNotFoundException.class, () -> twitterService.getTwitterAccountById(10L, "root1")); - assertNotNull(twitterService.getTwitterAccountById(twitterAccount.getId(), "root1")); - - // When - TwitterAccount twitterAccount1 = twitterService.addTwitterAccount("twitterUsername1", "root1"); - - // Then - Throwable exception1 = assertThrows(IllegalStateException.class, - () -> twitterService.addTwitterAccount("twitterUsername2", "root1")); - assertEquals("The maximum number of watched twitter accounts has been reached", exception1.getMessage()); - - // When - twitterService.deleteTwitterAccount(twitterAccount1.getId(), "root1"); - - // Then - assertThrows(ObjectAlreadyExistsException.class, () -> twitterService.addTwitterAccount("twitterUsername", "root1")); - - // When - twitterService.updateAccountLastMentionTweetId(twitterAccount.getId(), 111122222L); - - // Then - assertEquals(111122222L, twitterService.getTwitterAccountById(twitterAccount.getId()).getLastMentionTweetId()); - assertThrows(IllegalArgumentException.class, () -> twitterService.updateAccountLastMentionTweetId(-10L, 111122222L)); - assertThrows(ObjectNotFoundException.class, () -> twitterService.updateAccountLastMentionTweetId(10L, 111122222L)); - } - - @Test - public void testDeleteTwitterAccount() throws Exception { - twitterService.saveTwitterBearerToken("bearerToken", "root1"); - RemoteTwitterAccount remoteTwitterAccount = new RemoteTwitterAccount(1, "username", "name", "description", "avatarUrl"); - when(twitterConsumerService.retrieveTwitterAccount("twitterUsername", "bearerToken")).thenReturn(remoteTwitterAccount); - - // When - TwitterAccount twitterAccount = twitterService.addTwitterAccount("twitterUsername", "root1"); - - // Then - assertThrows(IllegalAccessException.class, () -> twitterService.deleteTwitterAccount(twitterAccount.getId(), "root")); - assertThrows(ObjectNotFoundException.class, () -> twitterService.deleteTwitterAccount(10L, "root1")); - - // When - twitterService.deleteTwitterAccount(twitterAccount.getId(), "root1"); - - // Then - assertNull(twitterService.getTwitterAccountById(twitterAccount.getId())); - } - - @Test - public void testSaveTwitterBearerToken() throws IllegalAccessException { - // When - assertThrows(IllegalAccessException.class, () -> twitterService.saveTwitterBearerToken("bearerToken", "root")); - // When - twitterService.saveTwitterBearerToken("bearerToken", "root1"); - // Then - assertThrows(IllegalAccessException.class, () -> twitterService.getTwitterBearerToken("root")); - - assertNotNull(twitterService.getTwitterBearerToken("root1")); - // When - assertThrows(IllegalAccessException.class, () -> twitterService.deleteTwitterBearerToken("root")); - // When - twitterService.deleteTwitterBearerToken("root1"); - // Then - assertNull(twitterService.getTwitterBearerToken()); - } - - @Test - public void testAddTweetToWatch() throws Exception { - Set tweetLikers = Tools.toSet("user1", "user2", "user3"); - Set tweetRetweeters = Tools.toSet("user1", "user2"); - - twitterService.saveTwitterBearerToken("bearerToken", "root1"); - when(twitterConsumerService.retrieveTweetLikers("tweetLink", "bearerToken")).thenReturn(tweetLikers); - when(twitterConsumerService.retrieveTweetRetweeters("tweetLink", "bearerToken")).thenReturn(tweetRetweeters); - - // When - Tweet tweet = twitterService.addTweetToWatch("tweetLink"); - - // Then - assertEquals(1, twitterService.getTweets(0, 10).size()); - assertThrows(IllegalArgumentException.class, () -> twitterService.getTweetByLink(null)); - assertNotNull(twitterService.getTweetByLink("tweetLink")); - - // When - twitterService.addTweetToWatch("tweetLink"); - - // Then - assertEquals(1, twitterService.getTweets(0, 10).size()); - - // When - twitterService.deleteTweet(tweet.getTweetId()); - - // Then - assertEquals(0, twitterService.getTweets(0, 10).size()); - assertThrows(ObjectNotFoundException.class, () -> twitterService.deleteTweet(-10L)); - - // When - tweet = twitterService.addTweetToWatch("tweetLink"); - tweetLikers = Tools.toSet("user1", "user2", "user3", "user4"); - tweetRetweeters = Tools.toSet("user1", "user2", "user3"); - twitterService.updateTweetReactions(tweet.getTweetId(), tweetLikers, tweetRetweeters); - - // Then - assertEquals(tweetLikers, twitterService.getTweetByLink(tweet.getTweetLink()).getLikers()); - assertEquals(tweetRetweeters, twitterService.getTweetByLink(tweet.getTweetLink()).getRetweeters()); - assertThrows(IllegalArgumentException.class, () -> twitterService.updateTweetReactions(-10, null, null)); - assertThrows(ObjectNotFoundException.class, () -> twitterService.updateTweetReactions(10L, null, null)); - - } -} diff --git a/gamification-twitter-services/src/test/java/io/meeds/twitter/gamification/listener/RuleUpdateTwitterListenerTest.java b/gamification-twitter-services/src/test/java/io/meeds/twitter/gamification/listener/RuleUpdateTwitterListenerTest.java new file mode 100644 index 00000000..7e6754db --- /dev/null +++ b/gamification-twitter-services/src/test/java/io/meeds/twitter/gamification/listener/RuleUpdateTwitterListenerTest.java @@ -0,0 +1,81 @@ +/* + * This file is part of the Meeds project (https://meeds.io/). + * + * Copyright (C) 2020 - 2024 Meeds Association contact@meeds.io + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package io.meeds.twitter.gamification.listener; + +import static org.mockito.Mockito.*; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import co.elastic.clients.elasticsearch.ml.Page; +import io.meeds.gamification.model.EventDTO; +import io.meeds.gamification.model.RuleDTO; +import io.meeds.gamification.model.filter.RuleFilter; +import io.meeds.gamification.service.RuleService; +import io.meeds.twitter.gamification.model.Tweet; +import io.meeds.twitter.gamification.service.TwitterService; +import io.meeds.twitter.gamification.utils.Utils; +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; +import org.springframework.data.domain.PageImpl; + +@SpringBootTest(classes = { RuleUpdateTwitterListener.class, }) +class RuleUpdateTwitterListenerTest { + + @MockBean + private TwitterService twitterAccountService; + + @MockBean + private RuleService ruleService; + + @MockBean + private ListenerService listenerService; + + @MockBean + private RuleDTO rule; + + @MockBean + private Tweet tweet; + + @MockBean + private Event event; + + @Autowired + private RuleUpdateTwitterListener ruleUpdateTwitterListener; + + @Test + void createEvent() { + EventDTO eventDTO = new EventDTO(); + Map properties = new HashMap<>(); + properties.put(Utils.TWEET_LINK, "tweetLink"); + eventDTO.setProperties(properties); + when(rule.getEvent()).thenReturn(eventDTO); + when(ruleService.getRules(any(RuleFilter.class), anyInt(), anyInt())).thenReturn(List.of(rule)); + when(twitterAccountService.getTweets(null)).thenReturn(new PageImpl<>(List.of(tweet))); + when(twitterAccountService.getTwitterBearerToken()).thenReturn("bearerToken"); + ruleUpdateTwitterListener.onEvent(event); + verify(twitterAccountService, times(1)).addTweetToWatch("tweetLink"); + } +} diff --git a/gamification-twitter-services/src/test/java/io/meeds/gamification/twitter/mock/TriggerServiceMock.java b/gamification-twitter-services/src/test/java/io/meeds/twitter/gamification/plugin/TwitterConnectorPluginTest.java similarity index 58% rename from gamification-twitter-services/src/test/java/io/meeds/gamification/twitter/mock/TriggerServiceMock.java rename to gamification-twitter-services/src/test/java/io/meeds/twitter/gamification/plugin/TwitterConnectorPluginTest.java index 3314f813..18e35254 100644 --- a/gamification-twitter-services/src/test/java/io/meeds/gamification/twitter/mock/TriggerServiceMock.java +++ b/gamification-twitter-services/src/test/java/io/meeds/twitter/gamification/plugin/TwitterConnectorPluginTest.java @@ -16,24 +16,24 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ -package io.meeds.gamification.twitter.mock; +package io.meeds.twitter.gamification.plugin; -import io.meeds.gamification.model.TriggerProperties; -import io.meeds.gamification.service.TriggerService; +import io.meeds.twitter.gamification.utils.Utils; +import org.junit.Test; +import org.springframework.boot.test.context.SpringBootTest; -public class TriggerServiceMock implements TriggerService { - @Override - public TriggerProperties getTriggerProperties(String triggerName) { - return null; - } +import static org.junit.jupiter.api.Assertions.*; - @Override - public void setTriggerEnabledForAccount(String triggerName, long accountId, boolean enabled, String currentUser) { +@SpringBootTest(classes = { TwitterConnectorPlugin.class, }) +public class TwitterConnectorPluginTest { - } + @Test + public void testValidateToken() { + // When + TwitterConnectorPlugin twitterConnectorPlugin = new TwitterConnectorPlugin(); - @Override - public boolean isTriggerEnabledForAccount(String triggerName, long accountId) { - return false; + // Then + assertEquals(Utils.CONNECTOR_NAME, twitterConnectorPlugin.getConnectorName()); + assertEquals(Utils.CONNECTOR_NAME, twitterConnectorPlugin.getName()); } } diff --git a/gamification-twitter-services/src/test/java/io/meeds/gamification/twitter/plugin/TwitterEventPluginTest.java b/gamification-twitter-services/src/test/java/io/meeds/twitter/gamification/plugin/TwitterEventPluginTest.java similarity index 56% rename from gamification-twitter-services/src/test/java/io/meeds/gamification/twitter/plugin/TwitterEventPluginTest.java rename to gamification-twitter-services/src/test/java/io/meeds/twitter/gamification/plugin/TwitterEventPluginTest.java index 44537f4c..0ad5da34 100644 --- a/gamification-twitter-services/src/test/java/io/meeds/gamification/twitter/plugin/TwitterEventPluginTest.java +++ b/gamification-twitter-services/src/test/java/io/meeds/twitter/gamification/plugin/TwitterEventPluginTest.java @@ -16,42 +16,46 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ -package io.meeds.gamification.twitter.plugin; +package io.meeds.twitter.gamification.plugin; -import io.meeds.gamification.twitter.BaseTwitterTest; +import io.meeds.twitter.gamification.utils.Utils; import org.junit.Test; +import org.springframework.boot.test.context.SpringBootTest; import java.util.HashMap; import java.util.List; import java.util.Map; -import static io.meeds.gamification.twitter.plugin.TwitterEventPlugin.EVENT_TYPE; -import static io.meeds.gamification.twitter.utils.Utils.*; +import static io.meeds.twitter.gamification.plugin.TwitterEventPlugin.EVENT_TYPE; +import static org.junit.jupiter.api.Assertions.*; -public class TwitterEventPluginTest extends BaseTwitterTest { +@SpringBootTest(classes = { TwitterEventPlugin.class, }) +public class TwitterEventPluginTest { @Test public void testIsValidEvent() { TwitterEventPlugin twitterEventPlugin = new TwitterEventPlugin(); assertEquals(EVENT_TYPE, twitterEventPlugin.getEventType()); - assertEquals(List.of(MENTION_ACCOUNT_EVENT_NAME, LIKE_TWEET_EVENT_NAME, RETWEET_TWEET_EVENT_NAME), + assertEquals(List.of(Utils.MENTION_ACCOUNT_EVENT_NAME, Utils.LIKE_TWEET_EVENT_NAME, Utils.RETWEET_TWEET_EVENT_NAME), twitterEventPlugin.getTriggers()); Map eventProperties = new HashMap<>(); - eventProperties.put(ACCOUNT_ID, "132452"); + eventProperties.put(Utils.ACCOUNT_ID, "132452"); assertFalse(twitterEventPlugin.isValidEvent(eventProperties, - "{" + ACCOUNT_ID + ": " + 13245258 + ", " + TWEET_ID + ": " + null + "}")); + "{" + Utils.ACCOUNT_ID + ": " + 13245258 + ", " + Utils.TWEET_ID + ": " + null + + "}")); assertTrue(twitterEventPlugin.isValidEvent(eventProperties, - "{" + ACCOUNT_ID + ": " + 132452 + ", " + TWEET_ID + ": " + null + "}")); + "{" + Utils.ACCOUNT_ID + ": " + 132452 + ", " + Utils.TWEET_ID + ": " + null + + "}")); eventProperties = new HashMap<>(); - eventProperties.put(TWEET_LINK, "https://twitter.com/IoMeeds/status/1760291687425798481"); + eventProperties.put(Utils.TWEET_LINK, "https://twitter.com/IoMeeds/status/1760291687425798481"); assertFalse(twitterEventPlugin.isValidEvent(eventProperties, - "{" + ACCOUNT_ID + ": " + null + ", " + TWEET_ID + ": " + 1760291687425798482L - + "}")); + "{" + Utils.ACCOUNT_ID + ": " + null + ", " + Utils.TWEET_ID + ": " + + 1760291687425798482L + "}")); assertTrue(twitterEventPlugin.isValidEvent(eventProperties, - "{" + ACCOUNT_ID + ": " + null + ", " + TWEET_ID + ": " + 1760291687425798481L - + "}")); + "{" + Utils.ACCOUNT_ID + ": " + null + ", " + Utils.TWEET_ID + ": " + + 1760291687425798481L + "}")); } } diff --git a/gamification-twitter-services/src/test/java/io/meeds/twitter/gamification/rest/TwitterAccountRestTest.java b/gamification-twitter-services/src/test/java/io/meeds/twitter/gamification/rest/TwitterAccountRestTest.java new file mode 100644 index 00000000..f72dd79b --- /dev/null +++ b/gamification-twitter-services/src/test/java/io/meeds/twitter/gamification/rest/TwitterAccountRestTest.java @@ -0,0 +1,233 @@ +/* + * This file is part of the Meeds project (https://meeds.io/). + * + * Copyright (C) 2020 - 2024 Meeds Association contact@meeds.io + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package io.meeds.twitter.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 io.meeds.twitter.gamification.model.TwitterAccount; +import io.meeds.twitter.gamification.service.TwitterConsumerService; +import io.meeds.twitter.gamification.service.TwitterService; +import org.exoplatform.commons.ObjectAlreadyExistsException; +import org.exoplatform.commons.exception.ObjectNotFoundException; +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.data.domain.Pageable; +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 io.meeds.spring.web.security.PortalAuthenticationManager; +import io.meeds.spring.web.security.WebSecurityConfiguration; +import jakarta.servlet.Filter; + +import java.util.Arrays; +import java.util.List; + +@SpringBootTest(classes = { TwitterAccountRest.class, PortalAuthenticationManager.class, }) +@ContextConfiguration(classes = { WebSecurityConfiguration.class }) +@AutoConfigureWebMvc +@AutoConfigureMockMvc(addFilters = false) +@ExtendWith(MockitoExtension.class) +class TwitterAccountRestTest { + + private static final String REST_PATH = "/accounts"; // NOSONAR + + private static final String SIMPLE_USER = "simple"; + + private static final String TEST_PASSWORD = "testPassword"; + + private static final Pageable PAGEABLE = Pageable.ofSize(2); + + @MockBean + private TwitterService twitterService; + + @MockBean + private TwitterConsumerService twitterConsumerService; + + @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 getWatchedAccountsAnonymously() throws Exception { + ResultActions response = mockMvc.perform(get(REST_PATH)); + response.andExpect(status().isForbidden()); + } + + @Test + void getWatchedAccountsSimpleUser() throws Exception { + when(twitterService.getTwitterAccounts(eq(SIMPLE_USER), any())).thenReturn(new PageImpl<>(List.of(newWatchedAccount()))); + + ResultActions response = mockMvc.perform(get(REST_PATH).with(testSimpleUser())); + response.andExpect(status().isOk()); + + doThrow(new IllegalAccessException()).when(twitterService).getTwitterAccounts(eq(SIMPLE_USER), any()); + + response = mockMvc.perform(get(REST_PATH).with(testSimpleUser())); + response.andExpect(status().isUnauthorized()); + } + + @Test + void getWatchedAccountByIdAnonymously() throws Exception { + ResultActions response = mockMvc.perform(get(REST_PATH + "/" + 1)); + response.andExpect(status().isForbidden()); + } + + @Test + void getWatchedAccountByIdSimpleUser() throws Exception { + 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(twitterService).getTwitterAccountById(1, SIMPLE_USER); + + response = mockMvc.perform(get(REST_PATH + "/" + 1).with(testSimpleUser())); + response.andExpect(status().isUnauthorized()); + + doThrow(new IllegalArgumentException()).when(twitterService).getTwitterAccountById(1, SIMPLE_USER); + + response = mockMvc.perform(get(REST_PATH + "/" + 1).with(testSimpleUser())); + response.andExpect(status().isBadRequest()); + + doThrow(new ObjectNotFoundException("Twitter account doesn't exist")).when(twitterService) + .getTwitterAccountById(1, SIMPLE_USER); + + response = mockMvc.perform(get(REST_PATH + "/" + 1).with(testSimpleUser())); + response.andExpect(status().isNotFound()); + } + + @Test + void createWatchedAccountAnonymously() throws Exception { + ResultActions response = mockMvc.perform(post(REST_PATH).param("twitterUsername", "twitterUsername") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)); + response.andExpect(status().isForbidden()); + } + + @Test + void createWatchedAccountSimpleUser() throws Exception { + ResultActions response = mockMvc.perform(post(REST_PATH).param("twitterUsername", "") + .with(testSimpleUser()) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)); + response.andExpect(status().isBadRequest()); + + response = mockMvc.perform(post(REST_PATH).param("twitterUsername", "twitterUsername") + .with(testSimpleUser()) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)); + response.andExpect(status().isOk()); + + doThrow(new IllegalAccessException()).when(twitterService).addTwitterAccount("twitterUsername", SIMPLE_USER); + + response = mockMvc.perform(post(REST_PATH).param("twitterUsername", "twitterUsername") + .with(testSimpleUser()) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)); + response.andExpect(status().isUnauthorized()); + + doThrow(new ObjectAlreadyExistsException(new TwitterAccount())).when(twitterService) + .addTwitterAccount("twitterUsername", SIMPLE_USER); + + response = mockMvc.perform(post(REST_PATH).param("twitterUsername", "twitterUsername") + .with(testSimpleUser()) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)); + response.andExpect(status().isConflict()); + + doThrow(new ObjectNotFoundException("twitter.accountNotFound")).when(twitterService) + .addTwitterAccount("twitterUsername", SIMPLE_USER); + + response = mockMvc.perform(post(REST_PATH).param("twitterUsername", "twitterUsername") + .with(testSimpleUser()) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)); + response.andExpect(status().isNotFound()); + } + + @Test + void deleteTwitterBearerTokenAnonymously() throws Exception { + ResultActions response = mockMvc.perform(delete(REST_PATH + "/" + 1).contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)); + response.andExpect(status().isForbidden()); + } + + @Test + void deleteTwitterBearerTokenSimpleUser() 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(twitterService).deleteTwitterAccount(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("Twitter account doesn't exist")).when(twitterService) + .deleteTwitterAccount(1, SIMPLE_USER); + + response = mockMvc.perform(delete(REST_PATH + "/" + 1).with(testSimpleUser()) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)); + response.andExpect(status().isNotFound()); + } + + private RequestPostProcessor testSimpleUser() { + return user(SIMPLE_USER).password(TEST_PASSWORD).authorities(new SimpleGrantedAuthority("users")); + } + + private TwitterAccount newWatchedAccount() { + return new TwitterAccount(1, 12314, "identifier", "name", "watchedDate", "watchedBy", "updatedDate", "refreshDate", 1234); + } + +} diff --git a/gamification-twitter-services/src/test/java/io/meeds/twitter/gamification/rest/TwitterSettingsRestTest.java b/gamification-twitter-services/src/test/java/io/meeds/twitter/gamification/rest/TwitterSettingsRestTest.java new file mode 100644 index 00000000..310a4fa1 --- /dev/null +++ b/gamification-twitter-services/src/test/java/io/meeds/twitter/gamification/rest/TwitterSettingsRestTest.java @@ -0,0 +1,187 @@ +/* + * This file is part of the Meeds project (https://meeds.io/). + * + * Copyright (C) 2020 - 2024 Meeds Association contact@meeds.io + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package io.meeds.twitter.gamification.rest; + +import static org.mockito.Mockito.*; +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 io.meeds.twitter.gamification.service.TwitterConsumerService; +import io.meeds.twitter.gamification.service.TwitterService; +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.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 io.meeds.spring.web.security.PortalAuthenticationManager; +import io.meeds.spring.web.security.WebSecurityConfiguration; +import jakarta.servlet.Filter; + +@SpringBootTest(classes = { TwitterSettingsRest.class, PortalAuthenticationManager.class, }) +@ContextConfiguration(classes = { WebSecurityConfiguration.class }) +@AutoConfigureWebMvc +@AutoConfigureMockMvc(addFilters = false) +@ExtendWith(MockitoExtension.class) +class TwitterSettingsRestTest { + + private static final String REST_PATH = "/settings"; // NOSONAR + + private static final String SIMPLE_USER = "simple"; + + private static final String ADMIN_USER = "admin"; + + private static final String TEST_PASSWORD = "testPassword"; + + @MockBean + private TwitterService twitterService; + + @MockBean + private TwitterConsumerService twitterConsumerService; + + @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 checkTwitterTokenStatusAnonymously() throws Exception { + ResultActions response = mockMvc.perform(get(REST_PATH)); + response.andExpect(status().isForbidden()); + } + + @Test + void checkTwitterTokenStatusSimpleUser() throws Exception { + ResultActions response = mockMvc.perform(get(REST_PATH).with(testSimpleUser())); + response.andExpect(status().isForbidden()); + } + + @Test + void checkTwitterTokenStatusAdmin() throws Exception { + ResultActions response = mockMvc.perform(get(REST_PATH).with(testAdminUser())); + response.andExpect(status().isOk()); + + doThrow(new IllegalAccessException()).when(twitterService).getTwitterBearerToken(ADMIN_USER); + response = mockMvc.perform(get(REST_PATH).with(testAdminUser())); + response.andExpect(status().isUnauthorized()); + } + + @Test + void saveBearerTokenAnonymously() throws Exception { + ResultActions response = mockMvc.perform(post(REST_PATH).param("bearerToken", "bearerToken") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)); + response.andExpect(status().isForbidden()); + } + + @Test + void saveBearerTokenSimpleUser() throws Exception { + ResultActions response = mockMvc.perform(post(REST_PATH).param("bearerToken", "bearerToken") + .with(testSimpleUser()) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)); + response.andExpect(status().isForbidden()); + } + + @Test + void saveBearerTokenAdmin() throws Exception { + ResultActions response = mockMvc.perform(post(REST_PATH).param("bearerToken", "") + .with(testAdminUser()) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)); + response.andExpect(status().isBadRequest()); + + response = mockMvc.perform(post(REST_PATH).param("bearerToken", "bearerToken") + .with(testAdminUser()) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)); + response.andExpect(status().isOk()); + + doThrow(new IllegalAccessException()).when(twitterService).saveTwitterBearerToken("bearerToken", ADMIN_USER); + + response = mockMvc.perform(post(REST_PATH).param("bearerToken", "bearerToken") + .with(testAdminUser()) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)); + response.andExpect(status().isUnauthorized()); + } + + @Test + void deleteTwitterBearerTokenAnonymously() throws Exception { + ResultActions response = mockMvc.perform(delete(REST_PATH).contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)); + response.andExpect(status().isForbidden()); + } + + @Test + void deleteTwitterBearerTokenSimpleUser() throws Exception { + ResultActions response = mockMvc.perform(delete(REST_PATH).with(testSimpleUser()) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)); + response.andExpect(status().isForbidden()); + } + + @Test + void deleteTwitterBearerTokenAdmin() throws Exception { + ResultActions response = mockMvc.perform(delete(REST_PATH).with(testAdminUser()) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)); + response.andExpect(status().isOk()); + + doThrow(new IllegalAccessException()).when(twitterService).deleteTwitterBearerToken(ADMIN_USER); + + response = mockMvc.perform(delete(REST_PATH).with(testAdminUser()) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)); + + response.andExpect(status().isUnauthorized()); + + } + + private RequestPostProcessor testAdminUser() { + return user(ADMIN_USER).password(TEST_PASSWORD).authorities(new SimpleGrantedAuthority("rewarding")); + } + + private RequestPostProcessor testSimpleUser() { + return user(SIMPLE_USER).password(TEST_PASSWORD).authorities(new SimpleGrantedAuthority("users")); + } + +} diff --git a/gamification-twitter-services/src/test/java/io/meeds/twitter/gamification/rest/TwitterTweetRestTest.java b/gamification-twitter-services/src/test/java/io/meeds/twitter/gamification/rest/TwitterTweetRestTest.java new file mode 100644 index 00000000..fb8801dd --- /dev/null +++ b/gamification-twitter-services/src/test/java/io/meeds/twitter/gamification/rest/TwitterTweetRestTest.java @@ -0,0 +1,107 @@ +/* + * This file is part of the Meeds project (https://meeds.io/). + * + * Copyright (C) 2020 - 2024 Meeds Association contact@meeds.io + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package io.meeds.twitter.gamification.rest; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +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 io.meeds.twitter.gamification.model.Tweet; +import io.meeds.twitter.gamification.service.TwitterService; +import org.gatein.common.util.Tools; +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.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 io.meeds.spring.web.security.PortalAuthenticationManager; +import io.meeds.spring.web.security.WebSecurityConfiguration; +import jakarta.servlet.Filter; + +import java.util.List; + +@SpringBootTest(classes = { TwitterTweetRest.class, PortalAuthenticationManager.class, }) +@ContextConfiguration(classes = { WebSecurityConfiguration.class }) +@AutoConfigureWebMvc +@AutoConfigureMockMvc(addFilters = false) +@ExtendWith(MockitoExtension.class) +class TwitterTweetRestTest { + + private static final String REST_PATH = "/tweets"; // NOSONAR + + private static final String SIMPLE_USER = "simple"; + + private static final String TEST_PASSWORD = "testPassword"; + + @MockBean + private TwitterService twitterService; + + @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 getWatchedTweetsAnonymously() throws Exception { + ResultActions response = mockMvc.perform(get(REST_PATH)); + response.andExpect(status().isForbidden()); + } + + @Test + void getWatchedTweetsSimpleUser() throws Exception { + when(twitterService.getTweets(any())).thenReturn(new PageImpl<>(List.of(newWatchedTweet()))); + + ResultActions response = mockMvc.perform(get(REST_PATH).with(testSimpleUser())); + response.andExpect(status().isOk()); + } + + private RequestPostProcessor testSimpleUser() { + return user(SIMPLE_USER).password(TEST_PASSWORD).authorities(new SimpleGrantedAuthority("users")); + } + + private Tweet newWatchedTweet() { + return new Tweet(1, "tweetLink", Tools.toSet("user1", "user2", "user3"), Tools.toSet("user1", "user2")); + } + +} diff --git a/gamification-twitter-services/src/test/java/io/meeds/twitter/gamification/service/TwitterServiceTest.java b/gamification-twitter-services/src/test/java/io/meeds/twitter/gamification/service/TwitterServiceTest.java new file mode 100644 index 00000000..bccd1a83 --- /dev/null +++ b/gamification-twitter-services/src/test/java/io/meeds/twitter/gamification/service/TwitterServiceTest.java @@ -0,0 +1,173 @@ +/* + * This file is part of the Meeds project (https://meeds.io/). + * + * Copyright (C) 2020 - 2024 Meeds Association contact@meeds.io + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +package io.meeds.twitter.gamification.service; + +import static io.meeds.twitter.gamification.utils.Utils.CONNECTOR_NAME; +import static io.meeds.twitter.gamification.utils.Utils.MENTION_ACCOUNT_EVENT_NAME; +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.twitter.gamification.model.RemoteTwitterAccount; +import io.meeds.twitter.gamification.model.Tweet; +import io.meeds.twitter.gamification.model.TwitterAccount; +import io.meeds.twitter.gamification.model.TwitterTrigger; +import io.meeds.twitter.gamification.service.impl.TwitterServiceImpl; +import io.meeds.twitter.gamification.storage.TwitterAccountStorage; +import io.meeds.twitter.gamification.storage.TwitterTweetStorage; +import org.exoplatform.commons.exception.ObjectNotFoundException; +import org.exoplatform.web.security.codec.CodecInitializer; +import org.gatein.common.util.Tools; +import org.junit.jupiter.api.Assertions; +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; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +@SpringBootTest(classes = { TwitterServiceImpl.class }) +class TwitterServiceTest { + + private static final String ADMIN_USER = "root"; + + private static final String USER = "user"; + + private static final Pageable PAGEABLE = Pageable.ofSize(2); + + @MockBean + private TwitterConsumerService twitterConsumerService; + + @MockBean + private TwitterAccountStorage twitterAccountStorage; + + @MockBean + private TwitterTweetStorage twitterTweetStorage; + + @MockBean + private RuleService ruleService; + + @Autowired + private TwitterService twitterService; + + @Test + void testAddTwitterAccount() throws Exception { + + Throwable exception = assertThrows(IllegalAccessException.class, + () -> twitterService.addTwitterAccount("twitterUsername", USER)); + assertEquals("The user is not authorized to add a twitter watched account", exception.getMessage()); + + when(twitterAccountStorage.countTwitterAccounts()).thenReturn(2L); + + exception = assertThrows(IllegalStateException.class, () -> twitterService.addTwitterAccount("twitterUsername", ADMIN_USER)); + assertEquals("The maximum number of watched twitter accounts has been reached", exception.getMessage()); + + RemoteTwitterAccount remoteTwitterAccount = new RemoteTwitterAccount(1, "username", "name", "description", "avatarUrl"); + when(twitterConsumerService.retrieveTwitterAccount(anyString(), anyString())).thenReturn(remoteTwitterAccount); + List twitterTriggers = new ArrayList<>(); + TwitterTrigger twitterTrigger = new TwitterTrigger(MENTION_ACCOUNT_EVENT_NAME, "user1", 1254555L, "tweet", 11222121L); + TwitterTrigger twitterTrigger1 = new TwitterTrigger(MENTION_ACCOUNT_EVENT_NAME, "user2", 12548855L, "tweet", 11222121L); + twitterTriggers.add(twitterTrigger); + twitterTriggers.add(twitterTrigger1); + when(twitterConsumerService.getMentionEvents(any(), anyLong(), anyString())).thenReturn(twitterTriggers); + + // When + when(twitterAccountStorage.countTwitterAccounts()).thenReturn(0L); + + // Then + assertThrows(IllegalAccessException.class, () -> twitterService.getTwitterAccounts(USER, PAGEABLE)); + //Assertions.assertNotNull(twitterService.getTwitterAccounts(ADMIN_USER, PAGEABLE)); + assertThrows(IllegalAccessException.class, () -> twitterService.countTwitterAccounts(USER)); + verify(twitterAccountStorage, times(1)).countTwitterAccounts(); + twitterService.getTwitterAccountById(1L); + verify(twitterAccountStorage, times(1)).getTwitterAccountById(1L); + + assertThrows(IllegalAccessException.class, () -> twitterService.getTwitterAccountById(1L, USER)); + assertThrows(IllegalArgumentException.class, () -> twitterService.getTwitterAccountById(-10L)); + when(twitterAccountStorage.getTwitterAccountById(10L)).thenReturn(null); + assertThrows(ObjectNotFoundException.class, () -> twitterService.getTwitterAccountById(10L, ADMIN_USER)); + TwitterAccount twitterAccount = new TwitterAccount(); + when(twitterAccountStorage.getTwitterAccountById(20L)).thenReturn(twitterAccount); + Assertions.assertNotNull(twitterService.getTwitterAccountById(20L, ADMIN_USER)); + } + + @Test + void testDeleteTwitterAccount() throws Exception { + + Throwable exception = assertThrows(IllegalAccessException.class, () -> twitterService.deleteTwitterAccount(1L, USER)); + assertEquals("The user is not authorized to delete Twitter account", exception.getMessage()); + + when(twitterAccountStorage.getTwitterAccountById(1L)).thenReturn(null); + + exception = assertThrows(ObjectNotFoundException.class, () -> twitterService.deleteTwitterAccount(1L, ADMIN_USER)); + assertEquals("Twitter account with remote id : 1 wasn't found", exception.getMessage()); + + when(twitterAccountStorage.getTwitterAccountById(2L)).thenReturn(new TwitterAccount()); + + // When + twitterService.deleteTwitterAccount(2L, ADMIN_USER); + + // Then + verify(twitterAccountStorage, times(1)).deleteTwitterAccount(2L); + RuleFilter ruleFilter = new RuleFilter(true); + ruleFilter.setEventType(CONNECTOR_NAME); + ruleFilter.setIncludeDeleted(true); + verify(ruleService, times(1)).getRules(ruleFilter, 0, -1); + } + + @Test + void testSaveTwitterBearerToken() throws Exception { + + Throwable exception = assertThrows(IllegalAccessException.class, + () -> twitterService.saveTwitterBearerToken("bearerToken", USER)); + assertEquals("The user is not authorized to save or update Twitter Bearer Token", exception.getMessage()); + + // When + twitterService.saveTwitterBearerToken("bearerToken", ADMIN_USER); + + // Then + verify(twitterAccountStorage, times(1)).saveTwitterBearerToken("bearerToken"); + } + + @Test + void testAddTweetToWatch() { + Set tweetLikers = Tools.toSet("user1", "user2", "user3"); + Set tweetRetweeters = Tools.toSet("user1", "user2"); + + Tweet tweet = new Tweet(); + when(twitterTweetStorage.getTweetByLink("existTweetLink")).thenReturn(tweet); + assertNull(twitterService.addTweetToWatch("existTweetLink")); + + when(twitterTweetStorage.getTweetByLink("tweetLink")).thenReturn(null); + when(twitterConsumerService.retrieveTweetLikers("tweetLink", "bearerToken")).thenReturn(tweetLikers); + when(twitterConsumerService.retrieveTweetRetweeters("tweetLink", "bearerToken")).thenReturn(tweetRetweeters); + + // When + twitterService.addTweetToWatch("tweetLink"); + + // Then + verify(twitterTweetStorage, times(1)).addTweetToWatch(any()); + + } +} diff --git a/gamification-twitter-services/src/test/java/io/meeds/gamification/twitter/service/TwitterTriggerServiceTest.java b/gamification-twitter-services/src/test/java/io/meeds/twitter/gamification/service/TwitterTriggerServiceTest.java similarity index 57% rename from gamification-twitter-services/src/test/java/io/meeds/gamification/twitter/service/TwitterTriggerServiceTest.java rename to gamification-twitter-services/src/test/java/io/meeds/twitter/gamification/service/TwitterTriggerServiceTest.java index 2ac0ffef..67ab1a2c 100644 --- a/gamification-twitter-services/src/test/java/io/meeds/gamification/twitter/service/TwitterTriggerServiceTest.java +++ b/gamification-twitter-services/src/test/java/io/meeds/twitter/gamification/service/TwitterTriggerServiceTest.java @@ -16,37 +16,60 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ -package io.meeds.gamification.twitter.service; +package io.meeds.twitter.gamification.service; import io.meeds.gamification.model.EventDTO; -import io.meeds.gamification.twitter.BaseTwitterTest; -import io.meeds.gamification.twitter.model.TwitterTrigger; -import org.junit.Test; +import io.meeds.gamification.service.ConnectorService; +import io.meeds.gamification.service.EventService; +import io.meeds.gamification.service.TriggerService; +import io.meeds.twitter.gamification.model.TwitterTrigger; +import io.meeds.twitter.gamification.service.impl.TwitterTriggerServiceImpl; +import org.exoplatform.services.listener.ListenerService; +import org.exoplatform.social.core.identity.model.Identity; +import org.exoplatform.social.core.manager.IdentityManager; +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.scheduling.concurrent.ThreadPoolTaskExecutor; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import static io.meeds.gamification.twitter.service.impl.TwitterTriggerServiceImpl.GAMIFICATION_GENERIC_EVENT; -import static io.meeds.gamification.twitter.utils.Utils.*; +import static io.meeds.twitter.gamification.service.impl.TwitterTriggerServiceImpl.GAMIFICATION_GENERIC_EVENT; +import static io.meeds.twitter.gamification.utils.Utils.*; import static org.mockito.Mockito.*; -public class TwitterTriggerServiceTest extends BaseTwitterTest { +@SpringBootTest(classes = { TwitterTriggerServiceImpl.class, }) +class TwitterTriggerServiceTest { - private static final String ADMIN_USER = "root1"; + private static final String USER = "root"; - private static final String USER = "root"; + @MockBean + private ConnectorService connectorService; - @Override - public void setUp() throws Exception { - super.setUp(); - registerAdministratorUser(ADMIN_USER); - registerInternalUser(USER); - } + @MockBean + private EventService eventService; + + @MockBean + private TriggerService triggerService; + + @MockBean + private IdentityManager identityManager; + + @MockBean + private ListenerService listenerService; + + @MockBean + private ThreadPoolTaskExecutor threadPoolTaskExecutor; + + @Autowired + private TwitterTriggerService twitterTriggerService; @Test - public void testHandleTriggerAsync() throws Exception { + void testHandleTriggerAsync() throws Exception { TwitterTrigger twitterTrigger = new TwitterTrigger(); twitterTrigger.setType("tweet"); @@ -54,7 +77,9 @@ public void testHandleTriggerAsync() throws Exception { twitterTrigger.setTwitterUsername("liker"); twitterTrigger.setTweetId(11112222L); when(triggerService.isTriggerEnabledForAccount(twitterTrigger.getTrigger(), twitterTrigger.getAccountId())).thenReturn(true); - when(connectorService.getAssociatedUsername(CONNECTOR_NAME, twitterTrigger.getTwitterUsername())).thenReturn("root1"); + when(connectorService.getAssociatedUsername(CONNECTOR_NAME, twitterTrigger.getTwitterUsername())).thenReturn(USER); + Identity identity = mock(Identity.class); + when(identityManager.getOrCreateUserIdentity(USER)).thenReturn(identity); List events = new ArrayList<>(); EventDTO eventDTO = new EventDTO(1, "likeTweet", "twitter", "likeTweet", null, null); EventDTO eventDTO1 = new EventDTO(2, "likeTweet", "twitter", "likeTweet", null, null); @@ -66,8 +91,8 @@ public void testHandleTriggerAsync() throws Exception { + twitterTrigger.getTweetId() + "}"; Map gam = new HashMap<>(); - gam.put("senderId", "root1"); - gam.put("receiverId", "root1"); + gam.put("senderId", USER); + gam.put("receiverId", USER); gam.put("objectId", "11112222"); gam.put("objectType", "tweet"); gam.put("ruleTitle", "likeTweet"); diff --git a/gamification-twitter-services/src/test/java/io/meeds/twitter/gamification/storage/TwitterAccountStorageTest.java b/gamification-twitter-services/src/test/java/io/meeds/twitter/gamification/storage/TwitterAccountStorageTest.java new file mode 100644 index 00000000..33e81493 --- /dev/null +++ b/gamification-twitter-services/src/test/java/io/meeds/twitter/gamification/storage/TwitterAccountStorageTest.java @@ -0,0 +1,194 @@ +/* + * This file is part of the Meeds project (https://meeds.io/). + * + * Copyright (C) 2020 - 2024 Meeds Association contact@meeds.io + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +package io.meeds.twitter.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.junit.jupiter.api.Assertions.assertNull; +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.twitter.gamification.dao.TwitterAccountDAO; +import io.meeds.twitter.gamification.entity.TwitterAccountEntity; +import io.meeds.twitter.gamification.model.TwitterAccount; +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.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; + +@SpringBootTest(classes = { TwitterAccountStorage.class, }) +@ExtendWith(MockitoExtension.class) +class TwitterAccountStorageTest { + + private static final Long ID = 2L; + + private static final Long REMOTE_ID = 1232L; + + private static final Pageable PAGEABLE = Pageable.ofSize(2); + + @Autowired + private TwitterAccountStorage twitterAccountStorage; + + @MockBean + private TwitterAccountDAO twitterAccountDAO; + + @MockBean + private SettingService settingService; + + @MockBean + private CodecInitializer codecInitializer; + + @BeforeEach + void setup() { + when(twitterAccountDAO.save(any())).thenAnswer(invocation -> { + TwitterAccountEntity entity = invocation.getArgument(0); + if (entity.getId() == null) { + entity.setId(ID); + } + when(twitterAccountDAO.findById(ID)).thenReturn(Optional.of(entity)); + when(twitterAccountDAO.findTwitterAccountEntityByRemoteId(REMOTE_ID)).thenReturn(entity); + when(twitterAccountDAO.findAll(PAGEABLE)).thenReturn(new PageImpl<>(List.of(entity))); + when(twitterAccountDAO.count()).thenReturn(1L); + return entity; + }); + doAnswer(invocation -> { + TwitterAccountEntity entity = invocation.getArgument(0); + when(twitterAccountDAO.findById(entity.getId())).thenReturn(Optional.empty()); + return null; + }).when(twitterAccountDAO).delete(any()); + } + + @Test + void testAddTwitterAccount() throws Exception { + // Given + TwitterAccount twitterAccount = createTwitterAccountInstance(); + + // When + TwitterAccount createdTwitterAccount = twitterAccountStorage.addTwitterAccount(twitterAccount); + + // Then + assertNotNull(createdTwitterAccount); + assertEquals(twitterAccount.getName(), createdTwitterAccount.getName()); + assertEquals(twitterAccount.getIdentifier(), createdTwitterAccount.getIdentifier()); + assertEquals(twitterAccount.getRemoteId(), createdTwitterAccount.getRemoteId()); + + assertThrows(ObjectAlreadyExistsException.class, () -> twitterAccountStorage.addTwitterAccount(twitterAccount)); + } + + @Test + void testGetTwitterAccounts() throws Exception { + // Given + TwitterAccount twitterAccount = createTwitterAccountInstance(); + + // When + TwitterAccount createdTwitterAccount = twitterAccountStorage.addTwitterAccount(twitterAccount); + + // Then + assertNotNull(createdTwitterAccount); + assertEquals(new PageImpl<>(List.of(createdTwitterAccount)), twitterAccountStorage.getTwitterAccounts(PAGEABLE)); + assertEquals(1L, twitterAccountStorage.countTwitterAccounts()); + } + + @Test + void testUpdateAccountLastMentionTweetId() throws Exception { + // Given + TwitterAccount twitterAccount = createTwitterAccountInstance(); + + // When + TwitterAccount account = twitterAccountStorage.updateAccountLastMentionTweetId(10L, 122121L); + + // Then + assertNull(account); + + // When + TwitterAccount createdTwitterAccount = twitterAccountStorage.addTwitterAccount(twitterAccount); + account = twitterAccountStorage.updateAccountLastMentionTweetId(createdTwitterAccount.getId(), 122121L); + + assertNotNull(account); + assertEquals(createdTwitterAccount.getIdentifier(), account.getIdentifier()); + assertEquals(createdTwitterAccount.getRemoteId(), account.getRemoteId()); + assertEquals(122121, account.getLastMentionTweetId()); + } + + @Test + void testGetTwitterAccountById() throws Exception { + // Given + TwitterAccount createdTwitterAccount = twitterAccountStorage.addTwitterAccount(createTwitterAccountInstance()); + + // When + TwitterAccount twitterAccount = twitterAccountStorage.getTwitterAccountById(createdTwitterAccount.getId()); + + // Then + assertNotNull(twitterAccount); + assertEquals(createdTwitterAccount.getName(), twitterAccount.getName()); + assertEquals(createdTwitterAccount.getIdentifier(), twitterAccount.getIdentifier()); + assertEquals(createdTwitterAccount.getRemoteId(), twitterAccount.getRemoteId()); + } + + @Test + void testDeleteTwitterAccount() throws Exception { + // Given + TwitterAccount createdTwitterAccount = twitterAccountStorage.addTwitterAccount(createTwitterAccountInstance()); + + // When + TwitterAccount twitterAccount = twitterAccountStorage.deleteTwitterAccount(createdTwitterAccount.getId()); + + // Then + assertNotNull(twitterAccount); + } + + @Test + void testGetTwitterAccountByRemoteId() throws Exception { + // Given + TwitterAccount createdTwitterAccount = twitterAccountStorage.addTwitterAccount(createTwitterAccountInstance()); + + // When + TwitterAccount twitterAccount = twitterAccountStorage.getTwitterAccountByRemoteId(createdTwitterAccount.getRemoteId()); + + // Then + assertNotNull(twitterAccount); + assertEquals(createdTwitterAccount.getName(), twitterAccount.getName()); + assertEquals(createdTwitterAccount.getIdentifier(), twitterAccount.getIdentifier()); + assertEquals(createdTwitterAccount.getRemoteId(), twitterAccount.getRemoteId()); + } + + protected TwitterAccount createTwitterAccountInstance() { + TwitterAccount twitterAccount = new TwitterAccount(); + twitterAccount.setIdentifier("twitterIdentifier"); + twitterAccount.setName("twitterName"); + twitterAccount.setRemoteId(REMOTE_ID); + return twitterAccount; + } +} diff --git a/gamification-twitter-services/src/test/java/io/meeds/twitter/gamification/storage/TwitterTweetStorageTest.java b/gamification-twitter-services/src/test/java/io/meeds/twitter/gamification/storage/TwitterTweetStorageTest.java new file mode 100644 index 00000000..2d150cec --- /dev/null +++ b/gamification-twitter-services/src/test/java/io/meeds/twitter/gamification/storage/TwitterTweetStorageTest.java @@ -0,0 +1,180 @@ +/* + * This file is part of the Meeds project (https://meeds.io/). + * + * Copyright (C) 2020 - 2024 Meeds Association contact@meeds.io + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +package io.meeds.twitter.gamification.storage; + +import static org.junit.jupiter.api.Assertions.*; +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 java.util.Set; + +import io.meeds.twitter.gamification.dao.TwitterTweetDAO; +import io.meeds.twitter.gamification.entity.TwitterTweetEntity; +import io.meeds.twitter.gamification.model.Tweet; +import org.gatein.common.util.Tools; +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.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; + +@SpringBootTest(classes = { TwitterTweetStorage.class, }) +@ExtendWith(MockitoExtension.class) +class TwitterTweetStorageTest { + + private static final Long ID = 2L; + + private static final String TWEET_LINK = "tweetLink"; + + private static final Pageable PAGEABLE = Pageable.ofSize(2); + + @Autowired + private TwitterTweetStorage twitterTweetStorage; + + @MockBean + private TwitterTweetDAO twitterTweetDAO; + + @BeforeEach + void setup() { + when(twitterTweetDAO.save(any())).thenAnswer(invocation -> { + TwitterTweetEntity entity = invocation.getArgument(0); + if (entity.getId() == null) { + entity.setId(ID); + } + when(twitterTweetDAO.findById(ID)).thenReturn(Optional.of(entity)); + when(twitterTweetDAO.findTwitterTweetEntityByTweetLink(TWEET_LINK)).thenReturn(entity); + when(twitterTweetDAO.findAll(PAGEABLE)).thenReturn(new PageImpl<>(List.of(entity))); + when(twitterTweetDAO.count()).thenReturn(1L); + return entity; + }); + doAnswer(invocation -> { + TwitterTweetEntity entity = invocation.getArgument(0); + when(twitterTweetDAO.findById(entity.getId())).thenReturn(Optional.empty()); + return null; + }).when(twitterTweetDAO).delete(any()); + } + + @Test + void testAddTweetToWatch() { + // Given + Tweet tweet = createTwitterTweetInstance(); + + // When + Tweet createdTweet = twitterTweetStorage.addTweetToWatch(tweet); + + // Then + assertNotNull(createdTweet); + assertEquals(tweet.getTweetLink(), createdTweet.getTweetLink()); + + createdTweet = twitterTweetStorage.addTweetToWatch(tweet); + assertNull(createdTweet); + + } + + @Test + void testGetTweetById() { + // Given + Tweet createdTweet = twitterTweetStorage.addTweetToWatch(createTwitterTweetInstance()); + + // When + Tweet tweet = twitterTweetStorage.getTweetById(createdTweet.getTweetId()); + + // Then + assertNotNull(tweet); + assertEquals(createdTweet.getTweetLink(), tweet.getTweetLink()); + } + + @Test + void testGetTweets() { + // Given + Tweet tweet = createTwitterTweetInstance(); + + // When + Tweet createdTweet = twitterTweetStorage.addTweetToWatch(tweet); + + // Then + assertNotNull(createdTweet); + assertEquals(new PageImpl<>(List.of(createdTweet)), twitterTweetStorage.getTweets(PAGEABLE)); + assertEquals(1L, twitterTweetStorage.countTweets()); + } + + @Test + void testTweetReactions() { + // Given + Tweet TwitterTweet = createTwitterTweetInstance(); + + // When + Set tweetLikers = Tools.toSet("user1", "user2", "user3"); + Set tweetRetweeters = Tools.toSet("user1", "user2"); + Tweet tweet = twitterTweetStorage.updateTweetReactions(10L, tweetLikers, tweetRetweeters); + + // Then + assertNull(tweet); + + // When + Tweet createdTweet = twitterTweetStorage.addTweetToWatch(TwitterTweet); + tweet = twitterTweetStorage.updateTweetReactions(createdTweet.getTweetId(), tweetLikers, tweetRetweeters); + + // Then + assertNotNull(tweet); + assertEquals(createdTweet.getTweetLink(), tweet.getTweetLink()); + assertEquals(tweetLikers, tweet.getLikers()); + assertEquals(tweetRetweeters, tweet.getRetweeters()); + } + + @Test + void testDeleteWebHook() { + // Given + Tweet createdTweet = twitterTweetStorage.addTweetToWatch(createTwitterTweetInstance()); + + // When + Tweet tweet = twitterTweetStorage.deleteTweet(createdTweet.getTweetId()); + + // Then + assertNotNull(tweet); + } + + @Test + void testGetTwitterAccountByRemoteId() { + // Given + Tweet createdTweet = twitterTweetStorage.addTweetToWatch(createTwitterTweetInstance()); + + // When + Tweet tweet = twitterTweetStorage.getTweetByLink(createdTweet.getTweetLink()); + + // Then + assertNotNull(tweet); + assertEquals(createdTweet.getTweetLink(), tweet.getTweetLink()); + } + + protected Tweet createTwitterTweetInstance() { + Tweet tweet = new Tweet(); + tweet.setTweetLink(TWEET_LINK); + return tweet; + } +} diff --git a/gamification-twitter-services/src/test/resources/conf/twitter-test-configuration.xml b/gamification-twitter-services/src/test/resources/conf/twitter-test-configuration.xml index c76f1a48..1ea8a775 100644 --- a/gamification-twitter-services/src/test/resources/conf/twitter-test-configuration.xml +++ b/gamification-twitter-services/src/test/resources/conf/twitter-test-configuration.xml @@ -23,49 +23,6 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 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"> - - org.exoplatform.social.core.manager.IdentityManager - io.meeds.gamification.twitter.mock.IdentityManagerMock - - - - io.meeds.gamification.service.RuleService - io.meeds.gamification.twitter.mock.RuleServiceMock - - - - io.meeds.gamification.service.ConnectorService - io.meeds.gamification.twitter.mock.ConnectorServiceMock - - - - io.meeds.gamification.service.ConnectorSettingService - io.meeds.gamification.twitter.mock.ConnectorSettingServiceMock - - - - io.meeds.gamification.service.EventService - io.meeds.gamification.twitter.mock.EventServiceMock - - - - io.meeds.gamification.service.TriggerService - io.meeds.gamification.twitter.mock.TriggerServiceMock - - - - org.exoplatform.social.core.manager.IdentityManager - io.meeds.gamification.twitter.mock.IdentityManagerMock - - - - org.exoplatform.web.security.codec.CodecInitializer - - - gatein.conf.dir - jar:/conf - - - + org.exoplatform.web.security.codec.CodecInitializer diff --git a/gamification-twitter-webapp/pom.xml b/gamification-twitter-webapp/pom.xml index b6ac24f3..5141a58c 100644 --- a/gamification-twitter-webapp/pom.xml +++ b/gamification-twitter-webapp/pom.xml @@ -29,6 +29,11 @@ war Meeds:: Gamification Twitter - Webapp + + ${project.groupId} + gamification-twitter-service + provided + io.meeds.platform-ui platform-ui-skin diff --git a/gamification-twitter-webapp/src/main/java/io/meeds/twitter/gamification/GamificationTwitterApplication.java b/gamification-twitter-webapp/src/main/java/io/meeds/twitter/gamification/GamificationTwitterApplication.java new file mode 100644 index 00000000..126ec5d9 --- /dev/null +++ b/gamification-twitter-webapp/src/main/java/io/meeds/twitter/gamification/GamificationTwitterApplication.java @@ -0,0 +1,44 @@ +/* + * This file is part of the Meeds project (https://meeds.io/). + * + * Copyright (C) 2020 - 2024 Meeds Association contact@meeds.io + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package io.meeds.twitter.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 = { + GamificationTwitterApplication.MODULE_NAME, + AvailableIntegration.KERNEL_MODULE, + AvailableIntegration.JPA_MODULE, + AvailableIntegration.LIQUIBASE_MODULE, + AvailableIntegration.WEB_MODULE, + }) +@EnableCaching +@EnableJpaRepositories(basePackages = GamificationTwitterApplication.MODULE_NAME) +@PropertySource("classpath:application.properties") +@PropertySource("classpath:application-common.properties") +@PropertySource("classpath:twitter.properties") +public class GamificationTwitterApplication extends PortalApplicationContextInitializer { + + public static final String MODULE_NAME = "io.meeds.twitter.gamification"; +} diff --git a/gamification-twitter-webapp/src/main/resources/twitter.properties b/gamification-twitter-webapp/src/main/resources/twitter.properties new file mode 100644 index 00000000..69248ae1 --- /dev/null +++ b/gamification-twitter-webapp/src/main/resources/twitter.properties @@ -0,0 +1,20 @@ +# +# This file is part of the Meeds project (https://meeds.io/). +# +# Copyright (C) 2020 - 2024 Meeds Association contact@meeds.io +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 3 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +spring.liquibase.change-log=classpath:db/changelog/twitter-connector.db.changelog-1.0.0.xml diff --git a/gamification-twitter-webapp/src/main/webapp/WEB-INF/web.xml b/gamification-twitter-webapp/src/main/webapp/WEB-INF/web.xml index c84c9a60..1119524c 100644 --- a/gamification-twitter-webapp/src/main/webapp/WEB-INF/web.xml +++ b/gamification-twitter-webapp/src/main/webapp/WEB-INF/web.xml @@ -39,7 +39,10 @@ ResourceRequestFilter - /* + *.css + *.js + *.html + /images/* \ No newline at end of file diff --git a/gamification-twitter-webapp/src/main/webapp/vue-app/connectorEventExtensions/components/TwitterEventDisplay.vue b/gamification-twitter-webapp/src/main/webapp/vue-app/connectorEventExtensions/components/TwitterEventDisplay.vue index 93a966d4..45693989 100644 --- a/gamification-twitter-webapp/src/main/webapp/vue-app/connectorEventExtensions/components/TwitterEventDisplay.vue +++ b/gamification-twitter-webapp/src/main/webapp/vue-app/connectorEventExtensions/components/TwitterEventDisplay.vue @@ -69,7 +69,7 @@ export default { }, computed: { tweetLink() { - return this.properties?.tweetLink; + return this.convertXtoTwitter(this.properties?.tweetLink); }, accountId() { return this.properties?.accountId; @@ -119,11 +119,17 @@ export default { }, getTwitterAccount() { this.loading = true; - return this.$twitterConnectorService.getWatchedAccounts() - .then(data => { - this.account = data.entities.find(a => a.remoteId === this.accountId); - }) .finally(() => this.loading = false); + return this.$twitterConnectorService.getWatchedAccounts({ + page: 0, + size: 5, + }).then(data => { + this.account = data?._embedded?.twitterAccountRestEntityList.find(a => a.remoteId === this.accountId); + }) .finally(() => this.loading = false); + }, + convertXtoTwitter(url) { + const xComRegex = /^https:\/\/x\.com\//; + return url.replace(xComRegex, 'https://twitter.com/'); } } }; diff --git a/gamification-twitter-webapp/src/main/webapp/vue-app/connectorEventExtensions/components/TwitterEventForm.vue b/gamification-twitter-webapp/src/main/webapp/vue-app/connectorEventExtensions/components/TwitterEventForm.vue index 61b0454e..9c0ed39b 100644 --- a/gamification-twitter-webapp/src/main/webapp/vue-app/connectorEventExtensions/components/TwitterEventForm.vue +++ b/gamification-twitter-webapp/src/main/webapp/vue-app/connectorEventExtensions/components/TwitterEventForm.vue @@ -120,25 +120,27 @@ export default { methods: { retrieveAccounts() { this.loadingAccounts = true; - return this.$twitterConnectorService.getWatchedAccounts() - .then(data => { - this.accounts = data.entities; - }).finally(() => { - if (this.properties) { - this.selected = this.accounts.find(a => a.remoteId === this.properties.accountId); - this.value = this.accounts.indexOf(this.selected); - } else if (this.accounts.length === 1) { - this.selected = this.accounts[0]; - const eventProperties = { - accountId: this.selected?.remoteId.toString() - }; - document.dispatchEvent(new CustomEvent('event-form-filled', {detail: eventProperties})); - this.value = this.accounts.indexOf(this.selected); - } else { - document.dispatchEvent(new CustomEvent('event-form-unfilled')); - } - this.loadingAccounts = false; - }); + return this.$twitterConnectorService.getWatchedAccounts({ + page: 0, + size: 5, + }).then(data => { + this.accounts = data?._embedded?.twitterAccountRestEntityList; + }).finally(() => { + if (this.properties) { + this.selected = this.accounts.find(a => a.remoteId === this.properties.accountId); + this.value = this.accounts.indexOf(this.selected); + } else if (this.accounts.length === 1) { + this.selected = this.accounts[0]; + const eventProperties = { + accountId: this.selected?.remoteId.toString() + }; + document.dispatchEvent(new CustomEvent('event-form-filled', {detail: eventProperties})); + this.value = this.accounts.indexOf(this.selected); + } else { + document.dispatchEvent(new CustomEvent('event-form-unfilled')); + } + this.loadingAccounts = false; + }); }, selectAccount(value) { this.selected = this.accounts[value]; @@ -170,10 +172,10 @@ export default { }; this.$twitterConnectorService.getWatchedTweets() .then(data => { - const existingTweetIndex = data.entities.findIndex(t => t.tweetLink === this.tweetLink); - if (existingTweetIndex < 0 && data?.size >= 5) { + const existingTweetIndex = data?._embedded?.tweetList?.findIndex(t => t.tweetLink === this.tweetLink); + if (existingTweetIndex < 0 && data?.page?.totalElements >= 5) { this.$root.$emit('alert-message', this.$t('gamification.event.detail.tweetLimitReached.error', { - 0: data?.size, + 0: data?.page?.totalElements, }), 'info'); } }).finally(() => document.dispatchEvent(new CustomEvent('event-form-filled', {detail: eventProperties}))); @@ -186,7 +188,7 @@ export default { }, this.endTypingKeywordTimeout); }, checkTweetLink(tweetLink) { - const tweetUrlRegex = /^https:\/\/twitter\.com\/[^/]+\/status\/\d+$/; + const tweetUrlRegex = /^https:\/\/(twitter\.com|x\.com)\/[^/]+\/status\/\d+$/; this.isValidLink = tweetUrlRegex.test(tweetLink); return this.isValidLink; }, diff --git a/gamification-twitter-webapp/src/main/webapp/vue-app/twitterAdminConnectorExtension/components/TwitterAdminConnectorItem.vue b/gamification-twitter-webapp/src/main/webapp/vue-app/twitterAdminConnectorExtension/components/TwitterAdminConnectorItem.vue index 77857098..e36ba7ed 100644 --- a/gamification-twitter-webapp/src/main/webapp/vue-app/twitterAdminConnectorExtension/components/TwitterAdminConnectorItem.vue +++ b/gamification-twitter-webapp/src/main/webapp/vue-app/twitterAdminConnectorExtension/components/TwitterAdminConnectorItem.vue @@ -33,13 +33,6 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. {{ $t('gamification.connectors.settings.BackToDetail') }} - - - fas fa-redo-alt -
@@ -108,7 +101,7 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- + export default { - props: { - forceUpdate: { - type: Boolean, - default: false - }, - }, data() { return { showLoadMoreButton: false, @@ -152,13 +146,6 @@ export default { return this.maxAccountsReached ? this.$t('twitterConnector.admin.label.maxAccountsReached') : this.$t('twitterConnector.admin.label.addAccount'); } }, - watch: { - forceUpdate() { - if (this.forceUpdate) { - this.refreshWatchedAccount(); - } - } - }, created() { this.$root.$on('twitter-accounts-updated', this.refreshWatchedAccount); this.$root.$on('twitter-bearer-token-updated', () => { @@ -188,15 +175,17 @@ export default { }, refreshWatchedAccount() { this.loading = true; - return this.$twitterConnectorService.getWatchedAccounts(this.offset, this.limit, this.forceUpdate) - .then(data => { - this.watchedAccounts = data.entities; - this.watchedAccountsCount = data.size || 0; - return this.$nextTick() - .then(() => { - this.$emit('updated', this.watchedAccounts); - }); - }).finally(() => this.loading = false); + return this.$twitterConnectorService.getWatchedAccounts({ + page: 0, + size: 5, + }).then(data => { + this.watchedAccounts = data?._embedded?.twitterAccountRestEntityList; + this.watchedAccountsCount = data?.page?.totalElements || 0; + return this.$nextTick() + .then(() => { + this.$emit('updated', this.watchedAccounts); + }); + }).finally(() => this.loading = false); }, addWatchedAccount() { this.$root.$emit('twitter-account-form-drawer'); diff --git a/gamification-twitter-webapp/src/main/webapp/vue-app/twitterAdminConnectorExtension/js/TwitterConnectorService.js b/gamification-twitter-webapp/src/main/webapp/vue-app/twitterAdminConnectorExtension/js/TwitterConnectorService.js index 051d8b42..dddcb8d9 100644 --- a/gamification-twitter-webapp/src/main/webapp/vue-app/twitterAdminConnectorExtension/js/TwitterConnectorService.js +++ b/gamification-twitter-webapp/src/main/webapp/vue-app/twitterAdminConnectorExtension/js/TwitterConnectorService.js @@ -18,7 +18,7 @@ */ export function checkTwitterTokenStatus() { - return fetch(`${eXo.env.portal.context}/${eXo.env.portal.rest}/gamification/connectors/twitter/bearerToken`, { + return fetch('/gamification-twitter/rest/settings', { method: 'GET', credentials: 'include', }).then((resp) => { @@ -33,7 +33,7 @@ export function checkTwitterTokenStatus() { export function saveBearerToken(bearerToken) { const formData = new FormData(); formData.append('bearerToken', bearerToken); - return fetch(`${eXo.env.portal.context}/${eXo.env.portal.rest}/gamification/connectors/twitter/bearerToken`, { + return fetch('/gamification-twitter/rest/settings', { method: 'POST', credentials: 'include', headers: { @@ -48,7 +48,7 @@ export function saveBearerToken(bearerToken) { } export function deleteTwitterBearerToken() { - return fetch(`${eXo.env.portal.context}/${eXo.env.portal.rest}/gamification/connectors/twitter/bearerToken`, { + return fetch('/gamification-twitter/rest/settings', { method: 'DELETE', credentials: 'include', }).then(resp => { @@ -61,7 +61,7 @@ export function deleteTwitterBearerToken() { export function addAccountToWatch(twitterUsername) { const formData = new FormData(); formData.append('twitterUsername', twitterUsername); - return fetch(`${eXo.env.portal.context}/${eXo.env.portal.rest}/gamification/connectors/twitter/account`, { + return fetch('/gamification-twitter/rest/accounts', { method: 'POST', credentials: 'include', headers: { @@ -82,7 +82,7 @@ export function addAccountToWatch(twitterUsername) { } export function deleteAccountToWatch(accountId) { - return fetch(`${eXo.env.portal.context}/${eXo.env.portal.rest}/gamification/connectors/twitter/account/${accountId}`, { + return fetch(`/gamification-twitter/rest/accounts/${accountId}`, { method: 'DELETE', credentials: 'include', }).then(resp => { @@ -92,8 +92,20 @@ export function deleteAccountToWatch(accountId) { }); } -export function getWatchedAccounts(offset, limit, forceUpdate) { - return fetch(`${eXo.env.portal.context}/${eXo.env.portal.rest}/gamification/connectors/twitter/account?offset=${offset || 0}&limit=${limit|| 10}&returnSize=true&forceUpdate=${forceUpdate|| false}`, { +export function getWatchedAccounts(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-twitter/rest/accounts?${params}`, { method: 'GET', credentials: 'include', }).then((resp) => { @@ -106,7 +118,7 @@ export function getWatchedAccounts(offset, limit, forceUpdate) { } export function getWatchedAccountById(accountId) { - return fetch(`${eXo.env.portal.context}/${eXo.env.portal.rest}/gamification/connectors/twitter/account/${accountId}`, { + return fetch(`/gamification-twitter/rest/accounts/${accountId}`, { method: 'GET', credentials: 'include', }).then((resp) => { @@ -118,8 +130,20 @@ export function getWatchedAccountById(accountId) { }); } -export function getWatchedTweets(offset, limit) { - return fetch(`${eXo.env.portal.context}/${eXo.env.portal.rest}/gamification/connectors/twitter/tweet?offset=${offset || 0}&limit=${limit|| 10}&returnSize=true`, { +export function getWatchedTweets(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-twitter/rest/tweets?${params}`, { method: 'GET', credentials: 'include', }).then((resp) => { diff --git a/gamification-twitter-webapp/src/main/webapp/vue-app/twitterUserConnectorExtension/js/twitterConnector.js b/gamification-twitter-webapp/src/main/webapp/vue-app/twitterUserConnectorExtension/js/twitterConnector.js index a7e840dc..a24e0358 100644 --- a/gamification-twitter-webapp/src/main/webapp/vue-app/twitterUserConnectorExtension/js/twitterConnector.js +++ b/gamification-twitter-webapp/src/main/webapp/vue-app/twitterUserConnectorExtension/js/twitterConnector.js @@ -28,7 +28,7 @@ export default { PROFILE_BASER_URL: 'https://twitter.com', openOauthPopup() { // Construct the Twitter OAuth URL with the oauth_token - const authUrl =`${window.location.origin}/portal/twitterOauth`; + const authUrl =`${window.location.origin}/gamification-twitter/rest/oauth`; const width = 600; const height = 600; const left = window.innerWidth / 2 - width / 2;