diff --git a/Gemfile b/Gemfile index 38c955195..f49be1f49 100644 --- a/Gemfile +++ b/Gemfile @@ -35,6 +35,7 @@ gem "omniauth-openid" gem "openid-redis-store" gem "omniauth-facebook" gem "omniauth-twitter" +gem "omniauth-github" gem 'oj' gem 'pbkdf2' gem 'pg' diff --git a/Gemfile.lock b/Gemfile.lock index 78575bdcb..67dbdcf14 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -279,6 +279,9 @@ GEM rack omniauth-facebook (1.4.1) omniauth-oauth2 (~> 1.1.0) + omniauth-github (1.1.0) + omniauth (~> 1.0) + omniauth-oauth2 (~> 1.1) omniauth-oauth (1.0.1) oauth omniauth (~> 1.0) @@ -489,6 +492,7 @@ DEPENDENCIES oj omniauth omniauth-facebook + omniauth-github omniauth-openid omniauth-twitter openid-redis-store diff --git a/app/assets/javascripts/discourse/templates/modal/login.js.handlebars b/app/assets/javascripts/discourse/templates/modal/login.js.handlebars index b605373bd..2c0d7cff0 100644 --- a/app/assets/javascripts/discourse/templates/modal/login.js.handlebars +++ b/app/assets/javascripts/discourse/templates/modal/login.js.handlebars @@ -5,6 +5,9 @@
+ {{#if Discourse.SiteSettings.enable_github_logins}} + + {{/if}}

{{i18n login.or}} diff --git a/app/assets/javascripts/discourse/views/modal/login_view.js b/app/assets/javascripts/discourse/views/modal/login_view.js index da08b0196..f11712ab3 100644 --- a/app/assets/javascripts/discourse/views/modal/login_view.js +++ b/app/assets/javascripts/discourse/views/modal/login_view.js @@ -101,6 +101,14 @@ Discourse.LoginView = Discourse.ModalBodyView.extend({ } }, + githubLogin: function() { + var left, top; + this.set('authenticate', 'github'); + left = this.get('lastX') - 400; + top = this.get('lastY') - 200; + return window.open("/auth/github", "_blank", "menubar=no,status=no,height=400,width=800,left=" + left + ",top=" + top); + }, + authenticationComplete: function(options) { if (options.awaiting_approval) { this.flash(Em.String.i18n('login.awaiting_approval'), 'success'); diff --git a/app/assets/stylesheets/components/buttons.css.scss b/app/assets/stylesheets/components/buttons.css.scss index 80e8756ba..74fdda739 100755 --- a/app/assets/stylesheets/components/buttons.css.scss +++ b/app/assets/stylesheets/components/buttons.css.scss @@ -162,6 +162,12 @@ content: "Y"; } } + &.github { + background: $github; + &:before { + content: "g"; + } + } } // Button Sizes diff --git a/app/assets/stylesheets/foundation/variables.scss b/app/assets/stylesheets/foundation/variables.scss index 39eea5716..4407937c8 100644 --- a/app/assets/stylesheets/foundation/variables.scss +++ b/app/assets/stylesheets/foundation/variables.scss @@ -123,6 +123,7 @@ $google: #5b76f7 !default; $facebook: #3b5998 !default; $twitter: #00bced !default; $yahoo: #810293 !default; +$github: #6d6d6d !default; // Layout dimensions diff --git a/app/controllers/users/omniauth_callbacks_controller.rb b/app/controllers/users/omniauth_callbacks_controller.rb index a719a14ae..f876fcdde 100644 --- a/app/controllers/users/omniauth_callbacks_controller.rb +++ b/app/controllers/users/omniauth_callbacks_controller.rb @@ -19,6 +19,8 @@ class Users::OmniauthCallbacksController < ApplicationController create_or_sign_on_user_using_twitter(auth_token) when "google", "yahoo" create_or_sign_on_user_using_openid(auth_token) + when "github" + create_or_sign_on_user_using_github(auth_token) end end @@ -169,4 +171,35 @@ class Users::OmniauthCallbacksController < ApplicationController end end + def create_or_sign_on_user_using_github(auth_token) + + data = auth_token[:info] + screen_name = data["nickname"] + github_user_id = auth_token["uid"] + + session[:authentication] = { + github_user_id: github_user_id, + github_screen_name: screen_name + } + + user_info = GithubUserInfo.where(:github_user_id => github_user_id).first + + @data = { + username: screen_name, + auth_provider: "Github" + } + + if user_info + if user_info.user.active + log_on_user(user_info.user) + @data[:authenticated] = true + else + @data[:awaiting_activation] = true + # send another email ? + end + else + @data[:name] = screen_name + end + end + end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 42fdf3cc7..dc5156d85 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -177,6 +177,10 @@ class UsersController < ApplicationController if auth[:facebook].present? and FacebookUserInfo.find_by_facebook_user_id(auth[:facebook][:facebook_user_id]).nil? FacebookUserInfo.create!(auth[:facebook].merge(user_id: user.id)) end + + if auth[:github_user_id] && auth[:github_screen_name] && GithubUserInfo.find_by_github_user_id(auth[:github_user_id]).nil? + GithubUserInfo.create(:user_id => user.id, :screen_name => auth[:github_screen_name], :github_user_id => auth[:github_user_id]) + end end diff --git a/app/models/github_user_info.rb b/app/models/github_user_info.rb new file mode 100644 index 000000000..7f2b4c56d --- /dev/null +++ b/app/models/github_user_info.rb @@ -0,0 +1,3 @@ +class GithubUserInfo < ActiveRecord::Base + belongs_to :user +end \ No newline at end of file diff --git a/app/models/site_setting.rb b/app/models/site_setting.rb index e5be8ac52..ec7679792 100644 --- a/app/models/site_setting.rb +++ b/app/models/site_setting.rb @@ -116,6 +116,10 @@ class SiteSetting < ActiveRecord::Base setting(:facebook_app_id, '') setting(:facebook_app_secret, '') + client_setting(:enable_github_logins, false) + setting(:github_client_id, '') + setting(:github_client_secret, '') + setting(:enforce_global_nicknames, true) setting(:discourse_org_access_key, '') setting(:enable_s3_uploads, false) diff --git a/app/models/user.rb b/app/models/user.rb index 564aa480f..8e6b377f5 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -21,6 +21,7 @@ class User < ActiveRecord::Base has_many :user_visits has_many :invites has_one :twitter_user_info + has_one :github_user_info belongs_to :approved_by, class_name: 'User' validates_presence_of :username diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb index 41e4c8d4d..838006e8a 100644 --- a/config/initializers/omniauth.rb +++ b/config/initializers/omniauth.rb @@ -27,4 +27,8 @@ Rails.application.config.middleware.use OmniAuth::Builder do SiteSetting.twitter_consumer_key, SiteSetting.twitter_consumer_secret + provider :github, + SiteSetting.github_client_id, + SiteSetting.github_client_secret + end diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 241ca3d7e..d0f8bb480 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -248,6 +248,9 @@ en: yahoo: title: "Log In with Yahoo" message: "Authenticating with Yahoo (make sure pop up blockers are not enabled)" + github: + title: "Log In with Github" + message: "Authenticating with Github (make sure pop up blockers are not enabled)" composer: saving_draft_tip: "saving" diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index fa4188200..4aa5add1d 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -314,6 +314,9 @@ en: facebook_app_secret: "App secret for Facebook authentication, registered at https://developers.facebook.com/apps" allow_import: "Allow import, which can replace ALL site data; leave false unless you plan to do data imports" + enable_github_logins: "Enable Github authentication, requires github_client_id and github_client_secret" + github_client_id: "Client id for Github authentication, registered at https://github.com/settings/applications" + github_client_secret: "Client secret for Github authentication, registered at https://github.com/settings/applications" active_user_rate_limit_secs: "How frequently we update the 'last_seen_at' field, in seconds" previous_visit_timeout_hours: "How long a visit lasts before we consider it the 'previous' visit, in hours" diff --git a/db/migrate/20130226015336_add_github_user_info.rb b/db/migrate/20130226015336_add_github_user_info.rb new file mode 100644 index 000000000..4887aa374 --- /dev/null +++ b/db/migrate/20130226015336_add_github_user_info.rb @@ -0,0 +1,13 @@ +class AddGithubUserInfo < ActiveRecord::Migration + def change + create_table :github_user_infos do |t| + t.integer :user_id, :null => false + t.string :screen_name, :null => false + t.integer :github_user_id, :null => false + t.timestamps + end + + add_index :github_user_infos, [:github_user_id], :unique => true + add_index :github_user_infos, [:user_id], :unique => true + end +end \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 39b4cd846..5951ff98a 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -1239,7 +1239,7 @@ CREATE TABLE categories ( -- CREATE SEQUENCE categories_id_seq - START WITH 5 + START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE @@ -1324,7 +1324,7 @@ CREATE TABLE draft_sequences ( -- CREATE SEQUENCE draft_sequences_id_seq - START WITH 20 + START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE @@ -1358,7 +1358,7 @@ CREATE TABLE drafts ( -- CREATE SEQUENCE drafts_id_seq - START WITH 2 + START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE @@ -1391,7 +1391,7 @@ CREATE TABLE email_logs ( -- CREATE SEQUENCE email_logs_id_seq - START WITH 3 + START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE @@ -1426,7 +1426,7 @@ CREATE TABLE email_tokens ( -- CREATE SEQUENCE email_tokens_id_seq - START WITH 3 + START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE @@ -1479,6 +1479,39 @@ CREATE SEQUENCE facebook_user_infos_id_seq ALTER SEQUENCE facebook_user_infos_id_seq OWNED BY facebook_user_infos.id; +-- +-- Name: github_user_infos; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- + +CREATE TABLE github_user_infos ( + id integer NOT NULL, + user_id integer NOT NULL, + screen_name character varying(255) NOT NULL, + github_user_id integer NOT NULL, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: github_user_infos_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE github_user_infos_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: github_user_infos_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE github_user_infos_id_seq OWNED BY github_user_infos.id; + + -- -- Name: incoming_links; Type: TABLE; Schema: public; Owner: -; Tablespace: -- @@ -1639,7 +1672,7 @@ CREATE TABLE onebox_renders ( -- CREATE SEQUENCE onebox_renders_id_seq - START WITH 2 + START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE @@ -1673,7 +1706,7 @@ CREATE TABLE post_action_types ( -- CREATE SEQUENCE post_action_types_id_seq - START WITH 6 + START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE @@ -1804,7 +1837,7 @@ CREATE TABLE posts ( -- CREATE SEQUENCE posts_id_seq - START WITH 16 + START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE @@ -1895,7 +1928,7 @@ CREATE TABLE site_settings ( -- CREATE SEQUENCE site_settings_id_seq - START WITH 4 + START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE @@ -1927,7 +1960,7 @@ CREATE TABLE topic_allowed_users ( -- CREATE SEQUENCE topic_allowed_users_id_seq - START WITH 3 + START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE @@ -2119,7 +2152,7 @@ CREATE TABLE topics ( -- CREATE SEQUENCE topics_id_seq - START WITH 16 + START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE @@ -2225,7 +2258,7 @@ CREATE TABLE user_actions ( -- CREATE SEQUENCE user_actions_id_seq - START WITH 40 + START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE @@ -2289,7 +2322,7 @@ CREATE TABLE user_visits ( -- CREATE SEQUENCE user_visits_id_seq - START WITH 4 + START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE @@ -2356,7 +2389,7 @@ CREATE TABLE users ( -- CREATE SEQUENCE users_id_seq - START WITH 3 + START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE @@ -2688,6 +2721,13 @@ ALTER TABLE ONLY email_tokens ALTER COLUMN id SET DEFAULT nextval('email_tokens_ ALTER TABLE ONLY facebook_user_infos ALTER COLUMN id SET DEFAULT nextval('facebook_user_infos_id_seq'::regclass); +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY github_user_infos ALTER COLUMN id SET DEFAULT nextval('github_user_infos_id_seq'::regclass); + + -- -- Name: id; Type: DEFAULT; Schema: public; Owner: - -- @@ -3174,6 +3214,14 @@ ALTER TABLE ONLY topics ADD CONSTRAINT forum_threads_pkey PRIMARY KEY (id); +-- +-- Name: github_user_infos_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- + +ALTER TABLE ONLY github_user_infos + ADD CONSTRAINT github_user_infos_pkey PRIMARY KEY (id); + + -- -- Name: incoming_links_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- @@ -3926,6 +3974,20 @@ CREATE UNIQUE INDEX index_forum_thread_users_on_forum_thread_id_and_user_id ON t CREATE INDEX index_forum_threads_on_bumped_at ON topics USING btree (bumped_at DESC); +-- +-- Name: index_github_user_infos_on_github_user_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE UNIQUE INDEX index_github_user_infos_on_github_user_id ON github_user_infos USING btree (github_user_id); + + +-- +-- Name: index_github_user_infos_on_user_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE UNIQUE INDEX index_github_user_infos_on_user_id ON github_user_infos USING btree (user_id); + + -- -- Name: index_invites_on_email_and_invited_by_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- @@ -4577,4 +4639,6 @@ INSERT INTO schema_migrations (version) VALUES ('20130213021450'); INSERT INTO schema_migrations (version) VALUES ('20130213203300'); -INSERT INTO schema_migrations (version) VALUES ('20130221215017'); \ No newline at end of file +INSERT INTO schema_migrations (version) VALUES ('20130221215017'); + +INSERT INTO schema_migrations (version) VALUES ('20130226015336'); \ No newline at end of file diff --git a/docs/SOFTWARE.md b/docs/SOFTWARE.md index 917883a1d..a13d104eb 100644 --- a/docs/SOFTWARE.md +++ b/docs/SOFTWARE.md @@ -27,6 +27,7 @@ The following Ruby Gems are used in Discourse: * [omniauth-openid](https://github.com/intridea/omniauth-openid) * [omniauth-facebook](https://github.com/mkdynamic/omniauth-facebook) * [omniauth-twitter](https://github.com/arunagw/omniauth-twitter) +* [omniauth-github](https://github.com/intridea/omniauth-github) * [has_ip_address](https://rubygems.org/gems/has_ip_address) * [vestal_versions](https://rubygems.org/gems/vestal_versions) * [uglifier](https://rubygems.org/gems/uglifier) diff --git a/spec/views/omniauth_callbacks/complete.html.erb_spec.rb b/spec/views/omniauth_callbacks/complete.html.erb_spec.rb index 6c8d48b5a..098e79bc7 100644 --- a/spec/views/omniauth_callbacks/complete.html.erb_spec.rb +++ b/spec/views/omniauth_callbacks/complete.html.erb_spec.rb @@ -38,6 +38,18 @@ describe "users/omniauth_callbacks/complete.html.erb" do rendered_data["awaiting_activation"].should eq(true) end + it "renders github data " do + assign(:data, {:username =>"username", :auth_provider=>"Github", :awaiting_activation=>true}) + + render + + rendered_data = JSON.parse(rendered.match(/window.opener.Discourse.authenticationComplete\((.*)\)/)[1]) + + rendered_data["username"].should eq("username") + rendered_data["auth_provider"].should eq("Github") + rendered_data["awaiting_activation"].should eq(true) + end + end