├── .editorconfig ├── .gitignore ├── LICENSE ├── README.md ├── babel.config.js ├── index.js ├── package.json ├── public ├── favicon.ico └── index.html ├── src ├── App.vue ├── assets │ └── images │ │ ├── g-signin-focus.png │ │ └── g-signin-normal.png ├── components │ ├── GoogleSigninBtn.vue │ └── GoogleUser.vue ├── core │ └── gapi.js └── main.js ├── tests └── unit │ ├── .eslintrc.js │ └── example.spec.js └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.{js,jsx,ts,tsx,vue}] 2 | indent_style = space 3 | indent_size = 2 4 | trim_trailing_whitespace = true 5 | insert_final_newline = true 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw* 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Vert Citron & Stéphane Souron 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-google-api 2 | 3 | ## This project is outdated and no longer maintained, I can't find time to do what should be done here. Really sorry, if someone wants to maintain it, tell me, I accept to transfer ownership, or even without asking me, fork it... 4 | 5 | This vue 2 plugin is a wrapper for the script needed to do client side operations with Google APIs and Google authentication. 6 | 7 | The plugin loads the Google API client library script dynamically, and append it to the document's head, without need to manually edit `index.html` file. This makes the `gapi` object accessible at `window.gapi` and you can do with it all the operations described in the [Google client library for Javascript documentation](https://developers.google.com/api-client-library/javascript/). 8 | 9 | But more than this, it also exposes the `$gapi` object through the Vue prototype, accessible from everywhere via `Vue.$gapi`, or via `this.$gapi` from within a component. `$gapi` encapsulate the `gapi` object and simplifies its operations by automatically doing loadings and initializations when needed, chaining the transitional results through a promises chain and always returns the expected result (or error) in a promise, to respect the asynchronous nature of the Google APIs and authentication processes. 10 | 11 | The plugin also globally registers a `GoogleSigninBtn` component which is a 'Signin with Google' button in the respect of the Google's guidelines for it. 12 | 13 | ## Installation 14 | 15 | ```bash 16 | yarn add vue-google-api 17 | ``` 18 | 19 | Then, in the file where you instantiate vue.js (generally `main.js`) : 20 | ```javascript 21 | import Vue from 'vue' 22 | import VueGoogleApi from 'vue-google-api' 23 | 24 | const config = { 25 | apiKey: 'your_api_key', 26 | clientId: 'your_client_id.apps.googleusercontent.com', 27 | scope: 'space_separated_scopes', 28 | discoveryDocs: [ list_of_discoverydocs_urls ] 29 | } 30 | Vue.use(VueGoogleApi, config) 31 | ``` 32 | `config` is an object containing the API key, the client Id, the authorization scope and optionally the discovery docs as described in the [Google API Client reference](https://developers.google.com/api-client-library/javascript/reference/referencedocs#gapiclientinitargs). You can learn how to obtain these parameters in the [Google API Guides / Get started page](https://developers.google.com/api-client-library/javascript/start/start-js#setup). 33 | 34 | ## Usage 35 | 36 | In normal usage, `$gapi` cares, when a final method is requested, to do all the intermediate stuff that is needed, such as loading parts of the client (commonly `client` and `auth2`), initializing them and performing required checks. It then returns a fulfilled promise containing the requested result in cas eof success, or a rejected promise in case of error, eventually containing various explanations about what happened. 37 | 38 |   39 | 40 | --- 41 | > **Vue.$gapi.isSignedIn()** 42 | 43 | Returns through an always resolved promise a boolean indicating if a user is actually signed in or not. 44 | ```javascript 45 | this.$gapi.isSignedIn() 46 | .then(result => { 47 | console.log(result ? 'Signed in' : 'Signed out') 48 | }) 49 | ``` 50 | 51 |   52 | 53 | --- 54 | > **Vue.$gapi.currentUser()** 55 | 56 | Returns through an always resolved promise the current user in a readable format if one is connected, or `null` if no user is connected. 57 | ```javascript 58 | this.$gapi.currentUser() 59 | .then(user => { 60 | if (user) { 61 | console.log('Signed in as %s', user.name) 62 | } else { 63 | console.log('No user is connected.') 64 | } 65 | }) 66 | ``` 67 | The user object corresponds to the [Google User Basic Profile](https://developers.google.com/api-client-library/javascript/reference/referencedocs#googleusergetbasicprofile) informations, but in a friendly format : 68 | ```javascript 69 | { 70 | id: google_user_identifier, 71 | name: full_name, 72 | firstname: given_name, 73 | lastname: family_name, 74 | image: user_thumbnail_url, 75 | email: email_address 76 | } 77 | ``` 78 | 79 |   80 | 81 | --- 82 | > **Vue.$gapi.signIn()** 83 | 84 | Starts an Oauth2 sign in process. It will open the Google authentification popup where the user will be prompted to identify, with a prefilled profile if the browser was already connected the the Google account. It could be followed by a password request and / or a captcha request, and then by another popup where the user has to authorize the application if it has never been done and depending on the application requested scope. 85 | 86 | If the user completes the authentication procedure (generally by just clicking his profile), the method returns a fulfilled promise containing the signed in user, with the same format than from `$gapi.currentUser()`. 87 | 88 | If anything goes wrong (for example if the user closes the authentication popup without signing in), the method returns a rejected Promise with an object containing an `error` property explaining what's wrong : 89 | 90 | ```javascript 91 | this.$gapi.signIn() 92 | .then(user => { 93 | console.log('Signed in as %s', user.name) 94 | }) 95 | .catch(err => { 96 | console.error('Not signed in: %s', err.error) 97 | }) 98 | ``` 99 | 100 |   101 | 102 | --- 103 | > **Vue.$gapi.signOut()** 104 | 105 | Disconnects the signed in user from the application. Returns an empty resolved promise when it's done. 106 | ```javascript 107 | this.$gapi.signOut() 108 | .then(() => { 109 | console.log('User disconnected.') 110 | }) 111 | ``` 112 | 113 |   114 | 115 | --- 116 | > **Vue.$gapi.request(args)** 117 | 118 | Makes a generic request to one of the several Google's APIs endpoint, as specified in the [Google API Client Reference](https://developers.google.com/api-client-library/javascript/reference/referencedocs#gapiclientrequestargs). Only the `path` property is mandatory, all the other ones are optional. Depending of several things and the authorizations the user has granted to the application, the method responds by a resolved promise containing the response, or a reject one containing a structure where informations on why it has failed can be found. 119 | 120 | ```javascript 121 | this.$gapi.request({ 122 | path: 'https://people.googleapis.com/v1/people/me?personFields=names,emailAddresses', 123 | method: 'GET', 124 | params: { 125 | personFields: 'names,emailAddresses' 126 | } 127 | }).then(response => { 128 | console.log(response) 129 | }) 130 | ``` 131 | 132 | To find and use Google's APIs endpoints, please refer to each API documentation, this is not the purpose of this Readme. 133 | 134 | ## Google Signin button component 135 | 136 | The plugin registers globally a Google Sign In button, respecting the [Google's guidelines](https://developers.google.com/identity/branding-guidelines) for such an element : 137 | 138 | ![Google sign in button](https://developers.google.com/identity/images/btn_google_signin_light_normal_web.png) 139 | 140 | The component re-emits its native click event as a vue click event to handle it the way you want. It also re-emits its keypress.enter as he same click event. 141 | 142 | It optionally takes two attributes: 143 | - `label`: Sets the text displayed in the button. Defaults to *"Signin in with Google"* 144 | - `custom-class`: A class name which overrides the default rendering of the button. The default styling includes two additional nested classes: `span.icon` and `span.text`, that also can be redefined cascading the custom class. 145 | 146 | ```html 147 | 148 | ... 149 | 157 | ``` 158 | 159 |   160 | 161 | ## Intermediate methods 162 | 163 | The methods seen above automatically calls and wait for intermediate methods that loads the required parts of the client and initialize what is needed. The wrapper always check if the required object need to be loaded or is already present, and need to be initialized or not, and acts in consequence. 164 | 165 | But if you need, for special purposes, to directly access these intermediate methods and their results, they are all exposed prefixed by an underscore: _ 166 | 167 |   168 | 169 | --- 170 | > **Vue.$gapi._load()** 171 | 172 | Loads the gapi global object and returns it through a promise. If it has already been loaded, directly resolves the promise without reloading it: 173 | ```javascript 174 | this.$gapi._load() 175 | .then(gapi => { 176 | console.log('gapi object :', gapi) 177 | }) 178 | ``` 179 | This object is exactly the base object where lives all the methods explained in the [Google API Client Javascript Library reference](https://developers.google.com/api-client-library/javascript/reference/referencedocs#top_of_page), and you can perform on it all the operations they describe. 180 | 181 |   182 | 183 | --- 184 | > **Vue.$gapi._libraryLoad('lib')** 185 | 186 | Loads a gapi sub library by its name (for example `client` or `auth2`). It makes an internal call to `$gapi._load()` so `gapi` is previously loaded if it hasn't been done. It returns through a promise the sub library itself. If the sub library has already been loaded, it doesn't reload it and resolves immediately. If it hasn't already been done, the sub library have to be initialized. 187 | ```javascript 188 | this.$gapi._libraryLoad('auth2') 189 | .then(auth2 => { 190 | return auth2.init(this.$gapi.config) 191 | }) 192 | ``` 193 | 194 |   195 | 196 | --- 197 | > **Vue.$gapi._libraryInit('lib', [ config ])** 198 | 199 | Initializes the specified library with an application config. As usual, loads `gapi` if needed and loads the library if needed too by an internal call to `_libraryLoad`. 200 | 201 | The config parameter is an object containing optional API key, Client Id, etc., as discussed in the plugin installation, but can be different here if you need a special config for a particular API call. If this optional parameter is omitted, the library will be initialized with the config passed down at the installation process (`Vue.use(VueGoogleApi, config)`). If one of its sub-properties is omitted, it wil be replaced by this base config same property value. 202 | 203 | The method returns, through a promise, the initialized library, ready to be used for API calls for example. 204 | 205 | One example of overriding the application API config is for example to grab in the client library particular methods to call one or more precise Google APIs by furnishing the DiscoveryDoc for that API: 206 | 207 | ```javascript 208 | this.$gapi._libraryInit('client', { discoveryDocs: [ 'https://people.googleapis.com/$discovery/rest' ]}) 209 | .then(client => { 210 | return client.people.people.get({ 211 | 'resourceName': 'people/me', 212 | 'requestMask.includeField': 'person.names' 213 | }).then(response => { 214 | console.log(response.result) 215 | }) 216 | }) 217 | ``` 218 | Even if you didn't completed the discoveryDocs property at the plugin installation time, you'll get a client with the people API facility. You can also give for different APIs different clientIds and apiKeys if you want to track hits from different Google Cloud accounts or projects for example. 219 | 220 |   221 | 222 | ## Development setup 223 | 224 | Clone the project, cd into it and install dependencies: 225 | 226 | *(if you don't use yarn, you can replace `yarn` commands by `npm run`...)* 227 | 228 | ``` 229 | git clone "https://github.com/vertcitron/vue-google-api.git" 230 | cd vue-google-api 231 | yarn install 232 | ``` 233 | Then create at the root of the project a .env.local file with your own Google application identifiers like this : 234 | ``` 235 | VUE_APP_CLIENTID=your_client_id.apps.googleusercontent.com 236 | VUE_APP_APIKEY=your_api_key 237 | VUE_APP_SCOPE=your_application_scope 238 | ``` 239 | You can also add a VUE_APP_DISCOVERYDOCS key / value if you need. 240 | 241 | This file will not be versionned by git and will remain local in your computer. 242 | 243 | Otherwise you can modify the `main.js` file to directly introduce these values if you don't want to use a .env file. 244 | 245 | Then you can work with the project, with the following commands: 246 | - Compiles and hot-reloads for development: `yarn serve` 247 | - Compiles and minifies for production: `yarn build` 248 | - Run tests: `yarn test` 249 | - Lints and fixes files: `yarn lint` 250 | 251 | `App.vue` and its children contains a basic Google authentication layout, with a component presenting the user if one is signed in or a signin button otherwise. 252 | 253 | The plugin `index.js` file is at the project's root, and the gapi wrapper is located at `core/GAPI.js` 254 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/app' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /************************************************************************************************** 2 | * 3 | * GOOGLE API WRAPPER FOR VUE.JS 2 4 | * 5 | *************************************************************************************************/ 6 | 7 | import GAPI from './src/core/gapi' 8 | import GoogleSigninBtn from './src/components/GoogleSigninBtn' 9 | 10 | export default { 11 | /** Plugin install method */ 12 | install (Vue, config) { 13 | Object.defineProperty(Vue.prototype, '$gapi', { value: new GAPI(config) }) 14 | Vue.component('GoogleSigninBtn', GoogleSigninBtn) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-google-api", 3 | "version": "v0.2.1", 4 | "private": false, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint", 9 | "test:unit": "vue-cli-service test:unit" 10 | }, 11 | "dependencies": { 12 | "set-value": "^2.0.1", 13 | "vue": "^2.5.17" 14 | }, 15 | "devDependencies": { 16 | "@vue/cli-plugin-babel": "^3.8.0", 17 | "@vue/cli-plugin-eslint": "^3.8.0", 18 | "@vue/cli-plugin-unit-jest": "^3.8.0", 19 | "@vue/cli-service": "^3.8.0", 20 | "@vue/eslint-config-standard": "^4.0.0", 21 | "@vue/test-utils": "^1.0.0-beta.20", 22 | "babel-core": "7.0.0-bridge.0", 23 | "babel-eslint": "^10.0.1", 24 | "babel-jest": "^23.6.0", 25 | "eslint": "^5.8.0", 26 | "eslint-plugin-vue": "^5.0.0-0", 27 | "standard": "^12.0.1", 28 | "vue-template-compiler": "^2.5.17" 29 | }, 30 | "resolutions": { 31 | "acorn": "^7.1.1", 32 | "kind-of": "^6.0.3", 33 | "minimist": "^1.2.3", 34 | "serialize-javascript": "^2.1.1", 35 | "mem": "^4.0.0", 36 | "braces": "^2.3.1" 37 | }, 38 | "eslintConfig": { 39 | "root": true, 40 | "env": { 41 | "node": true 42 | }, 43 | "extends": [ 44 | "plugin:vue/essential", 45 | "@vue/standard" 46 | ], 47 | "rules": {}, 48 | "parserOptions": { 49 | "parser": "babel-eslint" 50 | } 51 | }, 52 | "postcss": { 53 | "plugins": { 54 | "autoprefixer": {} 55 | } 56 | }, 57 | "browserslist": [ 58 | "> 1%", 59 | "last 2 versions", 60 | "not ie <= 8" 61 | ], 62 | "jest": { 63 | "moduleFileExtensions": [ 64 | "js", 65 | "jsx", 66 | "json", 67 | "vue" 68 | ], 69 | "transform": { 70 | "^.+\\.vue$": "vue-jest", 71 | ".+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$": "jest-transform-stub", 72 | "^.+\\.jsx?$": "babel-jest" 73 | }, 74 | "moduleNameMapper": { 75 | "^@/(.*)$": "/src/$1" 76 | }, 77 | "snapshotSerializers": [ 78 | "jest-serializer-vue" 79 | ], 80 | "testMatch": [ 81 | "**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)" 82 | ], 83 | "testURL": "http://localhost/" 84 | }, 85 | "description": "This vue 2 plugin is a wrapper for the script needed to do client side operations with Google APIs and Google authentication.", 86 | "main": "index.js", 87 | "directories": { 88 | "test": "tests" 89 | }, 90 | "repository": { 91 | "type": "git", 92 | "url": "git+https://github.com/vertcitron/vue-google-api.git" 93 | }, 94 | "keywords": [ 95 | "google", 96 | "api", 97 | "authentication", 98 | "oauth2" 99 | ], 100 | "author": "ssouron", 101 | "license": "MIT", 102 | "bugs": { 103 | "url": "https://github.com/vertcitron/vue-google-api/issues" 104 | }, 105 | "homepage": "https://github.com/vertcitron/vue-google-api#readme" 106 | } 107 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vertcitron/vue-google-api/702f83c6376e0ac1a4f3aaa8a8685cd9eac5cbff/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | vue-google-api 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 42 | 72 | -------------------------------------------------------------------------------- /src/assets/images/g-signin-focus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vertcitron/vue-google-api/702f83c6376e0ac1a4f3aaa8a8685cd9eac5cbff/src/assets/images/g-signin-focus.png -------------------------------------------------------------------------------- /src/assets/images/g-signin-normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vertcitron/vue-google-api/702f83c6376e0ac1a4f3aaa8a8685cd9eac5cbff/src/assets/images/g-signin-normal.png -------------------------------------------------------------------------------- /src/components/GoogleSigninBtn.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 19 | 20 | 56 | -------------------------------------------------------------------------------- /src/components/GoogleUser.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 38 | 39 | 74 | -------------------------------------------------------------------------------- /src/core/gapi.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 3 | * GAPI WRAPPER 4 | * 5 | ******************************************************************************/ 6 | 7 | /** 8 | * Exposes methods related to the Google API Client and Auth modules. 9 | * As they are a part of the gapi object, each method returns 10 | * always a promise because it always calls it through its loader, 11 | * to be sure to properly load things it if ir's not present. 12 | * In the same manner, because things could change between two calls and 13 | * as the Google's guidelines suggest, the client and auth objects are 14 | * initialized for each call, and as this is done asynchronously it enforces 15 | * the promise response. 16 | */ 17 | 18 | /** 19 | * It has been done through a class definition for two reasons : 20 | * * It's easier to bind this to the good things from inside a class 21 | * * It allows to easily extend the class by inheritance (or its JS mimic...) 22 | * * It also allows to instanciate, if needed, more than one GAPI in the same 23 | * application, with different config for some edge cases. 24 | */ 25 | 26 | const timeout = 5000 27 | const gapiUrl = 'https://apis.google.com/js/api.js' 28 | 29 | /** Formats a GoogleUser basic profile object to something readable */ 30 | function _formatUser (guser) { 31 | if (!guser.getBasicProfile) return null 32 | const profile = guser.getBasicProfile() 33 | return { 34 | id: profile.getId(), 35 | name: profile.getName(), 36 | firstname: profile.getGivenName(), 37 | lastname: profile.getFamilyName(), 38 | image: profile.getImageUrl(), 39 | email: profile.getEmail() 40 | } 41 | } 42 | 43 | export default class GAPI { 44 | /** 45 | * The constructor expect as parameter the config object, containing 46 | * API key, Cliend Id, the scope and the Google's discovery docs, as 47 | * it's defined at : 48 | * https://developers.google.com/api-client-library/javascript/reference/referencedocs#gapiclientinitargs 49 | */ 50 | constructor (config) { 51 | this.config = config 52 | } 53 | 54 | /** Exposes the gapi object, loading the script and attaching it to 55 | * document's head if it hasn't been done */ 56 | _load () { 57 | // resolves immediately if already loaded 58 | if (window.gapi) return Promise.resolve(window.gapi) 59 | 60 | // otherwise prepares and loads 61 | return new Promise((resolve, reject) => { 62 | const script = document.createElement('script') 63 | script.src = gapiUrl 64 | let limit = setTimeout(() => { 65 | // reject promise in case of a timeout. 66 | script.remove() 67 | reject(new Error('gapi load timeout.')) 68 | }, timeout) 69 | document.head.appendChild(script) 70 | 71 | // defines the callback that resolves on successful load 72 | script.onload = () => { 73 | clearTimeout(limit) 74 | // let's reject if the global gapi object has not been created 75 | if (!window.gapi) reject(new Error('gapi load error.')) 76 | 77 | // otherwise, everything is ok, resolves 78 | resolve(window.gapi) 79 | } 80 | }) 81 | } 82 | 83 | /** Exposes a gapi library object, loading it if it hasn't been done */ 84 | _libraryLoad (lib) { 85 | return this._load() 86 | .then(gapi => { 87 | if (gapi[lib]) return Promise.resolve(gapi[lib]) 88 | return new Promise((resolve, reject) => { 89 | gapi.load(lib, { 90 | timeout: timeout, 91 | callback: () => { 92 | resolve(gapi[lib]) 93 | }, 94 | onerror: err => { 95 | reject(new Error(`Error on gapi ${lib} load: ${err.message}`)) 96 | }, 97 | ontimeout: () => { 98 | reject(new Error(`Error on gapi ${lib} load: timeout`)) 99 | } 100 | }) 101 | }) 102 | }) 103 | } 104 | 105 | /** Initialize a gapi library object with config before each API call. 106 | * Return the library object through a Promise. */ 107 | _libraryInit (lib, config = {}) { 108 | // fills omitted parameters wit hmain config ones if needed 109 | config.apiKey = config.apiKey || this.config.apiKey 110 | config.clientId = config.clientId || this.config.clientId 111 | config.scope = config.scope || this.config.scope 112 | config.discoveryDocs = config.discoveryDocs || this.config.discoveryDocs 113 | return this._libraryLoad(lib) 114 | .then(library => { 115 | return library.init(config) 116 | .then(response => { 117 | // if auth2, returns the google auth object, the library otherwise 118 | return Promise.resolve((lib === 'auth2') ? response : library) 119 | }, () => { 120 | return Promise.reject(new Error(`Error on gapi ${lib} init.`)) 121 | }) 122 | }) 123 | } 124 | 125 | /** returns asynchronously true if the user is signed in */ 126 | isSignedIn () { 127 | return this._libraryInit('auth2') 128 | .then(auth => { 129 | return Promise.resolve(auth.isSignedIn.get()) 130 | }) 131 | } 132 | 133 | /** returns asynchronously true if the user is signed in */ 134 | getAuthObject () { 135 | return this._libraryInit('auth2') 136 | } 137 | 138 | /** returns the current user if signed in, undefined otherwise */ 139 | currentUser () { 140 | return this._libraryInit('auth2') 141 | .then(auth => { 142 | if (auth.isSignedIn.get()) { 143 | return Promise.resolve(_formatUser(auth.currentUser.get())) 144 | } else { 145 | return Promise.resolve(null) 146 | } 147 | }) 148 | } 149 | 150 | /** Starts the signin process - returns a promise resolved with the user if 151 | * signin successfull, or rejected otherwise */ 152 | signIn () { 153 | return this._libraryInit('auth2') 154 | .then(auth => { 155 | if (auth.isSignedIn.get()) { 156 | return Promise.resolve(_formatUser(auth.currentUser.get())) 157 | } else { 158 | return auth.signIn() 159 | .then(guser => { 160 | return Promise.resolve(_formatUser(guser)) 161 | }) 162 | } 163 | }) 164 | } 165 | 166 | /** Disconnects the current user */ 167 | signOut () { 168 | return this._libraryInit('auth2') 169 | .then(auth => { 170 | if (auth.isSignedIn.get()) { 171 | auth.disconnect() 172 | } 173 | return Promise.resolve() 174 | }) 175 | } 176 | 177 | /** Makes a generic API request */ 178 | request (args) { 179 | return this._libraryInit('client') 180 | .then(client => { 181 | return client.request(args) 182 | }) 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | import VueGoogleApi from '../index.js' 4 | 5 | Vue.config.productionTip = false 6 | 7 | const ddocs = process.env.VUE_APP_DDOCS 8 | Vue.use(VueGoogleApi, { 9 | apiKey: process.env.VUE_APP_APIKEY, 10 | clientId: process.env.VUE_APP_CLIENTID, 11 | discoveryDocs: ddocs ? ddocs.split(',') : [], 12 | scope: process.env.VUE_APP_SCOPE 13 | }) 14 | 15 | new Vue({ 16 | render: h => h(App) 17 | }).$mount('#app') 18 | -------------------------------------------------------------------------------- /tests/unit/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | jest: true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /tests/unit/example.spec.js: -------------------------------------------------------------------------------- 1 | import { shallowMount } from '@vue/test-utils' 2 | import HelloWorld from '@/components/HelloWorld.vue' 3 | 4 | describe('HelloWorld.vue', () => { 5 | it('renders props.msg when passed', () => { 6 | const msg = 'new message' 7 | const wrapper = shallowMount(HelloWorld, { 8 | propsData: { msg } 9 | }) 10 | expect(wrapper.text()).toMatch(msg) 11 | }) 12 | }) 13 | --------------------------------------------------------------------------------