React를 사용하여 Fullcalendar에서 Google 캘린더 이벤트 표시

27992 단어 reactjavascript
편의를 위해 TheGoodPsy의 심리학자는 둘 사이의 충돌을 방지하기 위해 Google 캘린더에 연결하여 플랫폼 로컬 약속과 함께 이벤트를 볼 수 있습니다. 한 캘린더에 환자와의 약속을 추가하고 다른 캘린더에 약속을 제안하는 것은 매우 쉽습니다.

Google Identity Services은 Google에서 시행하는 새로운 인증 흐름이 되어 새로 생성된 자격 증명이 대체to Google Sign-In Platform를 허용하지 않고 기본적으로 이를 사용하도록 합니다.

이전 방법을 사용하여 React 애플리케이션을 Google 캘린더에 연결하는 방법에 대한 몇 가지 자습서가 있지만 구현해야 하는 특정 흐름에 대한 자습서를 거의 찾을 수 없었기 때문에 직접 작성하기로 결정했습니다.

기사를 간략하게 유지하기 위해 여기에서는 자격 증명을 생성하고 OAuth 화면을 구성하는 방법을 설명하지 않을 것이며 이를 수행하는 방법에 대한 많은 문서가 있습니다.

사용자 흐름에 대한 몇 가지 세부 정보:
  • 백엔드에서 인증 토큰 새로 고침을 직접 처리해야 하기 때문에 사용자 코드 모델을 사용하고 있습니다.
  • OAuth 권한 화면에 팝업 모드를 사용하고 있으므로 사용자가 리디렉션되지 않고 앱에 남아 있습니다.

  • Google에 로그인


    @react-oauth/google' 라이브러리를 사용하여 인증 흐름, ux_mode 및 인증 토큰을 얻기 위한 범위를 구성한 다음 Google에 API 호출을 위한 인증 토큰을 요청하는 데 사용할 인증 토큰을 얻습니다.

    모든 것은 간단한 버튼으로 시작됩니다.

    <GoogleButton
        id='google-calendar-connection'
        label='Connect Google Calendar'
        onClick={googleLogin}
    />
    


    googleLogin 함수는 OAuth 화면을 열고 승인 토큰을 전달하는 백엔드를 호출하여 액세스 토큰을 얻습니다.

    const getGoogleAccessToken = async (authorizationCode) => {
        const response = await axios.post(
            `/api/google/accesstoken`, 
            { authorizationCode }
        );
    
        if (response.data.access_token) {
            localStorage.setItem("google_access_token", JSON.stringify(response.data.access_token));
        }
    
        if (response.data.expiry_date) {
            localStorage.setItem("google_access_token_expiry_date", JSON.stringify(response.data.expiry_date));
        }
    
        return response.data;  
    }
    
    
    const fetchGoogleAccessToken = async (tokenResponse) => {
        const accessToken = await getGoogleAccessToken(tokenResponse.code);
        if (localStorage.getItem("google_access_token")) {
            setGoogleCalendarSync(true);
        }
        return accessToken;
    }
    
    
    const googleLogin = useGoogleLogin({
        onSuccess: fetchGoogleAccessToken,
        onError: error => console.log(error),
        flow: 'auth-code',
        ux_mode: 'popup',
        scope: GOOGLE_CALENDAR_SCOPES
    });
    

    getGoogleAccessToken() 함수 호출을 처리하는 API 엔드포인트:

    const getAccessToken = async (req, res) => {
        const { authorizationCode } = req.body;
        const user = req.user;
    
        // Get access and refresh tokens (if access_type is offline)
        let { tokens } = await oauth2Client.getToken(authorizationCode);
        oauth2Client.setCredentials(tokens);
    
        let userGoogleAuthentication;
        userGoogleAuthentication = await user.getGoogleAuthentication();
    
        //If the user has already a google authentication, update the refresh token,
        //otherwise create a google authentication object and associate it to the user.
        if (userGoogleAuthentication) {
            await userGoogleAuthentication.update({ refresh_token: tokens.refresh_token });
        }
        else {
            userGoogleAuthentication =
                await GoogleAuthentication.create({
                    refresh_token: tokens.refresh_token,
                    userId: user.id
                });
        }
    
        return res.status(200).json({ ...tokens });
    }
    


    이제 브라우저의 localStorage에 액세스 및 갱신 토큰이 각각 google_access_token 및 google_access_token_expiry_date로 있습니다. 남은 것은 eventsFullCalendar 속성에 대한 이벤트를 가져오는 기능의 일부로 Google 캘린더 이벤트를 가져오는 것입니다. 이 비트에는 현재 토큰이 만료된 경우 백엔드에서 토큰을 새로 고치는 기능이 포함되어 있습니다.

    다음은 프런트엔드 부분입니다.

    const refreshGoogleAccessToken = async () => {
        const response = await axios.post(
            `/api/google/refreshtoken`,
            {}
        );
    
        if (response.data.access_token) {
            localStorage.setItem("google_access_token", JSON.stringify(response.data.access_token));
        }
    
        if (response.data.expiry_date) {
            localStorage.setItem("google_access_token_expiry_date", JSON.stringify(response.data.expiry_date));
        }
    
        return response.data;
    }
    
    //API call to the Google Calendar endpoint.
    const googleEventsFetch = async ({ token, from, until }) => {
        const response = await fetch(
            `${GOOGLE_CALENDAR_EVENTS_API_URL}/?key=${GOOGLE_CALENDAR_API_KEY}&orderBy=startTime&singleEvents=true&timeMin=${from.toISOString()}&timeMax=${until.toISOString()}`,
            {
                headers: {
                    Authorization: `Bearer ${token}`,
                },
            }
        );
        return response;
    }
    
    //Small wrapper around functionality
    const getGoogleEvents = async ({ token, from, until }) => {
        if (from && until) {
            const response = await googleEventsFetch({ token, from, until });
    
            if (response.status === OK) {
                const data = await response.json();
                return {
                    status: response.status,
                    items: data.items
                }
            }
            else {
                return {
                    status: response.status,
                    items: []
                }
            }
        }
        else return [];
    }
    
    
    // Load events from Google Calendar between 2 dates.
    const loadGoogleCalendarEvents = useCallback(async (from, until) => {
        const googleAccessToken = localStorage.getItem("google_access_token");
        const googleAccessTokenExpirationDate = localStorage.getItem("google_access_token_expiry_date");
    
        //If the's an expiration date in the offline storage.
        if (googleAccessTokenExpirationDate && googleAccessToken) {
            const googleAccesTokenExpirationDateParsed = parseInt(googleAccessTokenExpirationDate);
            const gAccesTokenExpDateMoment = moment(googleAccesTokenExpirationDateParsed);
            const currentDateMoment = moment();
    
            //If the token has expired.
            if (currentDateMoment.isAfter(gAccesTokenExpDateMoment)) {
                localStorage.removeItem("google_access_token_expiry_date");
                localStorage.removeItem("google_access_token");
    
                //Get a new access token & expiry_date with the refresh token.
                const { access_token: newAccessToken} = await refreshGoogleAccessToken();
    
                if (newAccessToken) {
                    const newResponse = await getGoogleEvents({
                        token: newAccessToken,
                        from,
                        until
                    });
    
                    if (newResponse.status === OK) {
                        setGoogleCalendarSync(true);
                        return newResponse.items;
                    }
                    else {
                        setGoogleCalendarSync(false);
                        return [];
                    }           
                }
            }
            // If the token hasn't expired yet.
            else {
                const response = await getGoogleEvents({
                    token: googleAccessToken,
                    from,
                    until
                });
    
                if (response.status === OK) {
                    return response.items;
                }
                else { //Token expired
                    setGoogleCalendarSync(false);
                }
            }
        }
        else {
            return [];
        }
    }, []);
    
    
    const fetchEvents = async (fetchInfo, successCallback) => {    
        const googleEvents = await loadGoogleCalendarEvents(fetchInfo.start, fetchInfo.end);
        //...Merging googleEvents with local events..
    }
    
    <FullCalendar
        ...attributes...
        events={fetchEvents} // alternatively, use the `events` setting to fetch from a feed
    />
    


    마지막으로 API 끝점은 새로 고침 토큰을 요청합니다. 새로 고침 토큰은 각 사용자별로 DB에 저장됩니다.

    const refreshToken = async (req, res) => {
        const user = req.user;
        const userGoogleAuthentication = await user.getGoogleAuthentication();
    
        if (userGoogleAuthentication) {
            const tokenResponse = await oauth2Client.refreshToken(userGoogleAuthentication.refresh_token);
            return res.status(200).json({ ...tokenResponse.tokens });
        }
        else {
            return res.sendStatus(500);
        }
    }
    


    그게 다야, 다른 사람에게 도움이 되길 바랍니다.
    재미있게 보내세요!

    퍼머링크: https://www.estebansastre.com/google-calendar-events-fullcalendar-react/

    좋은 웹페이지 즐겨찾기