From 10dcb7324fac83c0190ff4a842360a035449f278 Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Tue, 20 Jun 2023 07:10:16 +0300 Subject: VK: read premium status using Callback API --- src/main/java/com/juick/service/UserService.java | 5 +- .../java/com/juick/service/UserServiceImpl.java | 13 ++- src/main/java/com/juick/service/VKService.java | 94 ++++++++++++++++++++++ 3 files changed, 104 insertions(+), 8 deletions(-) create mode 100644 src/main/java/com/juick/service/VKService.java (limited to 'src/main/java/com/juick/service') diff --git a/src/main/java/com/juick/service/UserService.java b/src/main/java/com/juick/service/UserService.java index fe5ce23f..4acc5b6a 100644 --- a/src/main/java/com/juick/service/UserService.java +++ b/src/main/java/com/juick/service/UserService.java @@ -25,12 +25,14 @@ import com.juick.model.ExternalToken; import com.juick.util.UsernameTakenException; import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; import org.apache.commons.lang3.tuple.Pair; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; import java.util.Collection; import java.util.List; +import java.util.Map; import java.util.Optional; /** @@ -151,7 +153,8 @@ public interface UserService { String getTelegramName(int uid); - List> getVkTokens(List uids); + @Nullable + Pair getVkTokens(int uid); void deleteVKUser(Integer uid); diff --git a/src/main/java/com/juick/service/UserServiceImpl.java b/src/main/java/com/juick/service/UserServiceImpl.java index c586886b..d19af067 100644 --- a/src/main/java/com/juick/service/UserServiceImpl.java +++ b/src/main/java/com/juick/service/UserServiceImpl.java @@ -741,14 +741,13 @@ public class UserServiceImpl extends BaseJdbcService implements UserService { @Transactional(readOnly = true) @Override - public List> getVkTokens(List uids) { - return getNamedParameterJdbcTemplate().query( - """ - SELECT vk_id, access_token FROM vk WHERE crosspost = 1 AND access_token <> ''""" - + (uids.isEmpty() ? "" : " AND user_id IN (:uids)"), + public Pair getVkTokens(int uid) { + var result = getNamedParameterJdbcTemplate().query( + "SELECT vk_id, access_token FROM vk WHERE user_id=:uid AND crosspost = 1 AND access_token <> ''", new MapSqlParameterSource() - .addValue("uids", uids), + .addValue("uid", uid), (rs, num) -> Pair.of(rs.getString(1), rs.getString(2))); + return result.isEmpty() ? null : result.get(0); } @Transactional @@ -885,7 +884,7 @@ public class UserServiceImpl extends BaseJdbcService implements UserService { @Transactional(readOnly = true) @Override public boolean canDeleteTelegramUser(User user) { - return getEmails(user).size() > 0 || getFbCrossPostStatus(user.getUid()).isConnected() || !getVkTokens(List.of(user.getUid())).isEmpty(); + return getEmails(user).size() > 0 || getFbCrossPostStatus(user.getUid()).isConnected() || getVkTokens(user.getUid()) != null; } private static class TokenMapper implements RowMapper { diff --git a/src/main/java/com/juick/service/VKService.java b/src/main/java/com/juick/service/VKService.java new file mode 100644 index 00000000..14d7e3e9 --- /dev/null +++ b/src/main/java/com/juick/service/VKService.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2008-2023, Juick + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.juick.service; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.scribejava.apis.VkontakteApi; +import com.github.scribejava.core.builder.ServiceBuilder; +import com.github.scribejava.core.model.OAuth2AccessToken; +import com.github.scribejava.core.model.OAuthRequest; +import com.github.scribejava.core.model.Response; +import com.github.scribejava.core.model.Verb; +import com.github.scribejava.core.oauth.OAuth20Service; +import jakarta.annotation.PostConstruct; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import javax.inject.Inject; + +@Service +public class VKService { + private static final Logger logger = LoggerFactory.getLogger("VK"); + @Value("${vk_appid:appid}") + private String VK_APPID; + @Value("${vk_secret:secret}") + private String VK_SECRET; + private static final String VK_REDIRECT = "https://juick.com/_vklogin"; + @Inject + private ObjectMapper jsonMapper; + @Inject + private UserService userService; + private OAuth20Service vkAuthService; + + @PostConstruct + public void init() { + ServiceBuilder vkBuilder = new ServiceBuilder(VK_APPID); + setVkAuthService(vkBuilder.apiSecret(VK_SECRET) + .defaultScope("friends,wall,offline,groups") + .callback(VK_REDIRECT) + .build(VkontakteApi.instance())); + } + + public void updatePremiumStatus(Integer userId) { + var vkUser = userService.getVkTokens(userId); + if (vkUser != null) { + OAuth2AccessToken token = new OAuth2AccessToken(vkUser.getRight()); + OAuthRequest donRequest = new OAuthRequest(Verb.GET, + "https://api.vk.com/method/donut.isDon?owner_id=-67669480&v=5.131"); + getVkAuthService().signRequest(token, donRequest); + try (Response vkResponse = getVkAuthService().execute(donRequest)) { + if (vkResponse.isSuccessful()) { + logger.info(vkResponse.getBody()); + var response = jsonMapper.readTree(vkResponse.getBody()); + if (response.has("response")) { + var isDon = response.get("response").intValue() > 0; + logger.info("{} is Don: {}", vkUser.getLeft(), isDon); + userService.setPremium(userId, isDon); + } else { + // token is expired or does not have "groups" permissions + userService.updateVkToken(userId, ""); + } + } + } catch (Exception e) { + logger.error("Don request error", e); + } + } else { + logger.warn("User is not connected to VK: {}", userId); + } + } + + public OAuth20Service getVkAuthService() { + return vkAuthService; + } + + public void setVkAuthService(OAuth20Service vkAuthService) { + this.vkAuthService = vkAuthService; + } +} -- cgit v1.2.3