I am using react native with native code. Using the 'react-native-activity-feed' library, I am trying to get Stream Feeds up and running on my app.
I have set up my stream account with an api key, app Id and app secret. Using firebase functions, I am creating a token server side for the user upon account creation and then saving that to the database.
const client = stream.connect(
functions.config().stream.key_id,
functions.config().stream.secret,
);
const userToken = client.createUserToken(user.uid);
admin.database().ref('users/' + user.uid ).set({
token: userToken
})
Client side, I retrieve that token for the current user and then I pass it (along with app Id and app key) into the object. I am expecting to get an empty feed with no errors but instead I get 'data undefined' error from Stream.
What else do I need to create client side or server side in order to start using the StreamApp Object?
import {StreamApp} from 'react-native-activity-feed
render() {
const { currentUser } = this.state
const {streamToken} = this.state
let apiKey = Config.STREAM_API_KEY;
let appId = Config.STREAM_APP_ID;
userId = firebase.auth().currentUser.uid;
let token;
tokenRef = firebase.database().ref(`users/${userId}`);
tokenRef.on('value', (snapshot) => {
token = snapshot.val().token;
})
return (
<StreamApp
apiKey={apiKey}
appId={appId}
token={token}
>
</StreamApp>
)
}
}
Error:
TypeError: undefined is not an object (evaluating 'client.currentUser.data')
This error is located at:
in StreamApp(...)
...
It ended up being a problem with the render function being called before the server had returned the stream token.
To fix, I gave the page time to load the stream token from the server:
render() {
if(this.state.loading) {
return (<View style={[styles.container, styles.horizontal]}><ActivityIndicator size="large" color="#0000ff" /></View>);
}
return (
<StreamApp
apiKey={this.state.apiKey}
appId={this.state.apiId}
token={this.state.streamToken}
>
</StreamApp>
)
}
}
Related
On this page I generate the access token and with it I can publish the image on my Instagram:
For publish:
function InstagramPost() {
const access_token = 'GENERATE ACESS TOKEN';
const instagram_business_account = 'YYYYYYYYYYYYYYYYYY';
const image = 'https://upload.wikimedia.org/wikipedia/en/9/95/Test_image.jpg';
const text = 'Hello World';
var formData = {
'image_url': image,
'caption': text,
'access_token': access_token
};
var options = {
'method' : 'post',
'payload' : formData
};
const container = 'https://graph.facebook.com/v14.0/' + instagram_business_account + '/media';
const response = UrlFetchApp.fetch(container, options);
const creation = response.getContentText();
var data = JSON.parse(creation);
var creationId = data.id
var formDataPublish = {
'creation_id': creationId,
'access_token': access_token
};
var optionsPublish = {
'method' : 'post',
'payload' : formDataPublish
};
const sendinstagram = 'https://graph.facebook.com/v14.0/' + instagram_business_account + '/media_publish';
UrlFetchApp.fetch(sendinstagram, optionsPublish);
}
Now I want to take this access token and generate a long-lived one with it!
It asks for Instagram App Secret, but that path indicated (App Dashboard > Products > Instagram > Basic Display > Instagram App Secret) doesn't exist in App Dashboard!
I tried using the App secret as a parameter:
"https://graph.instagram.com/access_token
?grant_type=ig_exchange_token
&client_secret={App Secret Key}
&access_token={short-lived-access-token}"
But this error occurs:
Sorry, this content isn't available right now
The Facebook API is 100% accessible, so that's not the problem.
In Javascript/NodeJS I couldn't get it working at all (also on PostMan), I was using the request library.
Changed my code to:
const respLong = await axios.get(`https://graph.instagram.com/access_token?grant_type=ig_exchange_token&client_secret=${CLIENT_SECRET}&access_token=${accessTokenShort.toString()}`);
And magically this works. I can't tell you why what seems to be the exact same request in Postman and the request library doesn't work.
See pic of the url to get app secret (add your app ID) is: https://developers.facebook.com/apps/YOUR_APP_ID(number)/instagram-basic-display/basic-display/
There is a difference in approach between Basic Display and Instagram Graph API for Business Account.
So the way to convert a short-lived token to a long-lived token for Instagram Business Account is:
"https://graph.facebook.com/{graph-api-version}/oauth/access_token?
grant_type=fb_exchange_token&
client_id={app-id}&
client_secret={app-secret}&
fb_exchange_token={your-short-lived-access-token}"
Note that Instagram App Secret is not used, instead, use App Id and App Secret.
In my firebase cloud function, I can get the email of each user that makes a call on the client side using:
context.auth.token.email
Is there a way to obtain the user's display name? I tried context.auth.token.name but it still return an undefined property.
The context.auth.token is an object of type DecodedToken which does not contain user display name. You'll have to use Admin SDK and get user by UID/email.
export const functionName = functions.https.onCall(async (data, ctx) => {
const { uid } = ctx.auth?.token
const user = await getAuth().getUser(uid)
console.log(user.displayName)
// ...
})
After logging in using the MsalAuthenticationTemplate InteractionType.Redirect, how do I get the JWT returned after successful authentication? It does not seem to be included in the msal instance.
import { MsalProvider, MsalAuthenticationTemplate, useMsal, useAccount } from "#azure/msal-react";
const { instance } = useMsal();
You should call acquireTokenSilent each time you need an access token. You can read more in our getting started doc and also review the msal-react-samples
Another way of getting the idToken(JWT) after successful login is to hook into the addEventCallback and check for EventType.LOGIN_SUCCESS.
const callbackId = instance.addEventCallback(message => {
if (message.eventType === EventType.LOGIN_SUCCESS) {
const { payload } = message;
// Get idToken(JWT) from the payload.
console.log(payload.idToken);
}
})
https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/events.md
Following these links https://firebase.google.com/docs/auth/web/manage-users#update_a_users_profile and https://firebase.google.com/docs/auth/web/manage-users#get_a_users_provider-specific_profile_information
I was able to authenticate user and log in with their twitter account. However, I want to get the screenName of an user. How will I do that?
I've checked some network request and I see the screenName attribute. I've checked onAuthStateChanged and it returns user attribute but without the screenName.
I needed to do this from Node, however, Google/Firebase Auth does not store a user's Twitter handle (at least it's not accessible through firebase-admin).
However, they do make the Twitter uid accessible as the question points out. With that, you can subsequently call Twitter's API to get a user by their uid and the result will return the handle a.k.a username:
import { TwitterApi } from 'twitter-api-v2';
import { auth } from 'firebase-admin';
const BEARER = process.env['TWITTER_BEARER_TOKEN'] as string;
const logTwitterHandleFromUid = async (googleUid: string): Promise<void> => {
// get Google Auth information associated with the target user
const { providerData } = await auth().getUser(googleUid);
// pull out the Twitter information
const twitter = providerData.find((p) => p.providerId.includes('twitter'));
if (!twitter) {
console.error('User does not have a linked Twitter account')
process.exit(1)
}
const details = await new TwitterApi(BEARER).v2.user(twitter.uid);
// pull out the Twitter handle
const twitter_handle = details.data.username;
return console.log(twitter_handle);
};
See Get a user's profile documentation. The .displayName property should have it.
var user = firebase.auth().currentUser;
var name, email, photoUrl, uid, emailVerified;
if (user != null) {
name = user.displayName;
email = user.email;
photoUrl = user.photoURL;
emailVerified = user.emailVerified;
uid = user.uid; // The user's ID, unique to the Firebase project. Do NOT use
// this value to authenticate with your backend server, if
// you have one. Use User.getToken() instead.
}
We are facing issues while managing multiple user interaction at the same time in Dialogflow.
How we can manage user unique session as we are using custom event which will process our 3rd party API and then return a response to the specific user.
To manage User unique session We try Dailogflow Set/Get Context method, to set Context with Unique Id (using this id will store API response to the Redis server) from the first intent when a user makes a first request then will traverse that Unique Id through the custom event.
Will get that Unique Id from Context and grab data from Redis server which we stored in first intent.
We used agent.set.context() to set unique id but this method is not working with "dialogflow-fulfillment" version ^0.5.0, To get this work we have updated the version with "^0.6.1". But this will provide other error like "UnhandledPromiseRejectionWarning: Error: No responses defined for platform: null".
Required Output: Context set with a unique id and will get a proper response.
Current Output: UnhandledPromiseRejectionWarning: Error: No responses defined for platform: null
async function searchFromAPI(agent){
axios.post('https://testApi.com', searchString.data, {headers: headers})
.then((resp) => {
response.data = resp;
redisClient.set(sessionId, JSON.stringify(response));
}
}).catch(error => {
response.error = true;
response.message = error.response.statusText;
redisClient.set(sessionId, JSON.stringify(response));
});
await customsleep(2000);
const sessionId = uuid.v4();
const contextData = {'name':'userSession','lifespan': 5,'parameters':{'sessionId':sessionId}};
agent.context.set(contextData);
console.log(contextData);
agent.add('We are processing your request, Could you please wait?');
agent.add(new Suggestion("Yes"));
agent.add(new Suggestion("No"));
}
// wait for 4.5sec and call custom event
async function followOne(agent){
await customsleep(4500);
agent.setFollowupEvent('followUpTwo');
}
// wait for 4.7sec then red API response from redis server and return
async function followUpTwo(agent){
await customsleep(4000);
sess = session;
//get context
const response = agent.context.get('userSession');
// get the sessionId, Get the data from redis server
agent.add(response);
}
async function PleaseWait(agent){
await customsleep(3500);
agent.setFollowupEvent('followUpOne');
}
I found the only workaround to reassign a new context object via context.set(ctx). Then it worked.
//update context to show full menu
let context = agent.context.get('user_data');
if (!context) throw "User_data context ius nod defined in PreferrenceAdd"
let context2 = new Object();
context2 = {'name': 'user_data', 'lifespan': 40,
'parameters': context.parameters};
console.log("ctx: = " + JSON.stringify(context2));
context2.parameters.new = false;
context2.parameters.refresh = true;
agent.context.set(context2);
Check this resource on how to set a new Dialogflow outgoing context
dialogflow webhook-client.
I hope this helps you?