728x90

이 부분해서 Slack 에서 대화생성하기 이후에 던져주는 부분을 활용하려면 아래와 같이 Slack 에서 Oauth Permission 을 허용시켜주어야 한다.

 

conversations.create

 
 

Initiates a public or private channel-based conversation

https://api.slack.com/methods/conversations.create

 

conversations.create API method

Initiates a public or private channel-based conversation

api.slack.com

 

Bot token 에 대해서 제대로 설정해주고, 해당 부분에 대한 코드를 작성하면 된다.

(물론 샘플 코드도 있더라)

 

import com.slack.api.bolt.App;
import com.slack.api.bolt.AppConfig;
import com.slack.api.bolt.jetty.SlackAppServer;
import com.slack.api.methods.SlackApiException;

import java.io.IOException;

public class ConversationsCreate {

    public static void main(String[] args) throws Exception {
        var config = new AppConfig();
        config.setSingleTeamBotToken(System.getenv("SLACK_BOT_TOKEN"));
        config.setSigningSecret(System.getenv("SLACK_SIGNING_SECRET"));
        var app = new App(config); // `new App()` does the same

        // Listen for a message shortcut with the callback_id "sample_message_action"
        // Message shortcuts require the commands scope
        app.messageShortcut("sample_message_action", (req, ctx) -> {
            var logger = ctx.logger;
            try {
                var payload = req.getPayload();
                // Call the conversations.create method using the built-in WebClient
                var result = ctx.client().conversationsCreate(r -> r
                    // The token you used to initialize your app
                    .token(System.getenv("SLACK_BOT_TOKEN"))
                    // The name of the conversation
                    .name("pretend-channel")
                );
                // Print result
                logger.info("result: {}", result);
            } catch (IOException | SlackApiException e) {
                logger.error("error: {}", e.getMessage(), e);
            }
            // Acknowledge incoming command event
            return ctx.ack();
        });

        var server = new SlackAppServer(app);
        server.start();
    }

}

 

하지만 여기서 단순하게 이렇게 설정하게 만들어주면 망하는 결과가 ... (난 Back-end API 에서 중계단을 만들거니까 이렇게 만들면 안되고 Service 부터 DTO 등까지 죄다 세세하게 분배해주었다.)

728x90
2023-08-11 04:14:46.858  3948-4126  NaverOAuth...Connection com.atlas.moyamo                     I  response status code:200
2023-08-11 04:14:46.927  3948-3948  System.out              com.atlas.moyamo                     I  accessToken is AAAAN5Z6D5+Ji+VL6Ef577RT9H6S9d1X0fHf6QJx6PpcduBu48urbqxg3x0vz6aaO4tEoc8O4fnbD6lsEDs/wnjcOzI=
2023-08-11 04:14:46.927  3948-3948  System.out              com.atlas.moyamo                     I  refreshToken is TlejyY5Q9cbuZTooIxFrn41qvEoLipBKT1g8JiiUUis01C9pngEkWsgoMisjoiiYSeisMlJisE32UE2cQeL18cQ2jKtxip53JmN9Pq4zHuJl8pKxQWf0GOz6UVyPca7Q8xq3yIar
2023-08-11 04:14:46.927  3948-3948  System.out              com.atlas.moyamo                     I  expiresAt is AAAAN5Z6D5+Ji+VL6Ef577RT9H6S9d1X0fHf6QJx6PpcduBu48urbqxg3x0vz6aaO4tEoc8O4fnbD6lsEDs/wnjcOzI=
2023-08-11 04:14:46.927  3948-3948  System.out              com.atlas.moyamo                     I  tokenType is bearer

Logcat 에서 주어지는 accessToken 은 굉장히 긴 반면에 spring 단에서 인식되는 accessToken 은 굉장히 짧은 부분을 보이고 있다.

 

아마 세션간의 문제라면 이 부분에서 spring 이 가져다 쓰는 부분에 문제가 생기거나 뭔가 착오가 생기는 모양인데, 추적 포인트를 바꿔야 할 것 같다

 

2023-08-11 04:14:47.412  3948-3948  System.out              com.atlas.moyamo                     I  main setup userId is 1799455,  user accessToken is 87e96dfbfe8d4d7d98d186720b6be80e, provider is naver
2023-08-11 04:14:47.440  3948-4954  System.out              com.atlas.moyamo                     I  okhttp ResponseInterceptor pre synchronized - http://v2/users/me
2023-08-11 04:14:47.440  3948-4954  System.out              com.atlas.moyamo                     I  ResponseInterceptor isExpiredTime 2023-09-09 19:14:47 - 1 - http://v2/users/me
2023-08-11 04:14:47.443  3948-4954  System.out              com.atlas.moyamo                     I  call bearer token Bearer 87e96dfbfe8d4d7d98d186720b6be80e

여기서 인식되는건 87 기반의 id 인데 위에는 왜 저렇게 되어있는걸까

 


