Redux Form post to /user/:id - redux

I am using redux form, but I would like to post the data from the form to this route user/:id.
But my action just get data from the form, what is the best to way to send this id for action create?
export async function createUser(props){
const request = await post(`/users`, props);
return {
type: CREATE_USER,
payload: request
}
}
How can I pass the id to change my url to /users/${id}

I don't really see anything here related to redux-form, but assuming your id is in your props object, you could do:
const request = await post(`/users/${props.id}`, props);
However, it seems pretty strange that you would even have an id if you are creating the user. Usually the primary key is generated upon creation, so what you have already would be just fine, and your server-side CRUD API should be smarter about not expecting an id.

Related

How to make Next-Auth-session-token-dependent server queries with React Query in Next JS?

I am trying to make an API GET request, using React Query's useInfiniteQuery hook, that uses data from a Next Auth session token in the query string.
I have a callback in /api/auth/[...nextauth.ts] to send extra userData to my session token.
There are two relevant pages on the client side. Let's call them /pages/index.tsx and /hooks/useApiData.ts. This is what they look like, for all intents and purposes:
// pages/index.tsx
export default function Page() {
const {data, fetchNextPage, isLoading, isError} = useCourseData()
if (isLoading) return <main />
return <main>
<InfiniteScroller fetchMore={fetchNextPage}>
{data?.pages?.map(page => page?.results?.map(item: string => item))}
</InfiniteScroller>
</main>
}
// hooks/useApiData.ts
async function fetchPage(pageParam: string) {
const response = await fetch(pageParam)
return await response.json()
}
export default function useApiData() {
const {data: session} = useSession()
const init = `/api?userData=${session?.user?.userData}`
return useInfiniteQuery('query',
({pageParam = init}) => fetchPage(pageParam),
{getNextPageParam: prevPage => prevPage.next ?? undefined}
)
}
My initial request gets sent to the API as /api?userData=undefined. The extra data is definitely making its way into the token.
I can place the data from my session in the DOM via the render function of /pages/index.tsx, so I figure the problem is something to do with custom hooks running before the session context is ready, or something like that... I don't understand the mechanics of hooks well enough to figure that out.
I've been looking for answers for a long time, and I'm surprised not to have found a single person with the same issue. These are not unpopular packages and I guess a lot of people are using them in conjunction to achieve what I'm attempting here, so I figure I must be doing something especially dumb. But what?!
How can I get the data from my Next Auth session into my React Query request? And for bonus points, why is the session data not available when the request is sent in my custom hook?

What is the correct way to use next-auth with Google OAuth and users stored in the database?

