diff --git a/src/generators/app/index.js b/src/generators/app/index.js index a28f5336c..4bc786152 100644 --- a/src/generators/app/index.js +++ b/src/generators/app/index.js @@ -262,6 +262,10 @@ export class Generator extends Base { message: 'Would you like to include additional oAuth strategies?', when: answers => answers.auth, choices: [{ + value: 'githubAuth', + name: 'GitHub', + checked: false + }, { value: 'googleAuth', name: 'Google', checked: false @@ -317,6 +321,7 @@ export class Generator extends Base { }); } insight.track('oauth', !!this.filters.oauth); + insight.track('github-oauth', !!this.filters['githubeAuth']); insight.track('google-oauth', !!this.filters['googleAuth']); insight.track('facebook-oauth', !!this.filters['facebookAuth']); insight.track('twitter-oauth', !!this.filters['twitterAuth']); diff --git a/src/test/main.test.js b/src/test/main.test.js index 79dbfff5d..454c67c11 100644 --- a/src/test/main.test.js +++ b/src/test/main.test.js @@ -197,7 +197,7 @@ describe('angular-fullstack:app', function() { testing: 'jasmine', odms: ['mongoose'], auth: true, - oauth: ['twitterAuth', 'facebookAuth', 'googleAuth'], + oauth: ['twitterAuth', 'facebookAuth', 'googleAuth', 'githubAuth'], socketio: true, bootstrap: true, uibootstrap: true diff --git a/templates/app/_package.json b/templates/app/_package.json index 7d119f9c0..a1ddc5f0c 100644 --- a/templates/app/_package.json +++ b/templates/app/_package.json @@ -33,14 +33,21 @@ "connect-mongo": "^1.2.1",<% } %><% if(filters.sequelize) { %> "sequelize": "^3.23.6", "sqlite3": "~3.1.1", - "express-sequelize-session": "0.4.0",<% } %><% if(filters.auth) { %> + "express-sequelize-session": "0.4.0",<% } %> + <%_ if(filters.auth) { -%> "jsonwebtoken": "^7.0.0", "express-jwt": "^5.0.0", "passport": "~0.3.0", - "passport-local": "^1.0.0",<% } %><% if(filters.facebookAuth) { %> - "passport-facebook": "^2.0.0",<% } %><% if(filters.twitterAuth) { %> - "passport-twitter": "^1.0.3",<% } %><% if(filters.googleAuth) { %> - "passport-google-oauth20": "^1.0.0",<% } %><% if(filters.socketio) { %> + "passport-local": "^1.0.0",<% } %> + <%_ if(filters.facebookAuth) { -%> + "passport-facebook": "^2.0.0",<% } %> + <%_ if(filters.twitterAuth) { -%> + "passport-twitter": "^1.0.3",<% } %> + <%_ if(filters.googleAuth) { -%> + "passport-google-oauth20": "^1.0.0",<% } %> + <%_ if(filters.githubAuth) { -%> + "passport-github": "^1.1.0",<% } %> + <%_ if(filters.socketio) { -%> "socket.io": "^1.3.5", "socket.io-client": "^1.3.5", "socketio-jwt": "^4.2.0",<% } %> diff --git a/templates/app/client/components/oauth-buttons(oauth)/oauth-buttons(css).css b/templates/app/client/components/oauth-buttons(oauth)/oauth-buttons(css).css index be33316e0..60e5b2fff 100644 --- a/templates/app/client/components/oauth-buttons(oauth)/oauth-buttons(css).css +++ b/templates/app/client/components/oauth-buttons(oauth)/oauth-buttons(css).css @@ -1,20 +1,25 @@ -<% if (!filters.bootstrap) { if (filters.facebookAuth) { %>.btn-facebook { +<%_ if(!filters.bootstrap) { -%> + <%_ if(filters.facebookAuth) { -%> +.btn-facebook { color: #fff; background-color: #3B5998; border-color: #133783; -} -<% } if (filters.googleAuth) { %>.btn-google { +}<% } %> + <%_ if(filters.googleAuth) { -%> +.btn-google { color: #fff; background-color: #dd4b39; border-color: #c53727; -} -<% } if (filters.twitterAuth) { %>.btn-twitter { +}<% } %> + <%_ if(filters.twitterAuth) { -%> +.btn-twitter { color: #fff; background-color: #2daddc; border-color: #0271bf; -} -<% } %>.btn-github { +}<% } %> + <%_ if(filters.githubAuth) { -%> +.btn-github { color: #fff; - background-color: #fafafa; - border-color: #ccc; + background-color: #444444; }<% } %> +<% } %> \ No newline at end of file diff --git a/templates/app/client/components/oauth-buttons(oauth)/oauth-buttons(html).html b/templates/app/client/components/oauth-buttons(oauth)/oauth-buttons(html).html index 7b9b0623a..b14eec94a 100644 --- a/templates/app/client/components/oauth-buttons(oauth)/oauth-buttons(html).html +++ b/templates/app/client/components/oauth-buttons(oauth)/oauth-buttons(html).html @@ -1,12 +1,20 @@ -<% if(filters.facebookAuth) { %> +<%_ if(filters.facebookAuth) { -%> + Connect with Facebook - -<% } if (filters.googleAuth) { %> +<% } %> +<%_ if(filters.googleAuth) { -%> + Connect with Google+ - -<% } if (filters.twitterAuth) { %> +<% } %> +<%_ if(filters.twitterAuth) { -%> + Connect with Twitter <% } %> +<%_ if(filters.githubAuth) { -%> + + + Connect with GitHub +<% } %> diff --git a/templates/app/client/components/oauth-buttons(oauth)/oauth-buttons(less).less b/templates/app/client/components/oauth-buttons(oauth)/oauth-buttons(less).less index be33316e0..60e5b2fff 100644 --- a/templates/app/client/components/oauth-buttons(oauth)/oauth-buttons(less).less +++ b/templates/app/client/components/oauth-buttons(oauth)/oauth-buttons(less).less @@ -1,20 +1,25 @@ -<% if (!filters.bootstrap) { if (filters.facebookAuth) { %>.btn-facebook { +<%_ if(!filters.bootstrap) { -%> + <%_ if(filters.facebookAuth) { -%> +.btn-facebook { color: #fff; background-color: #3B5998; border-color: #133783; -} -<% } if (filters.googleAuth) { %>.btn-google { +}<% } %> + <%_ if(filters.googleAuth) { -%> +.btn-google { color: #fff; background-color: #dd4b39; border-color: #c53727; -} -<% } if (filters.twitterAuth) { %>.btn-twitter { +}<% } %> + <%_ if(filters.twitterAuth) { -%> +.btn-twitter { color: #fff; background-color: #2daddc; border-color: #0271bf; -} -<% } %>.btn-github { +}<% } %> + <%_ if(filters.githubAuth) { -%> +.btn-github { color: #fff; - background-color: #fafafa; - border-color: #ccc; + background-color: #444444; }<% } %> +<% } %> \ No newline at end of file diff --git a/templates/app/client/components/oauth-buttons(oauth)/oauth-buttons(sass).scss b/templates/app/client/components/oauth-buttons(oauth)/oauth-buttons(sass).scss index be33316e0..60e5b2fff 100644 --- a/templates/app/client/components/oauth-buttons(oauth)/oauth-buttons(sass).scss +++ b/templates/app/client/components/oauth-buttons(oauth)/oauth-buttons(sass).scss @@ -1,20 +1,25 @@ -<% if (!filters.bootstrap) { if (filters.facebookAuth) { %>.btn-facebook { +<%_ if(!filters.bootstrap) { -%> + <%_ if(filters.facebookAuth) { -%> +.btn-facebook { color: #fff; background-color: #3B5998; border-color: #133783; -} -<% } if (filters.googleAuth) { %>.btn-google { +}<% } %> + <%_ if(filters.googleAuth) { -%> +.btn-google { color: #fff; background-color: #dd4b39; border-color: #c53727; -} -<% } if (filters.twitterAuth) { %>.btn-twitter { +}<% } %> + <%_ if(filters.twitterAuth) { -%> +.btn-twitter { color: #fff; background-color: #2daddc; border-color: #0271bf; -} -<% } %>.btn-github { +}<% } %> + <%_ if(filters.githubAuth) { -%> +.btn-github { color: #fff; - background-color: #fafafa; - border-color: #ccc; + background-color: #444444; }<% } %> +<% } %> \ No newline at end of file diff --git a/templates/app/client/components/oauth-buttons(oauth)/oauth-buttons(stylus).styl b/templates/app/client/components/oauth-buttons(oauth)/oauth-buttons(stylus).styl index 995d4c766..ace003c55 100644 --- a/templates/app/client/components/oauth-buttons(oauth)/oauth-buttons(stylus).styl +++ b/templates/app/client/components/oauth-buttons(oauth)/oauth-buttons(stylus).styl @@ -1,16 +1,21 @@ -<% if (!filters.bootstrap) { if (filters.facebookAuth) { %>.btn-facebook +<%_ if(!filters.bootstrap) { -%> + <%_ if(filters.facebookAuth) { -%> +.btn-facebook color #fff background-color #3B5998 - border-color #133783 -<% } if (filters.googleAuth) { %>.btn-google + border-color #133783<% } %> + <%_ if(filters.googleAuth) { -%> +.btn-google color #fff background-color #dd4b39 - border-color #c53727 -<% } if (filters.twitterAuth) { %>.btn-twitter + border-color #c53727<% } %> + <%_ if(filters.twitterAuth) { -%> +.btn-twitter color #fff background-color #2daddc - border-color #0271bf -<% } %>.btn-github + border-color #0271bf<% } %> + <%_ if(filters.githubAuth) { -%> +.btn-github color #fff - background-color #fafafa - border-color #ccc<% } %> + background-color #444444<% } %> +<% } %> \ No newline at end of file diff --git a/templates/app/e2e/account(auth)/login/login.spec(jasmine).js b/templates/app/e2e/account(auth)/login/login.spec(jasmine).js index 780ed57d0..51a6ba158 100644 --- a/templates/app/e2e/account(auth)/login/login.spec(jasmine).js +++ b/templates/app/e2e/account(auth)/login/login.spec(jasmine).js @@ -51,6 +51,9 @@ describe('Login View', function() { expect(page.form.oauthButtons.google.getAttribute('class')).toMatch('btn-block');<% } if (filters.twitterAuth) { %> expect(page.form.oauthButtons.twitter.getText()).toBe('Connect with Twitter'); expect(page.form.oauthButtons.twitter.getAttribute('class')).toMatch('btn-block');<% } %> + <%_ if (filters.githubAuth) { -%> + expect(page.form.oauthButtons.github.getText()).toBe('Connect with GitHub'); + expect(page.form.oauthButtons.github.getAttribute('class')).toMatch('btn-block');<% } %> });<% } %> describe('with local auth', function() { diff --git a/templates/app/e2e/account(auth)/login/login.spec(mocha).js b/templates/app/e2e/account(auth)/login/login.spec(mocha).js index fd11f4131..cf927aef6 100644 --- a/templates/app/e2e/account(auth)/login/login.spec(mocha).js +++ b/templates/app/e2e/account(auth)/login/login.spec(mocha).js @@ -51,6 +51,9 @@ describe('Login View', function() { <%= expect() %>page.form.oauthButtons.google.getAttribute('class')<%= to() %>.eventually.contain('btn-block');<% } if (filters.twitterAuth) { %> <%= expect() %>page.form.oauthButtons.twitter.getText()<%= to() %>.eventually.equal('Connect with Twitter'); <%= expect() %>page.form.oauthButtons.twitter.getAttribute('class')<%= to() %>.eventually.contain('btn-block');<% } %> + <%_ if (filters.githubAuth) { -%> + <%= expect() %>page.form.oauthButtons.github.getText()<%= to() %>.eventually.equal('Connect with GitHub'); + <%= expect() %>page.form.oauthButtons.github.getAttribute('class')<%= to() %>.eventually.contain('btn-block');<% } %> });<% } %> describe('with local auth', function() { diff --git a/templates/app/e2e/account(auth)/signup/signup.spec(jasmine).js b/templates/app/e2e/account(auth)/signup/signup.spec(jasmine).js index a70f76f19..4da100cca 100644 --- a/templates/app/e2e/account(auth)/signup/signup.spec(jasmine).js +++ b/templates/app/e2e/account(auth)/signup/signup.spec(jasmine).js @@ -1,7 +1,7 @@ 'use strict'; -var config = browser.params;<% if (filters.mongooseModels) { %> -var UserModel = require(config.serverConfig.root + '/server/api/user/user.model').default;<% } %><% if (filters.sequelizeModels) { %> +var config = browser.params;<% if(filters.mongooseModels) { %> +var UserModel = require(config.serverConfig.root + '/server/api/user/user.model').default;<% } %><% if(filters.sequelizeModels) { %> var UserModel = require(config.serverConfig.root + '/server/sqldb').User;<% } %> describe('Signup View', function() { @@ -38,22 +38,25 @@ describe('Signup View', function() { expect(page.form.confirmPassword.getAttribute('name')).toBe('confirmPassword'); expect(page.form.submit.getAttribute('type')).toBe('submit'); expect(page.form.submit.getText()).toBe('Sign up'); - });<% if (filters.oauth) { %> + });<% if(filters.oauth) { %> - it('should include oauth buttons with correct classes applied', function() {<% if (filters.facebookAuth) { %> + it('should include oauth buttons with correct classes applied', function() {<% if(filters.facebookAuth) { %> expect(page.form.oauthButtons.facebook.getText()).toBe('Connect with Facebook'); - expect(page.form.oauthButtons.facebook.getAttribute('class')).toMatch('btn-block');<% } if (filters.googleAuth) { %> + expect(page.form.oauthButtons.facebook.getAttribute('class')).toMatch('btn-block');<% } if(filters.googleAuth) { %> expect(page.form.oauthButtons.google.getText()).toBe('Connect with Google+'); - expect(page.form.oauthButtons.google.getAttribute('class')).toMatch('btn-block');<% } if (filters.twitterAuth) { %> + expect(page.form.oauthButtons.google.getAttribute('class')).toMatch('btn-block');<% } if(filters.twitterAuth) { %> expect(page.form.oauthButtons.twitter.getText()).toBe('Connect with Twitter'); expect(page.form.oauthButtons.twitter.getAttribute('class')).toMatch('btn-block');<% } %> + <%_ if(filters.githubAuth) { -%> + expect(page.form.oauthButtons.github.getText()).toBe('Connect with GitHub'); + expect(page.form.oauthButtons.github.getAttribute('class')).toMatch('btn-block');<% } %> });<% } %> describe('with local auth', function() { beforeAll(function(done) { - <% if (filters.mongooseModels) { %>UserModel.remove().then(done);<% } - if (filters.sequelizeModels) { %>UserModel.destroy({ where: {} }).then(done);<% } %> + <% if(filters.mongooseModels) { %>UserModel.remove().then(done);<% } + if(filters.sequelizeModels) { %>UserModel.destroy({ where: {} }).then(done);<% } %> }); it('should signup a new user, log them in, and redirecting to "/"', function() { diff --git a/templates/app/e2e/account(auth)/signup/signup.spec(mocha).js b/templates/app/e2e/account(auth)/signup/signup.spec(mocha).js index f7debbe47..9390dbe52 100644 --- a/templates/app/e2e/account(auth)/signup/signup.spec(mocha).js +++ b/templates/app/e2e/account(auth)/signup/signup.spec(mocha).js @@ -1,7 +1,7 @@ 'use strict'; -var config = browser.params;<% if (filters.mongooseModels) { %> -var UserModel = require(config.serverConfig.root + '/server/api/user/user.model').default;<% } %><% if (filters.sequelizeModels) { %> +var config = browser.params;<% if(filters.mongooseModels) { %> +var UserModel = require(config.serverConfig.root + '/server/api/user/user.model').default;<% } %><% if(filters.sequelizeModels) { %> var UserModel = require(config.serverConfig.root + '/server/sqldb').User;<% } %> describe('Signup View', function() { @@ -26,8 +26,8 @@ describe('Signup View', function() { }); after(function() { - <% if (filters.mongooseModels) { %>return UserModel.remove();<% } - if (filters.sequelizeModels) { %>return UserModel.destroy({ where: {} });<% } %> + <% if(filters.mongooseModels) { %>return UserModel.remove();<% } + if(filters.sequelizeModels) { %>return UserModel.destroy({ where: {} });<% } %> }); it('should include signup form with correct inputs and submit button', function() { @@ -41,22 +41,25 @@ describe('Signup View', function() { <%= expect() %>page.form.confirmPassword.getAttribute('name')<%= to() %>.eventually.equal('confirmPassword'); <%= expect() %>page.form.submit.getAttribute('type')<%= to() %>.eventually.equal('submit'); <%= expect() %>page.form.submit.getText()<%= to() %>.eventually.equal('Sign up'); - });<% if (filters.oauth) { %> + });<% if(filters.oauth) { %> - it('should include oauth buttons with correct classes applied', function() {<% if (filters.facebookAuth) { %> + it('should include oauth buttons with correct classes applied', function() {<% if(filters.facebookAuth) { %> <%= expect() %>page.form.oauthButtons.facebook.getText()<%= to() %>.eventually.equal('Connect with Facebook'); - <%= expect() %>page.form.oauthButtons.facebook.getAttribute('class')<%= to() %>.eventually.contain('btn-block');<% } if (filters.googleAuth) { %> + <%= expect() %>page.form.oauthButtons.facebook.getAttribute('class')<%= to() %>.eventually.contain('btn-block');<% } if(filters.googleAuth) { %> <%= expect() %>page.form.oauthButtons.google.getText()<%= to() %>.eventually.equal('Connect with Google+'); - <%= expect() %>page.form.oauthButtons.google.getAttribute('class')<%= to() %>.eventually.contain('btn-block');<% } if (filters.twitterAuth) { %> + <%= expect() %>page.form.oauthButtons.google.getAttribute('class')<%= to() %>.eventually.contain('btn-block');<% } if(filters.twitterAuth) { %> <%= expect() %>page.form.oauthButtons.twitter.getText()<%= to() %>.eventually.equal('Connect with Twitter'); <%= expect() %>page.form.oauthButtons.twitter.getAttribute('class')<%= to() %>.eventually.contain('btn-block');<% } %> + <%_ if(filters.githubAuth) { -%> + <%= expect() %>page.form.oauthButtons.github.getText()<%= to() %>.eventually.equal('Connect with GitHub'); + <%= expect() %>page.form.oauthButtons.github.getAttribute('class')<%= to() %>.eventually.contain('btn-block');<% } %> });<% } %> describe('with local auth', function() { before(function() { - <% if (filters.mongooseModels) { %>return UserModel.remove();<% } - if (filters.sequelizeModels) { %>return UserModel.destroy({ where: {} });<% } %> + <% if(filters.mongooseModels) { %>return UserModel.remove();<% } + if(filters.sequelizeModels) { %>return UserModel.destroy({ where: {} });<% } %> }) it('should signup a new user, log them in, and redirecting to "/"', function() { diff --git a/templates/app/e2e/components/oauth-buttons(oauth)/oauth-buttons.po.js b/templates/app/e2e/components/oauth-buttons(oauth)/oauth-buttons.po.js index c25d2b994..009d964e6 100644 --- a/templates/app/e2e/components/oauth-buttons(oauth)/oauth-buttons.po.js +++ b/templates/app/e2e/components/oauth-buttons(oauth)/oauth-buttons.po.js @@ -3,13 +3,16 @@ * https://docs.google.com/presentation/d/1B6manhG0zEXkC-H-tPo2vwU06JhL8w9-XCF9oehXzAQ */ -'use strict'; - var OauthButtons = function() { - var oauthButtons = this.oauthButtons = element(by.css('oauth-buttons'));<% if (filters.facebookAuth) { %> - oauthButtons.facebook = oauthButtons.element(by.css('.btn<% if (filters.bootstrap) { %>.btn-social<% } %>.btn-facebook'));<% } if (filters.googleAuth) { %> - oauthButtons.google = oauthButtons.element(by.css('.btn<% if (filters.bootstrap) { %>.btn-social<% } %>.btn-google'));<% } if (filters.twitterAuth) { %> - oauthButtons.twitter = oauthButtons.element(by.css('.btn<% if (filters.bootstrap) { %>.btn-social<% } %>.btn-twitter'));<% } %> + var oauthButtons = this.oauthButtons = element(by.css('oauth-buttons')); + <%_ if(filters.facebookAuth) { -%> + oauthButtons.facebook = oauthButtons.element(by.css('.btn<% if(filters.bootstrap) { %>.btn-social<% } %>.btn-facebook'));<% } %> + <%_ if(filters.googleAuth) { -%> + oauthButtons.google = oauthButtons.element(by.css('.btn<% if(filters.bootstrap) { %>.btn-social<% } %>.btn-google'));<% } %> + <%_ if(filters.twitterAuth) { -%> + oauthButtons.twitter = oauthButtons.element(by.css('.btn<% if(filters.bootstrap) { %>.btn-social<% } %>.btn-twitter'));<% } %> + <%_ if(filters.githubAuth) { -%> + oauthButtons.github = oauthButtons.element(by.css('.btn<% if(filters.bootstrap) { %>.btn-social<% } %>.btn-github'));<% } %> }; module.exports = new OauthButtons(); diff --git a/templates/app/server/api/user(auth)/user.model(mongooseModels).js b/templates/app/server/api/user(auth)/user.model(mongooseModels).js index f23208f12..cb437f9cb 100644 --- a/templates/app/server/api/user(auth)/user.model(mongooseModels).js +++ b/templates/app/server/api/user(auth)/user.model(mongooseModels).js @@ -38,11 +38,17 @@ var UserSchema = new Schema({ }<% } else { %>true<% } %> }, provider: String, - salt: String<% if(filters.oauth) { %>,<% if(filters.facebookAuth) { %> - facebook: {},<% } %><% if(filters.twitterAuth) { %> - twitter: {},<% } %><% if(filters.googleAuth) { %> + salt: String, +<%_ if(filters.oauth) { -%> + <%_ if(filters.facebookAuth) { -%> + facebook: {},<% } %> + <%_ if(filters.twitterAuth) { -%> + twitter: {},<% } %> + <%_ if(filters.googleAuth) { -%> google: {},<% } %> - github: {}<% } %> + <%_ if(filters.githubAuth) { -%> + github: {}, +<% } %> }); /** diff --git a/templates/app/server/api/user(auth)/user.model(sequelizeModels).js b/templates/app/server/api/user(auth)/user.model(sequelizeModels).js index 58e8f5ae2..721f80442 100644 --- a/templates/app/server/api/user(auth)/user.model(sequelizeModels).js +++ b/templates/app/server/api/user(auth)/user.model(sequelizeModels).js @@ -1,7 +1,7 @@ 'use strict'; import crypto from 'crypto';<% if(filters.oauth) { %> -var authTypes = ['github', 'twitter', 'facebook', 'google'];<% } %> +const authTypes = ['github', 'twitter', 'facebook', 'google'];<% } %> var validatePresenceOf = function(value) { return value && value.length; @@ -37,11 +37,17 @@ export default function(sequelize, DataTypes) { } }, provider: DataTypes.STRING, - salt: DataTypes.STRING<% if(filters.oauth) { %>,<% if(filters.facebookAuth) { %> - facebook: DataTypes.JSON,<% } %><% if(filters.twitterAuth) { %> - twitter: DataTypes.JSON,<% } %><% if(filters.googleAuth) { %> + salt: DataTypes.STRING, + <% if(filters.oauth) { %> + <%_ if(filters.facebookAuth) { -%> + facebook: DataTypes.JSON,<% } %> + <%_ if(filters.twitterAuth) { -%> + twitter: DataTypes.JSON,<% } %> + <%_ if(filters.githubAuth) { -%> + github: DataTypes.JSON,<% } %> + <%_ if(filters.googleAuth) { -%> google: DataTypes.JSON,<% } %> - github: DataTypes.JSON<% } %> + <% } %> }, { diff --git a/templates/app/server/api/user(auth)/user.model.spec(mongooseModels).js b/templates/app/server/api/user(auth)/user.model.spec(mongooseModels).js index 5fe8de3c5..aaaa766b0 100644 --- a/templates/app/server/api/user(auth)/user.model.spec(mongooseModels).js +++ b/templates/app/server/api/user(auth)/user.model.spec(mongooseModels).js @@ -54,7 +54,20 @@ describe('User Model', function() { it('should fail when saving without an email', function() { user.email = undefined; return <%= expect() %>user.save()<%= to() %>.be.rejected; - });<% if (filters.oauth && filters.googleAuth) { %> + }); + <%_ if(filters.githubAuth) { -%> + + describe('given user provider is github', function() { + beforeEach(function() { + user.provider = 'github'; + }); + + it('should succeed when saving without an email', function() { + user.email = null; + return <%= expect() %>user.save()<%= to() %>.be.fulfilled; + }); + });<% } %> + <%_ if(filters.oauth && filters.googleAuth) { -%> describe('given user provider is google', function() { beforeEach(function() { @@ -65,7 +78,7 @@ describe('User Model', function() { user.email = null; return <%= expect() %>user.save()<%= to() %>.be.fulfilled; }); - });<% } %><% if (filters.oauth && filters.facebookAuth) { %> + });<% } %><% if(filters.oauth && filters.facebookAuth) { %> describe('given user provider is facebook', function() { beforeEach(function() { @@ -76,7 +89,7 @@ describe('User Model', function() { user.email = null; return <%= expect() %>user.save()<%= to() %>.be.fulfilled; }); - });<% } %><% if (filters.oauth && filters.twitterAuth) { %> + });<% } %><% if(filters.oauth && filters.twitterAuth) { %> describe('given user provider is twitter', function() { beforeEach(function() { @@ -87,7 +100,7 @@ describe('User Model', function() { user.email = null; return <%= expect() %>user.save()<%= to() %>.be.fulfilled; }); - });<% } %><% if (filters.oauth) { %> + });<% } %><% if(filters.oauth) { %> describe('given user provider is github', function() { beforeEach(function() { @@ -137,7 +150,20 @@ describe('User Model', function() { return u.authenticate('password'); })<%= to() %>.eventually.be.true; }); - });<% if (filters.oauth && filters.googleAuth) { %> + }); + <%_ if(filters.oauth && filters.githubAuth) { -%> + + describe('given user provider is github', function() { + beforeEach(function() { + user.provider = 'github'; + }); + + it('should succeed when saving without a password', function() { + user.password = null; + return <%= expect() %>user.save()<%= to() %>.be.fulfilled; + }); + });<% } %> + <%_ if(filters.oauth && filters.googleAuth) { -%> describe('given user provider is google', function() { beforeEach(function() { @@ -148,7 +174,7 @@ describe('User Model', function() { user.password = null; return <%= expect() %>user.save()<%= to() %>.be.fulfilled; }); - });<% } %><% if (filters.oauth && filters.facebookAuth) { %> + });<% } %><% if(filters.oauth && filters.facebookAuth) { %> describe('given user provider is facebook', function() { beforeEach(function() { @@ -159,7 +185,7 @@ describe('User Model', function() { user.password = null; return <%= expect() %>user.save()<%= to() %>.be.fulfilled; }); - });<% } %><% if (filters.oauth && filters.twitterAuth) { %> + });<% } %><% if(filters.oauth && filters.twitterAuth) { %> describe('given user provider is twitter', function() { beforeEach(function() { @@ -170,7 +196,7 @@ describe('User Model', function() { user.password = null; return <%= expect() %>user.save()<%= to() %>.be.fulfilled; }); - });<% } %><% if (filters.oauth) { %> + });<% } %><% if(filters.oauth) { %> describe('given user provider is github', function() { beforeEach(function() { diff --git a/templates/app/server/auth(auth)/github(githubAuth)/index.js b/templates/app/server/auth(auth)/github(githubAuth)/index.js new file mode 100644 index 000000000..85b4c4b87 --- /dev/null +++ b/templates/app/server/auth(auth)/github(githubAuth)/index.js @@ -0,0 +1,20 @@ +import { Router } from 'express'; +import passport from 'passport'; +import { setTokenCookie } from '../auth.service'; + +let router = new Router(); + +router + .get('/', passport.authenticate('github', { + failureRedirect: '/signup', + scope: [ + 'user:email', + ], + session: false + })) + .get('/callback', passport.authenticate('github', { + failureRedirect: '/signup', + session: false + }), setTokenCookie); + +export default router; diff --git a/templates/app/server/auth(auth)/github(githubAuth)/passport.js b/templates/app/server/auth(auth)/github(githubAuth)/passport.js new file mode 100644 index 000000000..3ea90f66f --- /dev/null +++ b/templates/app/server/auth(auth)/github(githubAuth)/passport.js @@ -0,0 +1,38 @@ +import passport from 'passport'; +import { Strategy as GitHubStrategy } from 'passport-github'; + +export function setup(User, config) { + passport.use(new GitHubStrategy({ + clientID: config.gitHub.clientID, + clientSecret: config.gitHub.clientSecret, + callbackURL: config.gitHub.callbackURL, + passReqToCallback: true + }, + function(accessToken, refreshToken, profile, done) { + <%_ if(filters.mongooseModels) { -%> + User.findOne({'github.id': profile.id}).exec()<% } %> + <%_ if(filters.sequelizeModels) { -%> + User.find({where:{'github.id': profile.id}})<% } %> + .then(user => { + if(user) { + return done(null, user); + } + + <%_ if(filters.mongooseModels) { -%> + user = new User({<% } %> + <%_ if(filters.sequelizeModels) { -%> + user = User.build({<% } %> + name: profile.displayName, + email: profile.emails[0].value, + role: 'user', + provider: 'github', + github: profile._json + }); + + return user.save() + .then(savedUser => done(null, savedUser)) + .catch(err => done(err)); + }) + .catch(err => done(err)); + })); +} diff --git a/templates/app/server/auth(auth)/index.js b/templates/app/server/auth(auth)/index.js index 3f9983fb3..658d6ca77 100644 --- a/templates/app/server/auth(auth)/index.js +++ b/templates/app/server/auth(auth)/index.js @@ -9,12 +9,16 @@ require('./local/passport').setup(User, config);<% if (filters.facebookAuth) { % require('./facebook/passport').setup(User, config);<% } %><% if (filters.googleAuth) { %> require('./google/passport').setup(User, config);<% } %><% if (filters.twitterAuth) { %> require('./twitter/passport').setup(User, config);<% } %> +<%_ if (filters.githubAuth) { -%> +require('./github/passport').setup(User, config);<% } %> var router = express.Router(); router.use('/local', require('./local').default);<% if (filters.facebookAuth) { %> -router.use('/facebook', require('./facebook').default);<% } %><% if (filters.twitterAuth) { %> -router.use('/twitter', require('./twitter').default);<% } %><% if (filters.googleAuth) { %> -router.use('/google', require('./google').default);<% } %> +router.use('/facebook', require('./facebook').default);<% } %><% if (filters.googleAuth) { %> +router.use('/google', require('./google').default);<% } %><% if (filters.twitterAuth) { %> +router.use('/twitter', require('./twitter').default);<% } %> +<%_ if (filters.githubAuth) { -%> +router.use('/github', require('./github').default);<% } %> export default router; diff --git a/templates/app/server/config/_local.env.js b/templates/app/server/config/_local.env.js index 02a5a084b..0084964b0 100644 --- a/templates/app/server/config/_local.env.js +++ b/templates/app/server/config/_local.env.js @@ -1,23 +1,28 @@ -'use strict'; - // Use local.env.js for environment variables that will be set when the server starts locally. // Use for your api keys, secrets, etc. This file should not be tracked by git. // // You will need to set these on the server you deploy to. module.exports = { - DOMAIN: 'http://localhost:<%= devPort %>', - SESSION_SECRET: '<%= lodash.slugify(appname) + "-secret" %>',<% if (filters.facebookAuth) { %> + DOMAIN: 'http://localhost:<%= devPort %>', + SESSION_SECRET: '<%= lodash.slugify(appname) + "-secret" %>', + <%_ if (filters.facebookAuth) { -%> + + FACEBOOK_ID: 'app-id', + FACEBOOK_SECRET: 'secret',<% } %> + <%_ if (filters.twitterAuth) { -%> + + TWITTER_ID: 'app-id', + TWITTER_SECRET: 'secret',<% } %> + <%_ if (filters.githubAuth) { -%> - FACEBOOK_ID: 'app-id', - FACEBOOK_SECRET: 'secret',<% } if (filters.twitterAuth) { %> + GITHUB_ID: 'app-id', + GITHUB_SECRET: 'secret',<% } %> + <%_ if (filters.googleAuth) { -%> - TWITTER_ID: 'app-id', - TWITTER_SECRET: 'secret',<% } if (filters.googleAuth) { %> + GOOGLE_ID: 'app-id', + GOOGLE_SECRET: 'secret',<% } %> - GOOGLE_ID: 'app-id', - GOOGLE_SECRET: 'secret', -<% } %> // Control debug level for modules using visionmedia/debug DEBUG: '' }; diff --git a/templates/app/server/config/_local.env.sample.js b/templates/app/server/config/_local.env.sample.js index 79dce5854..0084964b0 100644 --- a/templates/app/server/config/_local.env.sample.js +++ b/templates/app/server/config/_local.env.sample.js @@ -1,5 +1,3 @@ -'use strict'; - // Use local.env.js for environment variables that will be set when the server starts locally. // Use for your api keys, secrets, etc. This file should not be tracked by git. // @@ -7,13 +5,20 @@ module.exports = { DOMAIN: 'http://localhost:<%= devPort %>', - SESSION_SECRET: '<%= lodash.slugify(appname) + "-secret" %>',<% if (filters.facebookAuth) { %> + SESSION_SECRET: '<%= lodash.slugify(appname) + "-secret" %>', + <%_ if (filters.facebookAuth) { -%> FACEBOOK_ID: 'app-id', - FACEBOOK_SECRET: 'secret',<% } if (filters.twitterAuth) { %> + FACEBOOK_SECRET: 'secret',<% } %> + <%_ if (filters.twitterAuth) { -%> TWITTER_ID: 'app-id', - TWITTER_SECRET: 'secret',<% } if (filters.googleAuth) { %> + TWITTER_SECRET: 'secret',<% } %> + <%_ if (filters.githubAuth) { -%> + + GITHUB_ID: 'app-id', + GITHUB_SECRET: 'secret',<% } %> + <%_ if (filters.googleAuth) { -%> GOOGLE_ID: 'app-id', GOOGLE_SECRET: 'secret',<% } %> diff --git a/templates/app/server/config/environment/index.js b/templates/app/server/config/environment/index.js index b82e4ae4f..49ece374e 100644 --- a/templates/app/server/config/environment/index.js +++ b/templates/app/server/config/environment/index.js @@ -43,25 +43,35 @@ var all = { safe: true } } - }<% if(filters.facebookAuth) { %>, + }, + <%_ if(filters.facebookAuth) { -%> facebook: { clientID: process.env.FACEBOOK_ID || 'id', clientSecret: process.env.FACEBOOK_SECRET || 'secret', callbackURL: `${process.env.DOMAIN || ''}/auth/facebook/callback` - }<% } %><% if(filters.twitterAuth) { %>, + },<% } %> + <%_ if(filters.twitterAuth) { -%> twitter: { - clientID: process.env.TWITTER_ID || 'id', + clientID: process.env.TWITTER_ID || 'id' clientSecret: process.env.TWITTER_SECRET || 'secret', callbackURL: `${process.env.DOMAIN || ''}/auth/twitter/callback` - }<% } %><% if(filters.googleAuth) { %>, + },<% } %> + <%_ if(filters.githubAuth) { -%> + + github: { + clientID: process.env.GITHUB_ID || 'id', + clientSecret: process.env.GITHUB_SECRET || 'secret', + callbackURL: `${process.env.DOMAIN || ''}/auth/github/callback` + },<% } %> + <%_ if(filters.googleAuth) { -%> google: { clientID: process.env.GOOGLE_ID || 'id', clientSecret: process.env.GOOGLE_SECRET || 'secret', callbackURL: `${process.env.DOMAIN || ''}/auth/google/callback` - }<% } %> + },<% } %> }; // Export the config object based on the NODE_ENV