From 7617fd602a922cfb756f198da5c49e5512e88bd9 Mon Sep 17 00:00:00 2001 From: hammadj Date: Wed, 11 Jan 2017 20:36:42 -0700 Subject: [PATCH 1/7] Add to changelog --- client/CHANGELOG.md | 8 ++++++++ meteor-server/CHANGELOG.md | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/client/CHANGELOG.md b/client/CHANGELOG.md index b4ce074..369128d 100644 --- a/client/CHANGELOG.md +++ b/client/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +### vNEXT + +- Add `initWithClient(apolloClientInstance)` function to remove need for passing apollo with every function call +- Calling `userId()` is now synchronous and more performant since it's cached in memory +- Added the following hooks/callbacks: `onLogin`, `onLoginFailure`, `onLogout` so the API is similar to Meteor Accounts +- Added `loggingIn` function, similar to Meteor Accounts +- Added support for persisting login automatically. As soon as you call `initWithClient` in your app, it will check for a stored token and attempt to login, calling the `onLogin` callback if it succeeds. + ### v2.0.0 - React Native support. diff --git a/meteor-server/CHANGELOG.md b/meteor-server/CHANGELOG.md index 2a5ab71..daa5621 100644 --- a/meteor-server/CHANGELOG.md +++ b/meteor-server/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +### vNEXT + +- Added `loginWithToken` mutation + ### v3.0.1 - Fix bug with ```tmeasday:check-npm-versions```. From 1799bc16b7714368b10804edaad3b4d38b954a18 Mon Sep 17 00:00:00 2001 From: hammadj Date: Wed, 11 Jan 2017 23:01:47 -0700 Subject: [PATCH 2/7] update docs --- README.md | 204 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 126 insertions(+), 78 deletions(-) diff --git a/README.md b/README.md index a2249ed..59e43e5 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,65 @@ npm install meteor-apollo-accounts ## Tutorials - [Using Meteor With Apollo and React](https://blog.orionsoft.io/using-meteor-accounts-with-apollo-and-react-df3c89b46b17#.znozw2zbd) +## Example Usage + +```js +import React, { Component } from 'react'; +import Accounts from 'meteor-apollo-accounts'; +import client from './ApolloClient'; // instance of apollo-client + +Accounts.initWithClient(client); //do this only once + +Accounts.onLogin(() => { + console.log(Accounts.userId()); +}); + +export default class Login extends Component { + constructor() { + this.state = { + username: '', + password: '' + }; + this.login = this.login.bind(this); + this.onUsernameChange = this.onUsernameChange.bind(this); + this.onPwdChange = this.onPwdChange.bind(this); + } + + login(e) { + const { username, password } = this.state; + e.preventDefault(); + Accounts.loginWithPassword({ username, password }) + .catch(function(err) { + console.log("Error logging in", err); + }); + } + + onUsernameChange(event) { + this.setState({username: event.target.value}); + } + + onPwdChange(event) { + this.setState({password: event.target.value}); + } + + render() { + const { username, password } = this.state; + return ( +
+
+
+ + +
+ +
+
+ ) + } +} + +``` + ## Methods Meteor accounts methods, client side only. All methods are promises. @@ -62,9 +121,7 @@ Meteor accounts methods, client side only. All methods are promises. Log the user in with a password. ```js -import { loginWithPassword } from 'meteor-apollo-accounts' - -loginWithPassword({username, email, password, plainPassword}, apollo) +Accounts.loginWithPassword({username, email, password, plainPassword}) ``` - ```username```: Optional. The user's username. @@ -75,159 +132,150 @@ loginWithPassword({username, email, password, plainPassword}, apollo) - ```plainPassword```: Optional. The plain user's password. Recommended only for use in testing tools, like GraphiQL. -- ```apollo```: Apollo client instance. -#### changePassword +#### logout -Change the current user's password. Must be logged in. +Log the user out. ```js -import { changePassword } from 'meteor-apollo-accounts' +Accounts.logout() +``` + +#### onLogin + +Register a function to be called when a user logged in -changePassword({oldPassword, newPassword}, apollo) +```js +Accounts.onLogin(() => { + console.log('Current User: ', Accounts.userId()) + ... + // Fetch data, change routes, etc +}) ``` -- ```oldPassword```: The user's current password. This is not sent in plain text over the wire. +#### onLoginFailure -- ```newPassword```: A new password for the user. This is not sent in plain text over the wire. +Register a function to be called when a login attempt is failed -- ```apollo```: Apollo client instance. +```js +Accounts.onLoginFailure(() => { + console.log('Login Failed'); + ... + // Set route to login page, reset store, etc +}) +``` -#### logout +#### onLogout -Log the user out. +Register a function to be called when a user logs out ```js -import { logout } from 'meteor-apollo-accounts' +Accounts.onLogout(() => { + console.log('User Logged Out'); + ... + // Set route to login page, reset store, etc +}) +``` + +#### loggingIn -logout(apollo) +Returns true if a login method (such as Accounts.loginWithPassword, Accounts.loginWithFacebook, or Accounts.createUser) is currently in progress. +```js +console.log('Currently logging in? : ', Accounts.loggingIn()) ``` -- ```apollo```: Apollo client instance. +#### userId + +Returns the id of the logged in user. + +```js +console.log('The user id is:', Accounts.userId()) +``` + +#### changePassword + +Change the current user's password. Must be logged in. + +```js +Accounts.changePassword({oldPassword, newPassword}) +``` + +- `oldPassword`: The user's current password. This is not sent in plain text over the wire. + +- `newPassword`: A new password for the user. This is not sent in plain text over the wire. + #### createUser Create a new user. ```js -import { createUser } from 'meteor-apollo-accounts' - -createUser({username, email, password, profile}, apollo) +Accounts.createUser({username, email, password, profile}) ``` -- ```username```: A unique name for this user. +- `username`: A unique name for this user. -- ```email```: The user's email address. +- `email`: The user's email address. -- ```password```: The user's password. This is not sent in plain text over the wire. +- `password`: The user's password. This is not sent in plain text over the wire. -- ```profile```: The profile object based on the ```UserProfileInput``` input type. +- `profile`: The profile object based on the ```UserProfileInput``` input type. -- ```apollo```: Apollo client instance. #### verifyEmail Marks the user's email address as verified. Logs the user in afterwards. ```js -import { verifyEmail } from 'meteor-apollo-accounts' - -verifyEmail({token}, apollo) +Accounts.verifyEmail({token}) ``` - ```token```: The token retrieved from the verification URL. -- ```apollo```: Apollo client instance. - - #### forgotPassword Request a forgot password email. ```js -import { forgotPassword } from 'meteor-apollo-accounts' - -forgotPassword({email}, apollo) +Accounts.forgotPassword({email}) ``` - ```email```: The email address to send a password reset link. -- ```apollo```: Apollo client instance. - #### resetPassword Reset the password for a user using a token received in email. Logs the user in afterwards. ```js -import { resetPassword } from 'meteor-apollo-accounts' - -resetPassword({newPassword, token}, apollo) +Accounts.resetPassword({newPassword, token}) ``` - ```newPassword```: A new password for the user. This is not sent in plain text over the wire. - ```token```: The token retrieved from the reset password URL. -- ```apollo```: Apollo client instance. - - #### loginWithFacebook Logins the user with a facebook accessToken ```js -import { loginWithFacebook } from 'meteor-apollo-accounts' - -loginWithFacebook({accessToken}, apollo) +Accounts.loginWithFacebook({accessToken}) ``` - ```accessToken```: A Facebook accessToken. It's recommended to use https://github.com/keppelen/react-facebook-login to fetch the accessToken. -- ```apollo```: Apollo client instance. - #### loginWithGoogle Logins the user with a google accessToken ```js -import { loginWithGoogle } from 'meteor-apollo-accounts' - -loginWithGoogle({accessToken}, apollo) +Accounts.loginWithGoogle({accessToken}) ``` - ```accessToken```: A Google accessToken. It's recommended to use https://github.com/anthonyjgrove/react-google-login to fetch the accessToken. -- ```apollo```: Apollo client instance. - - -#### onTokenChange - -Register a function to be called when a user is logged in or out. - -```js -import { onTokenChange } from 'meteor-apollo-accounts' - -onTokenChange(function () { - console.log('token did change') - apollo.resetStore() -}) -``` - -#### userId - -Returns the id of the logged in user. - -```js -import { userId } from 'meteor-apollo-accounts' - -async function () { - console.log('The user id is:', await userId()) -} - -``` - ### React-Native usage From 3ff767a27c466e5e65260a94362d4b1f838a1449 Mon Sep 17 00:00:00 2001 From: hammadj Date: Wed, 11 Jan 2017 23:05:39 -0700 Subject: [PATCH 3/7] Modify headings in readme --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 59e43e5..c9fdd3c 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ This package uses the Meteor Accounts methods in GraphQL, it's compatible with t ## Installing -### Install on Meteor server +## Install on Meteor server ```sh meteor add nicolaslopezj:apollo-accounts @@ -37,7 +37,7 @@ const executableSchema = makeExecutableSchema(schema) ``` -### Install on your apollo app +## Install on your apollo app May or may not be the same app. @@ -45,15 +45,15 @@ May or may not be the same app. npm install meteor-apollo-accounts ``` -## Examples +### Examples - [janikvonrotz/meteor-apollo-accounts-example](https://github.com/janikvonrotz/meteor-apollo-accounts-example): Meteor client and server side. - [orionsoft/server-boilerplate](https://github.com/orionsoft/server-boilerplate): Large Meteor server side only starter app. -## Tutorials +### Tutorials - [Using Meteor With Apollo and React](https://blog.orionsoft.io/using-meteor-accounts-with-apollo-and-react-df3c89b46b17#.znozw2zbd) -## Example Usage +### Example Usage ```js import React, { Component } from 'react'; @@ -112,7 +112,7 @@ export default class Login extends Component { ``` -## Methods +### Methods Meteor accounts methods, client side only. All methods are promises. From 3228eda59bb064ba428e778e698d04406e24ea8c Mon Sep 17 00:00:00 2001 From: hammadj Date: Wed, 11 Jan 2017 23:14:53 -0700 Subject: [PATCH 4/7] add initWithClient to ReadMe --- README.md | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c9fdd3c..72967d2 100644 --- a/README.md +++ b/README.md @@ -116,6 +116,22 @@ export default class Login extends Component { Meteor accounts methods, client side only. All methods are promises. +#### initWithClient + +Initialize the accounts system with an instance of Apollo Client. You only need to do this once in your app, typically upon startup. + +```js +import ApolloClient from 'apollo-client'; +import Accounts from 'meteor-apollo-accounts'; + +const client = new ApolloClient(); + +Accounts.initWithClient(client); +``` + +- ```client```: Your instance of Apollo Client + + #### loginWithPassword Log the user in with a password. @@ -159,7 +175,7 @@ Register a function to be called when a login attempt is failed ```js Accounts.onLoginFailure(() => { - console.log('Login Failed'); + console.log('Login Failed') ... // Set route to login page, reset store, etc }) @@ -171,7 +187,7 @@ Register a function to be called when a user logs out ```js Accounts.onLogout(() => { - console.log('User Logged Out'); + console.log('User Logged Out') ... // Set route to login page, reset store, etc }) From 817430bd05a1f5a87a9216e339453e1e198382c7 Mon Sep 17 00:00:00 2001 From: hammadj Date: Thu, 12 Jan 2017 00:45:42 -0700 Subject: [PATCH 5/7] Add react native instructions to ReadMe --- README.md | 63 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 43 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 72967d2..215d956 100644 --- a/README.md +++ b/README.md @@ -305,35 +305,58 @@ import { AsyncStorage } from 'react-native'; -import { loginWithPassword, userId, setTokenStore} from 'meteor-apollo-accounts' - -// Then you'll have to define a TokenStore for your user data using setTokenStore -// (for instance when your component is mounted): -setTokenStore({ - set: async function ({userId, token, tokenExpires}) { - await AsyncStorage.setItem('Meteor.userId', userId) - await AsyncStorage.setItem('Meteor.loginToken', token) - // AsyncStorage doesn't support Date type so we'll store it as a String - await AsyncStorage.setItem('Meteor.loginTokenExpires', tokenExpires.toString()) +import Accounts, { USER_ID_KEY, TOKEN_KEY, TOKEN_EXPIRES_KEY } from 'meteor-apollo-accounts'; +import client from './ApolloClient'; // Your instance of apollo client + +// Then you'll have to define a TokenStore for your user data using setTokenStore. +// This should be done before calling Accounts.initWithClient: +Accounts.setTokenStore({ + async set({ userId, token, tokenExpires }) { + return AsyncStorage.multiSet([ + [USER_ID_KEY, userId], + [TOKEN_KEY, token], + [TOKEN_EXPIRES_KEY, tokenExpires.toString()] + ]); }, - get: async function () { - return { - userId: await AsyncStorage.getItem('Meteor.userId'), - token: await AsyncStorage.getItem('Meteor.loginToken'), - tokenExpires: await AsyncStorage.getItem('Meteor.loginTokenExpires') - } + async get() { + const stores = await AsyncStorage.multiGet([ + USER_ID_KEY, + TOKEN_KEY, + TOKEN_EXPIRES_KEY + ]); + + const userId = stores[0][1]; + const token = stores[1][1]; + const tokenExpires = stores[2][1]; + + return { userId, token, tokenExpires }; + }, + async remove() { + return AsyncStorage.multiRemove([ + USER_ID_KEY, + TOKEN_KEY, + TOKEN_EXPIRES_KEY + ]); } -}) +}); + +// Make sure to initialize before calling anything else in Accounts: +Accounts.initWithClient(client); + // Finally, you'll be able to use asynchronously any method from the library: + +Accounts.onLogin(() => { + console.log(Accounts.userId()); +}); + async login (event) { event.preventDefault(); try { - const id_ = await loginWithPassword({ "email", "password" }, this.client) - this.client.resetStore() + const id = await Accounts.loginWithPassword({ "email", "password" }) } catch (error) { - + console.log("Error logging in: ", error); } } From 22ae0974514299178e0924a9545071df01ce202b Mon Sep 17 00:00:00 2001 From: hammadj Date: Tue, 17 Jan 2017 13:09:54 -0700 Subject: [PATCH 6/7] include instructions to properly initialize apollo-client to pass token in header --- README.md | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 215d956..5982f5f 100644 --- a/README.md +++ b/README.md @@ -56,9 +56,35 @@ npm install meteor-apollo-accounts ### Example Usage ```js +// client.js +import ApolloClient, { createNetworkInterface } from 'apollo-client'; +import Accounts from 'meteor-apollo-accounts'; + +const networkInterface = createNetworkInterface({ uri: 'localhost:3000/graphql' }); + +networkInterface.use([{ + applyMiddleware(req, next) { + if (!req.options.headers) { + req.options.headers = {}; + } + req.options.headers.authorization = Accounts.getLoginToken() || null; + next(); + } +}]); + +const client = new ApolloClient({ + networkInterface, + dataIdFromObject: (result) => result._id +}); + +export default client; +``` + +```js +// Login.jsx import React, { Component } from 'react'; import Accounts from 'meteor-apollo-accounts'; -import client from './ApolloClient'; // instance of apollo-client +import client from './client'; // instance of apollo-client Accounts.initWithClient(client); //do this only once From 6ce1a8a4c0e316fa55c9380fa7aa374a5e57e42f Mon Sep 17 00:00:00 2001 From: hammadj Date: Tue, 17 Jan 2017 13:10:13 -0700 Subject: [PATCH 7/7] Add snippet about react native in intro --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5982f5f..a6fb2c9 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ A implementation of Meteor Accounts only in GraphQL with Apollo. -This package uses the Meteor Accounts methods in GraphQL, it's compatible with the accounts you have saved in your database and you may use apollo-accounts and Meteor's DPP accounts at the same time. +This package uses the Meteor Accounts methods in GraphQL, it's compatible with the accounts you have saved in your database and you may use apollo-accounts and Meteor's DPP accounts at the same time. It is also compatible with React Native using AsyncStorage (see guide at end of ReadMe). > Sorry for all the api changes, now we will use [graphql-loader](https://github.com/orionsoft/graphql-loader) for a long term solution.