diff options
author | George Rusu <56009869+grusu6928@users.noreply.github.com> | 2020-10-25 15:21:38 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-10-25 18:21:38 -0400 |
commit | 9da19cdcb6c7596d60afde6d0d559f06a24a0627 (patch) | |
tree | 8f11b6e0a5fcdc2eb983d498fa7b016d4daf44ba /src/services/SocialLinkingService.ts | |
parent | 44a25bfabd356f5eee5ec4f580452407a7e40246 (diff) |
[TMA-237] Added modal for user registration and redirect (#61)
* move async-storage
* removed lock files
* added lock files to gitignore
* added the wrong file to gitignore
* added modal for user registration and redirect
* api call to get list of linked socials for each user to display appropriate icon
* fixed indentation and linting
* refactored modal and browser sign-in
* now dynamically adding linked and unlinked taggs, added a bunch of TODOs for tomorrow
* added svg icons
* done? finished taggs bar UI and all the navigations including modal
* fixed some bugs and added more TODOs
* fixed some bugs and refactored posts fetching logic
* fixed taggs bar bug
* done, it will update everything correctly
* added comments
* added tiktok
Co-authored-by: hsalhab <husam_salhab@brown.edu>
Co-authored-by: george <grus6928@gmail.com>
Co-authored-by: Ivan Chen <ivan@thetaggid.com>
Diffstat (limited to 'src/services/SocialLinkingService.ts')
-rw-r--r-- | src/services/SocialLinkingService.ts | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/src/services/SocialLinkingService.ts b/src/services/SocialLinkingService.ts new file mode 100644 index 00000000..8d67d90e --- /dev/null +++ b/src/services/SocialLinkingService.ts @@ -0,0 +1,184 @@ +import AsyncStorage from '@react-native-community/async-storage'; +import {Alert} from 'react-native'; +import InAppBrowser from 'react-native-inappbrowser-reborn'; +import { + LINKED_SOCIALS_ENDPOINT, + LINK_FB_ENDPOINT, + LINK_FB_OAUTH, + LINK_IG_ENDPOINT, + LINK_IG_OAUTH, + LINK_SNAPCHAT_ENDPOINT, + LINK_TIKTOK_ENDPOINT, + LINK_TWITTER_ENDPOINT, + LINK_TWITTER_OAUTH, +} from '../constants'; + +// A list of endpoint strings for all the integrated socials +export const integratedEndpoints: {[social: string]: [string, string]} = { + Instagram: [LINK_IG_OAUTH, LINK_IG_ENDPOINT], + Facebook: [LINK_FB_OAUTH, LINK_FB_ENDPOINT], + Twitter: [LINK_TWITTER_OAUTH, LINK_TWITTER_ENDPOINT], +}; + +export const nonIntegratedEndponits: {[social: string]: string} = { + Snapchat: LINK_SNAPCHAT_ENDPOINT, + TikTok: LINK_TIKTOK_ENDPOINT, +}; + +export const registerNonIntegratedSocialLink: ( + socialType: string, + username: string, +) => Promise<boolean> = async (socialType, username) => { + if (!(socialType in nonIntegratedEndponits)) { + return false; + } + try { + const user_token = await AsyncStorage.getItem('token'); + const response = await fetch(nonIntegratedEndponits[socialType], { + method: 'POST', + headers: { + Authorization: `Token ${user_token}`, + }, + body: JSON.stringify({ + username: username, + }), + }); + return response.status === 200; + } catch (error) { + console.log(error); + return false; + } +}; + +// We have already received the short-lived token (callback_data), sending it +// to backend to exchange for and store the long-lived token. +export const registerIntegratedSocialLink: ( + callback_data: string, + user_token: string, + socialType: string, +) => Promise<boolean> = async (callback_data, user_token, socialType) => { + if (!(socialType in integratedEndpoints)) { + return false; + } + const response = await fetch(integratedEndpoints[socialType][1], { + method: 'POST', + headers: { + Authorization: `Token ${user_token}`, + }, + body: JSON.stringify({ + callback_url: callback_data, + }), + }); + if (!(response.status === 201)) { + console.log(await response.json()); + } + return response.status === 201; +}; + +// Twitter is a special case since they use OAuth1, we will need to request +// for a request_token before we can begin browser signin. +export const getTwitterRequestToken: ( + user_token: string, +) => Promise<string> = async (user_token) => { + const response = await fetch(integratedEndpoints.Twitter[0], { + method: 'GET', + headers: { + Authorization: `Token ${user_token}`, + }, + }); + return response.url; +}; + +// one stop shop for handling all browser sign-in social linkings +export const handlePressForAuthBrowser: ( + socialType: string, +) => Promise<boolean> = async (socialType: string) => { + try { + if (!(socialType in integratedEndpoints)) { + Alert.alert('Coming soon!'); + return false; + } + + if (!(await InAppBrowser.isAvailable())) { + // Okay... to open an external browser and have it link back to + // the app is a bit tricky, we will need to have navigation routes + // setup for this screen and have it hooked up. + // See https://github.com/proyecto26/react-native-inappbrowser#authentication-flow-using-deep-linking + // Though this isn't the end of the world, from the documentation, + // the in-app browser should be supported from iOS 11, which + // is about 98.5% of all iOS devices in the world. + // See https://support.apple.com/en-gb/HT209574 + Alert.alert( + 'Sorry! Your device was unable to open a browser to let you sign-in! 😔', + ); + return false; + } + + let url = integratedEndpoints[socialType][0]; + const user_token = await AsyncStorage.getItem('token'); + + if (!user_token) { + throw 'Unable to get user token'; + } + + // We will need to do an extra step for twitter sign-in + if (socialType === 'Twitter') { + url = await getTwitterRequestToken(user_token); + } + + return await InAppBrowser.openAuth(url, 'taggid://callback', { + ephemeralWebSession: true, + }) + .then(async (response) => { + if (response.type === 'success' && response.url) { + const success = await registerIntegratedSocialLink( + response.url, + user_token, + socialType, + ); + if (!success) { + throw 'Unable to register with backend'; + } + Alert.alert(`Successfully linked ${socialType} 🎉`); + return true; + } else { + throw 'Error from Oauth API'; + } + }) + .catch((error) => { + console.log(error); + Alert.alert( + `Something went wrong, we can't link with ${socialType} 😔`, + ); + return false; + }); + } catch (error) { + console.log(error); + Alert.alert(`Something went wrong, we can't link with ${socialType} 😔`); + } + return false; +}; + +// get all the linked socials from backend as an array +export const getLinkedSocials: (user_id: string) => Promise<string[]> = async ( + user_id: string, +) => { + try { + const user_token = await AsyncStorage.getItem('token'); + const response = await fetch(`${LINKED_SOCIALS_ENDPOINT}${user_id}/`, { + method: 'GET', + headers: { + Authorization: 'Token ' + user_token, + }, + }); + const body = await response.json(); + if (response.status !== 200) { + console.log(body); + throw 'Unable to fetch from server'; + } + return body.linked_socials || []; + } catch (error) { + console.log(error); + return []; + } +}; |