추가적인 증상 발견

naver, OAuth 기반의 Id 에서 로그인이 해제되어 있을 때 shop에서 프로필 조회 end-point 를 불러오면 이후 로그인이 되는 현상이 발견되었다.

 

{{HOST}}/v2/shops/users/me
728x90

Shop 상에서 Login 이 지속적으로 풀리는 현상이 발생

해당 부분에서 내 Android 기기로 접근했을 때의 Bearer 를 땃고, 이걸 기반으로 accessToken 값으로 활용해서 End-Point에 던져보기로 했다

 

맨 처음에는 유효하지 않은 토큰이라고 resultMsg 가 return 되길래 나자신 뭘잘못했는가 생각하다가, end-point 주소가 잘못됬었다는 것을 기억하고 때려박으니 던져서 납치해오는 방법에 대해서 문제가 생긴것으로 생각된다.

 

Android Side 에서 request  -> Spring 에서 hook -> Shop 의 API 단에 때려박고 -> Shop 내부의 DB 에 접근하는 것으로 보이는데, 신기하게도 Spring 서버를 재시작 시키면 4~6시간은 정상적으로 작동되는 것으로 보아 뭔가가 있다고 판단함

728x90
[Rest][2023-08-02 18:39:02][ERROR][PostingController.java][lambda$doFindPostingActivity$5(92)] : readPosting
org.springframework.aop.AopInvocationException: Null return value from advice does not match primitive return type for: public abstract boolean net.infobank.moyamo.repository.PostingRepository.isPostingOwner(long,java.lang.Long)
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:229)
        at com.sun.proxy.$Proxy237.isPostingOwner(Unknown Source)
        at net.infobank.moyamo.service.PostingService.findPostingActivity(PostingService.java:1831)
        at net.infobank.moyamo.service.PostingService$$FastClassBySpringCGLIB$$72b2a0db.invoke(<generated>)
        at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
        at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:779)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
        at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750)
        at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123)
        at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:388)
        at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
        at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750)
        at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:692)
        at net.infobank.moyamo.service.PostingService$$EnhancerBySpringCGLIB$$886f7a7f.findPostingActivity(<generated>)
        at net.infobank.moyamo.controller.PostingController.lambda$doFindPostingActivity$4(PostingController.java:91)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:750)

 

Handling

The error message you are encountering (AopInvocationException: Null return value from advice does not match primitive return type) suggests that a method with a primitive return type (boolean in this case) is returning null. Since primitives cannot be null, this results in an exception.

Here's a brief rundown of what might be happening:

  1. Method Signature: The method isPostingOwner(long, java.lang.Long) in the PostingRepository interface is declared with a return type of boolean.
  2. Proxy Invocation: During the invocation, some AOP advice (such as a transactional aspect) may be being applied to this method.
  3. Null Return: For some reason, this method is returning null (possibly from a repository implementation or advice method), which is not compatible with the primitive boolean return type.

Here's how you can potentially resolve this:

1. Check the Repository Implementation

Ensure that the method's implementation in the corresponding repository class is not returning null. It should return a boolean value (true or false).

2. Check the AOP Advice

If there is any AOP (Aspect-Oriented Programming) advice being applied to the method, make sure that it's not altering the return value to null. Examine any aspects that might be affecting the method, including transactional aspects.

3. Change the Return Type (if applicable)

If it is acceptable for the method to indicate an absence of a value, consider changing the return type of the method from the primitive boolean to the wrapper class Boolean. This will allow the method to return null. Note that this will require handling the null value in the calling code.

Example:

javaCopy code
public abstract Boolean isPostingOwner(long id, java.lang.Long ownerId);

4. Exception Handling

If the null return is expected in some situations (like when some data is not found), consider adding proper exception handling in the method or its caller to deal with these scenarios gracefully.

By focusing on these areas, you should be able to track down the cause of the exception and resolve it. Make sure to thoroughly test your changes to ensure they don't introduce other issues.

 

 

 

JPOL 상에서 일치하지 않는 return type을 확인해서 boolean 에서 Boolean 으로 변경

@Query("select p.owner.id from Posting p where p.id = :postingId and p.owner.id = :userId")
Boolean isPostingOwner(@Param("postingId") long postingId, @Param("userId") Long userId);

 

추가적으로 null Pointer Exception handling

if(isWatch == null) {
    isWatch = !commentRepository.findDistinctRecipientByMentionUserIds(id, Collections.singletonList(user.getId())).isEmpty();
    Boolean isOwner = postingRepository.isPostingOwner(id, user.getId());
    isWatch = isWatch || (isOwner != null && isOwner);
}

 

을 했지만 문제발생으로 인한 JPQL 변경으로 처리

@Query("select case when count(p) > 0 then true else false end from Posting p where p.id = :postingId and p.owner.id = :userId")
Boolean isPostingOwner(@Param("postingId") long postingId, @Param("userId") Long userId);

+ Recent posts