/* * Copyright (C) 2008-2024, 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.TwitterApi20; import com.github.scribejava.core.builder.ServiceBuilder; 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 com.juick.model.Message; import com.juick.util.MessageUtils; import jakarta.annotation.PostConstruct; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.MediaType; import org.springframework.stereotype.Service; import javax.inject.Inject; import java.io.IOException; import java.util.concurrent.ExecutionException; @Service public class TwitterService { private static final Logger logger = LoggerFactory.getLogger("Twitter"); @Value("${twitter_client_id:12345678}") private String clientId; @Value("${twitter_client_secret:secret}") private String clientSecret; private static final String redirectUri = "https://juick.com/_twitter"; @Inject private UserService userService; private OAuth20Service twitterAuthService; @Inject private ObjectMapper jsonMapper; @PostConstruct public void init() { ServiceBuilder twitterBuilder = new ServiceBuilder(clientId); setTwitterAuthService(twitterBuilder.apiSecret(clientSecret) .defaultScope("tweet.read tweet.write users.read offline.access") .callback(redirectUri) .build(TwitterApi20.instance())); } public void twitterPost(final Message jmsg) { userService.getTwitterToken(jmsg.getUser().getUid()).ifPresent(t -> { String status = MessageUtils.getMessageHashTags(jmsg) + StringUtils.defaultString(jmsg.getText()); if (status.length() > 253) { status = StringUtils.abbreviate(status, "…", 252); } status += " http://juick.com/" + jmsg.getMid(); try { var token = twitterAuthService.refreshAccessToken(t.secret()); userService.refreshTwitterToken(jmsg.getUser(), token.getAccessToken(), token.getRefreshToken()); OAuthRequest postRequest = new OAuthRequest(Verb.POST, "https://api.twitter.com/2/tweets"); var body = jsonMapper.createObjectNode(); body.put("text", status); postRequest.addHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE); postRequest.setPayload(jsonMapper.writeValueAsString(body)); twitterAuthService.signRequest(token, postRequest); try (Response twitterResponse = twitterAuthService.execute(postRequest)) { if (twitterResponse.isSuccessful()) { logger.info(twitterResponse.getBody()); } else { logger.warn("Twitter error {}: {}", twitterResponse.getCode(), twitterResponse.getBody()); } } catch (Exception e) { logger.error("Twitter exception {}", jmsg.getUser().getName(), e); } } catch (IOException | InterruptedException | ExecutionException e) { logger.error("Twitter exception {}", jmsg.getUser().getName(), e); } }); } public OAuth20Service getTwitterAuthService() { return twitterAuthService; } public void setTwitterAuthService(OAuth20Service twitterAuthService) { this.twitterAuthService = twitterAuthService; } }