How do you get a resource's region in Pulumi - pulumi

I have a Cognito user pool in Pulumi and I need to reference its region in another resource.
How does one get the region for a resource in Pulumi?

The AWS provider doesn't allow defining the region per each resource. Instead, region is a property of the provider itself.
If you use the default ambient provider, then the region is in aws.config.region:
const user = new aws.cognito.UserPool("up", { ... });
export const region = aws.config.region;
If you use an explicit provider, the region is defined by its options:
const myProvider = new aws.Provider("my-provider", {
region: "eu-north-1",
});
const user = new aws.cognito.UserPool("up", { ... }, { provider: myProvider });

Related

Detect if user is connected to firebase app

I want to implement an "isActive" feature on my app that is built using firebase firestore. I am using firebase functions along with authentication in my React App.
Is there a way of detecting if the user is "active" or "inActive" on my app by triggering a cloud function when they login or disconnect to the app?
If i can determine this i would store the value in firestore and handle it in the frontend to display a UI.
Thanks
I see two aspects to the question here:
Auth state: You want to track the logged-in duration of the user.
Focus state: You want to track when the user is active on the app.
For #1, you will have to listen to the auth state changes, and you may also want to change your auth state persistence strategy accordingly. From https://firebase.google.com/docs/auth/web/auth-state-persistence:
Enum
Value
Description
firebase.auth.Auth.Persistence.LOCAL
'local'
Indicates that the state will be persisted even when the browser window is closed or the activity is destroyed in React Native. An explicit sign out is needed to clear that state. Note that Firebase Auth web sessions are single host origin and will be persisted for a single domain only.
firebase.auth.Auth.Persistence.SESSION
'session'
Indicates that the state will only persist in the current session or tab, and will be cleared when the tab or window in which the user authenticated is closed. Applies only to web apps.
firebase.auth.Auth.Persistence.NONE
'none'
Indicates that the state will only be stored in memory and will be cleared when the window or activity is refreshed.
import { getAuth, setPersistence, signInWithRedirect, inMemoryPersistence, GoogleAuthProvider } from "firebase/auth";
const auth = getAuth();
setPersistence(auth, inMemoryPersistence)
.then(() => {
const provider = new GoogleAuthProvider();
// In memory persistence will be applied to the signed in Google user
// even though the persistence was set to 'none' and a page redirect
// occurred.
return signInWithRedirect(auth, provider);
})
.catch((error) => {
// Handle Errors here.
const errorCode = error.code;
const errorMessage = error.message;
});
You don't need a cloud function for th
For #2, you might want to check out this blog. https://javascript.plainenglish.io/validate-your-apps-session-on-focus-892f610f7e23.
import { useLocation } from '#reach/router';
import React, { useEffect } from 'react';
import { useDispatch } from 'react-redux';
export function WindowFocusHandler() {
const dispatch = useDispatch()
const location = useLocation()
useEffect(() => {
window.addEventListener("focus", onFocus)
return () => {
window.removeEventListener("focus", onFocus)
}
}, [])
const onFocus = () => dispatch(session.effects.checkSessionOnFocus(location))
return <></>
}
The Focus event on a window might get triggered more often if it is a browser app. Depending on what you want to achieve, both things should be possible in
your front-end code without the need for cloud functions. Although, you might opt to code the logic as a firebase function and invoke it from your react code when onFocus.

Update global state after RTK Query loads data