I'm new to next-auth, and I'm looking for some help.
I have added the Google OAuth provider, and now when I run signIn("google") function on the frontend, it automatically takes me to the google's login page, and logs me in, somehow, without ever touching my database.
When the google authentication is complete, I need to be able to create a new user in my database, or retrieve the existing one if they have already signed up before (because I need to store all kinds of custom information about the user, not just their email).
And I want to make user's information available on the session object from useSession()hook. Right now I'm seeing some kind of default user info (with name, email, and image field which I didn't define).
When I was using a regular Express server and Passport, the code looked kinda like this:
const googleAuth = new GoogleStrategy(
{
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: "/api/v1/profiles/google/callback",
},
async (req, accessToken, refreshToken, profile, done) => {
const existingProfile = await Profile.findOne({ email: profile.emails[0].value })
/* Found user, return him and move along. */
if (existingProfile) return done(null, existingProfile)
/* Haven't found profile with this googleId, create a new one. */
const newProfile = await new Profile({
googleId: profile.id,
email: profile.emails[0].value,
})
newProfile.save()
done(null, newProfile)
}
)
So I would still be creating the users in my database, and retrieving their information on log in, so that I could send it to the client.
Where does this kind of code supposed to go when I'm using the serverless next-auth?
And a second, but kind of related question - what's that default user object that gets provided to me in the session object? The one with the name, email, and image fields that next-auth seems to create for me? How can I make it use the user object I'm returning from my database instead?
(I've done my best to look through the tutorials and examples, but couldn't find one that explains this clearly.)
I don't know if you still need this, but I hope it helps someone:
Oauth kinda mixes up Sign In and Sign Up, so if you want to have Google authentication what you probably want to do is create a callback of the Sign In function in /api/auth/[...nextauth].js, then get the account and profile as parameters and access to its provider.
async signIn({account, profile}) {
if(account.provider === 'google') {
//check if user is in your database
if(user NOT in DB) {
//add your user in DB here with profile data (profile.email, profile.name)
}
return true
}
You always want to return true since you always want to log in independently if it is in your DB or not.
Regarding the session object, you can also add a callback and access to the default session (that you can modify), token and user. Here you can retrieve all information you want from your database, add it to the session object and return it.
async session({ session, token, user }) {
const newData = DB.find(...).data
session.newfield = newInfo
return session
}

Dynamic callback endpoints with cloud functions

When a user triggers a function there’s a POST request going away to a partner. Within the body I need to include a unique endpoint callbackURL with an Id so they can send me status updates linked with a specific user. How can I accomplish that? I know how to setup static endpoints, but not create new ones for every request.
As Doug said in his comment above, you don't need a new URL (i.e. a new endpoint) for each different id. You can deploy only one HTTP Cloud Function (which exposes one endpoint) and, in the Cloud Function, you extract the value of id from the Request object with its originalUrl property, as follows:
exports.myWebhook = functions.https.onRequest((req, res) => {
const urlArray = req.originalUrl.split('/');
console.log(urlArray);
console.log(urlArray[1]);
const id = urlArray[1];
//Do whatever you need with id
//.....
//If you want to test that it works with a browser, you can send it back as a response to the browser
res.send(urlArray[1]);
});
You then call this Cloud Function with the following URI:
https://us-central1-yourprojectname.cloudfunctions.net/myWebhook/id/callback
Note that it is also possible to extract values from the Request body, see https://firebase.google.com/docs/functions/http-events?authuser=0#read_values_from_the_request.

Fetch data for record edit page

I have a page that lets you edit user data. I'm using FlowRouter for the routing and it can be found on the route /employees/:id.
I need to update the detail form when data changes on the server and leave the route if it was deleted by other client.
I decided to use Tracker.autorun which informs me whenever the data changes. The previous user info is stored on the template so it's easy to tell if the record was deleted.
Template.UpdateEmployee.onCreated(function () {
const self = this;
self.subscribe('user', FlowRouter.getParam('id'));
self.autorun(function () {
const _id = FlowRouter.getParam('id');
const user = Meteor.users.findOne({_id});
if(!user && self.user)
FlowRouter.go('/employees');
self.user = user;
if(!user)
return;
user.email = user.emails[0].address;
$('.ui.form').form('set values',user);
});
});
And lastly in the onRendered callback I'm checking if the data was set on template as I believe not doing so could lead to data being available before the template is rendered and hence values wouldn't get set properly. Is this correct?
Template.UpdateEmployee.onRendered(function () {
if(this.user){
user.email = user.emails[0].address;
$('.ui.form').form('set values',user);
}
});
Are there any pitfalls to this solution?
I can see a couple drawbacks inherently. The first one is doing a find query on the client. Typically you would want to return data from the server using Meteor publish and subscribe.
The second is you are passing the key to find the data over the URL. This can be spoofed by other users for them to find that users data.
Lastly if you are doing a find on the user object, I assume you might be storing data there. This is generally bad practice. If you need to store user data with their profile, it's best to create a new collection and publish/subscribe what you need.

meteor-shopify User Creation/ Login after Auth callback

Assuming I want to create users upon authorizing the app, how would I grab their email during the onAuth callback...? Looks like the callback assumes the user is already logged in. Am I thinking about it correctly?
I noticed when installing the Fishbowl Prizes app, after auth I can click on the accounts tab and see that all my account info is pre-populated from my shopify store account (name, email, address, etc).
I'm not sure if I should go by the title or the content of the post in terms of answering your question, so I'll provide a very simple example of how to get the info from the API and do something with it here.
I have provided a more in depth answer related specifically to grabbing the details from the API for user account creation here: https://github.com/froatsnook/meteor-shopify/issues/15#issuecomment-177413630
Looks like the callback assumes the user is already logged in.
The userId param is undefined if there is no user. If your onAuth operations don't need to do anything with the user, you can just leave it out of the params. In your case you'll just want to handle it conditionally using an if/else block:
if(!userId){
// do stuff
} else {
// do other stuff
}
On to the example of grabbing those details from the API:
All the prepopulated information you are seeing is available from the Shopify API in the shop object. You already have the access token when onAuth callbacks are fired, so you can just grab it from the API immediately after you have inserted the shop's Keyset.
For the sake of simplicity, in this example we'll assume the user already exists and is logged in. In your server-side onAuth callback (after you have inserted the keyset) you can do something like this to add those fields to the user's profile object:
Shopify.onAuth(function(access_token, authConfig, userId) {
var shopUUID = uuid.new(); // Not secure to name keyset same as the shop!
Shopify.addKeyset(shopUUID, {
access_token: access_token
});
var api = new Shopify.API({
shop: authConfig.shop,
keyset: shopUUID
});
// get the Shop object from the API
var shopObj = api.getShop();
var userInfo = {
'profile.name': shopObj.shop_owner,
'profile.email': shopObj.email,
'profile.phone': shopObj.phone,
'profile.shopName': shopObj.name
};
Meteor.users.update({_id: userId}, {$set: userInfo})
});
Then you can use them in templates like this:
{{currentUser.profile.name}} or {{currentUser.profile.email}}
Or in functions like so:
var realName = Meteor.user().profile.name
or
var userEmail = Meteor.user().profile.email etc
For a more about using this data for user creation, see my explanation here:
https://github.com/froatsnook/meteor-shopify/issues/15#issuecomment-177413630

Resources