I've noticed a problem with splitting responsibilities in React components based on the fetched data using RTK Query.
Basically, I have two components like HomePage and NavigationComponent.
On HomePage I'd like to fetch the information about the user so that I can modify NavigationComponent accordingly.
What I do inside HomePage:
import { setNavigationMode } from "features/nav/navSlice";
export default function HomePage() {
const {data: user} = useGetUserDataQuery();
const dispatch = useAppDispatch();
const navMode = user ? "all-options" : "none";
dispatch(setNavigationMode(navMode)); // here I change the default Navigation mode
return <MainLayout>
<Navigation/>
<Content/>
<Footer/>
</MainLayout>;
}
The HomePage is a special Page when the NavigationComponent shouldn't display any options for the not logged in user.
Other pages presents additional Logo and Title on Nav.
React communicates:
Warning: Cannot update a component (NavComponent) while rendering a different component (HomePage). To locate the bad setState() call inside HomePage, follow the stack trace as described in https://reactjs.org/link/setstate-in-render
Not sure what is the right way to follow.
Whether the state should be changed in GetUser query after it is loaded - that doesn't seem to be legit.
problem is dispatch calls every render. Instead you can create a navigationSlice (if you don't have already) and use extraReducers for matching your authorization action like:
extraReducers: (builder) => {
builder.addMatcher(
usersApi.endpoints.login.matchFulfilled,
(state, { payload }) => {
if (payload.user) {
state.navigationMode = "all-options"
}
}
);
}
This way, state.navigationMode will only change when authorization changes
The solution was too obvious. The dispatch should be run in useEffect.
import { setNavigationMode } from "features/nav/navSlice";
export default function HomePage() {
const {data: user} = useGetUserDataQuery();
const dispatch = useAppDispatch();
const navMode = user ? "all-options" : "none";
// changed lines
useEffect( () => {
dispatch(setNavMode(navMode));
}, [navMode, dispatch]);
// /changed lines
return <MainLayout>
<Navigation/>
<Content/>
<Footer/>
</MainLayout>;
}
Thank you #papa-xvii for the hint with changing the navMode after user login. That solves the second problem I had.
However I cannot accept the answer as it does not solve the problem I described above.

Google charged me $5000 in a month for using Google Place API

My project is under development, Vuejs and Flutter in the frontend and Laravel is in the backend.
I am using Google place autocomplete API in this project, I made a big mistake due to not having enough knowledge of using google apiz.
After trial finished google charged $5000.
My mistakes were 2 things;
Requesting unnecessary data and not providing sessionToken
I am posting my edited codes here if anyone can check it please, I'm afraid to make mistake again.
vuejs code
mounted() {
this.$refs.focusable.focus();
let $vm = this;
var autocomplete = new google.maps.places.Autocomplete(
document.getElementById("autocomplete"),
{
componentRestrictions: { country: "ca" },
fields: ["address_components", "formatted_address", "geometry"],
types: ["address"],
bounds: new google.maps.LatLngBounds(
new google.maps.LatLng(49.246292, -123.116226)
),
//strictbounds: true,
}
);
google.maps.event.addListener(autocomplete, "place_changed", function () {
var data = autocomplete.getPlace();
let latlng = {
lat: data.geometry.location.lat(),
lng: data.geometry.location.lng(),
};
data.address_components.forEach((component) => {
if (component.types.indexOf("administrative_area_level_1") > -1) {
if ($vm.checkState(component.short_name)) {
$vm.validAddress(data, latlng);
} else {
$vm.invalidAddress(data);
}
}
});
});
},
According to google docs link I don't need to provide sessionToken for Autocomplete widget. and I think my code is correct here.
and this is my Flutter code
TextFormField(
autofocus: true,
controller: _addressController,
decoration: InputDecoration(hintText: 'Postal code'),
onChanged: (val) {
final sessionToken = Uuid.v4();
findPlace(val, sessionToken);
},
),
//get a place
void findPlace(String placeName, String sessionToken) async {
if (placeName.length > 1) {
String autoComplete =
"$googleApi?input=$placeName&types=address&components=country:ca&key=$mapKey&sessiontoken=$sessionToken";
var res = await http.get(Uri.parse(autoComplete));
Map data = jsonDecode(res.body);
var predictions = data['predictions'];
var placesList = (predictions as List)
.map((e) => PlacePredictions.fromJson(e))
.toList();
setState(() {
sToken = sessionToken;
placePredictionList = placesList;
});
}
}
// get place details using place_id
addressDetails(placeId, sessionToken) async {
String fields = 'address_component,formatted_address,geometry';
String placeDetailsUrl =
"$googleApiDetails?place_id=$placeId&fields=$fields&key=$mapKey&sessiontoken=$sessionToken";
var res = await http.get(Uri.parse(placeDetailsUrl));
Map data = jsonDecode(res.body);
}
In the above Flutter code there is a confusion for me is this sessiontoken or sessionToken I don't know how to check it and there is no any information in the Google docs.
Help really appreciated.
Can't post as a comment as I don't have the required rep.
But you can cap your API usage so things like these won't happen.
Read more here: https://cloud.google.com/apis/docs/capping-api-usage
In the Google Cloud console, go to the APIs & Services Dashboard page.
From the projects list, select a project or create a new one.
Click the name of the API you're interested in.
Click Quotas. If the Quotas tab is not present in the tab nav, it means the API you've selected doesn't have quotas defined.
To find the quota you want to cap, enter the appropriate properties and values in the filter_list Filter field. For example, to find the Subnetworks quota, enter Quota:Subnetworks.
Click the checkbox next to the quota you want to cap, and then click create EDIT QUOTAS.
Complete the quota change form, including the new limit that you want to set.
Click SUBMIT REQUEST.

How to check if the logged-in Realm user logged in via "Sign in with Apple"?

The alternative title is "How to check the logged-in Realm user logged in via certain authentication provider?" OR "How to check a user is using a specific authentication provider/method?"
For an app start with an anonymous user and then linked to another authentication provider using user.linkUser(credentials: credential). Since the user always has a value either an anonymous user or a linked user.
How can I know if the current logged-in user is already linked with another auth provider e.g. "Sign in with Apple" or "Google"? This information needs to be known in order to hide the auth provider sign-in button.
In RealmSwift 10.12.0
There is an identifiers property under user. It is an array of RLMUserIdentity. the user identity contains a providerType string, https://docs.mongodb.com/realm-sdks/objc/latest/Classes/RLMUserIdentity.html#/c:objc(cs)RLMUserIdentity(py)providerType
Below is a sample output
print(">>> DEBUG:", user.identities.map { identity in (identity.identifier, identity.providerType)
[("611a27f9a1575af5ed15234e-lnnaeteekatdftrnsmpbpldr", "anon-user"), ("000766.23cbd125344c140b18ef0baa4deccaf32.61234", "oauth2-apple")]
Now you can check if the user identities contains the provider you care and hide the "sign in" button/link for that provider
https://github.com/realm/realm-cocoa/blob/d407cdc1c8be5f04c3decd37b88524855edfa7e8/Realm/RLMCredentials.mm
When you initialize a realm app, it checks by default for the accessToken, refresh token and other stuff that Realm does to store user data on the device after successful login. So, the default value when you declare your current user should be retrieved from Realm app instance. In my case, I use web development and it looks like this for React application.
import React, { useState } from 'react';
import LoginPage from 'containers/LoginPage';
import { RealmApp, getCustomCredentials } from './RealmApp';
function App() {
const [currentUser, setCurrentUser] = useState(RealmApp.currentUser);
const onAuth = async (data) => {
const credentials = getCustomCredentials(data);
const user = await RealmApp.logIn(credentials);
setCurrentUser(user);
};
const App = () => {
return (
<Box className="app-root-component" sx={{ display: 'flex' }}>
<h1>App</>
</Box>
);
};
return currentUser ? <App /> : <LoginPage onAuth={onAuth} />;
}
export default App;
here I have my variable & it's setter function
const [currentUser, setCurrentUser] = useState(RealmApp.currentUser);
I wish that helps you to get closer with apple sign in

How to send notifications following recent Firestore updates using Firebase FCM and Ionic Native

I am trying to set up Cloud Messaging Functions using https://www.youtube.com/watch?v=SOOjamH1bAA&t=317s
The code for my question is at 7:35 of this video. The full doc is in the link accessible from the video.
I am struggling with the recent updates to Firestore (see https://firebase.google.com/docs/functions/beta-v1-diff#cloud-firestore ), especially for time 7:35 of the youtube video link above. following the updates I changed the .onCreate to:
exports.newSubscriberNotification = functions.firestore
.document('subscribers/{subscriberId}')
.onCreate((snap,context) => { //I notice no async event...
const data = snap.data();
The problem is: 'await' expression is only allowed within an async function. This makes sense as there is no longer an 'async event' due to the update.
const devices = await devicesRef.get(); //see time 8:25 of video above.
If I add an async even above, the problem becomes: Property 'error' does not exist on type '“” | Promise' on the line:
devices.forEach(result => {...}) //see time 8:35 of video above.
I have tried multiple solutions found online but I'm digging myself in a hole. I think the problem is I am not triggering the index.ts function file (according to console.log() ).
Please bear with me - I am relatively new to app development.
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
import { Subject } from 'rxjs/Subject';
import { tap } from 'rxjs/operators';
admin.initializeApp();
console.log('before initializeApp');
exports.newSubscriberNotification = functions.firestore
.document('subscribers/{subscriberId}') //odd
.onCreate((snap,context) => {
const data = snap.data();
console.log('const data fired');
const userId = data.userId
const subscriber = data.subscriberId
console.log('gathered data')
// Notification content
const payload = {
notification: {
title: 'New Subscriber',
body: `${subscriber} is following your content!`,
}
}
// ref to the device collection for the user
const db = admin.firestore();
const devicesRef = db.collection('devices').where('userId', '==', userId);
// get the user's tokens and send notifications
console.log('before await');
const devices = await devicesRef.get();
console.log('async function');
console.log('before devices');
//devices();
console.log('after devices');
const tokens = [];
// send a notification to each device token
devices.forEach(result => {
const token = result.data().token;
tokens.push( token )
})
return admin.messaging().sendToDevice(tokens, payload)
});