Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add user signup with GitHub OAuth #125

Merged
merged 11 commits into from
Apr 4, 2024
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@
!/tmp/pids/
!/tmp/pids/.keep

# Ignore local envs
.env.local
.env.production.local
.env.development.local
.env.test.local

/public/assets
.byebug_history
Expand Down
4 changes: 4 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ gem 'stimulus-rails', '~> 1.3'
gem 'tailwindcss-rails', '~> 2.0'
gem 'turbo-rails', '~> 2.0'

gem 'omniauth-github', '~> 2.0'
gem 'omniauth-rails_csrf_protection', '~> 1.0'

gem 'imgkit'
install_if -> { RUBY_PLATFORM =~ /darwin/ } do
gem 'wkhtmltoimage-binary'
Expand All @@ -32,6 +35,7 @@ end
group :development, :test do
# Call 'byebug' anywhere in the code to stop execution and get a debugger console
gem 'byebug', platforms: %i[mri mingw x64_mingw]
gem 'dotenv', '~> 3.1'
gem 'rubocop', '~> 1.18'
end

Expand Down
42 changes: 42 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -96,13 +96,19 @@ GEM
connection_pool (2.4.1)
crass (1.0.6)
date (3.3.4)
dotenv (3.1.0)
drb (2.2.1)
erb-formatter (0.4.3)
syntax_tree (~> 6.0)
erubi (1.12.0)
faraday (2.9.0)
faraday-net_http (>= 2.0, < 3.2)
faraday-net_http (3.1.0)
net-http
ffi (1.15.5)
globalid (1.2.1)
activesupport (>= 6.1)
hashie (5.0.0)
i18n (1.12.0)
concurrent-ruby (~> 1.0)
imgkit (1.6.2)
Expand All @@ -113,6 +119,8 @@ GEM
jsbundling-rails (1.2.1)
railties (>= 6.0.0)
json (2.6.3)
jwt (2.8.1)
base64
listen (3.8.0)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
Expand All @@ -129,7 +137,10 @@ GEM
mini_mime (1.1.5)
mini_portile2 (2.8.1)
minitest (5.17.0)
multi_xml (0.6.0)
mutex_m (0.2.0)
net-http (0.4.1)
uri
net-imap (0.4.10)
date
net-protocol
Expand All @@ -143,6 +154,26 @@ GEM
nokogiri (1.14.2)
mini_portile2 (~> 2.8.0)
racc (~> 1.4)
oauth2 (2.0.9)
faraday (>= 0.17.3, < 3.0)
jwt (>= 1.0, < 3.0)
multi_xml (~> 0.5)
rack (>= 1.2, < 4)
snaky_hash (~> 2.0)
version_gem (~> 1.1)
omniauth (2.1.2)
hashie (>= 3.4.6)
rack (>= 2.2.3)
rack-protection
omniauth-github (2.0.1)
omniauth (~> 2.0)
omniauth-oauth2 (~> 1.8)
omniauth-oauth2 (1.8.0)
oauth2 (>= 1.4, < 3)
omniauth (~> 2.0)
omniauth-rails_csrf_protection (1.0.1)
actionpack (>= 4.2)
omniauth (~> 2.0)
parallel (1.22.1)
parser (3.2.1.0)
ast (~> 2.4.1)
Expand All @@ -162,6 +193,9 @@ GEM
rack (2.2.8.1)
rack-contrib (2.3.0)
rack (~> 2.0)
rack-protection (3.2.0)
base64 (>= 0.1.0)
rack (~> 2.2, >= 2.2.4)
rack-session (1.0.2)
rack (< 3)
rack-test (2.1.0)
Expand Down Expand Up @@ -231,6 +265,9 @@ GEM
rexml (~> 3.2, >= 3.2.5)
rubyzip (>= 1.2.2, < 3.0)
websocket (~> 1.0)
snaky_hash (2.0.1)
hashie
version_gem (~> 1.1, >= 1.1.1)
stimulus-rails (1.3.3)
railties (>= 6.0.0)
stringio (3.1.0)
Expand All @@ -253,6 +290,8 @@ GEM
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
unicode-display_width (2.4.2)
uri (0.13.0)
version_gem (1.1.4)
webrick (1.8.1)
websocket (1.2.10)
websocket-driver (0.7.6)
Expand All @@ -273,10 +312,13 @@ DEPENDENCIES
bcrypt (~> 3.1.16)
byebug
capybara
dotenv (~> 3.1)
erb-formatter (~> 0.4.3)
imgkit
jsbundling-rails (~> 1.2)
listen (~> 3.3)
omniauth-github (~> 2.0)
omniauth-rails_csrf_protection (~> 1.0)
pg (~> 1.1)
propshaft
puma (~> 5.0)
Expand Down
33 changes: 21 additions & 12 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ class ApplicationController < ActionController::Base
before_action :set_user
before_action :set_plan
before_action :set_locale
before_action :set_last_path

around_action :with_time_zone

Expand All @@ -12,29 +13,25 @@ class ApplicationController < ActionController::Base
rescue_from ActionController::RoutingError, with: :not_found

def set_user
if session[:user_id]
@user = User.find(session[:user_id])
else
create_and_set_user
end
rescue ActiveRecord::RecordNotFound
create_and_set_user
@user = User.find(session[:user_id]) if session[:user_id]
end

def set_plan
@plan = @user.plans.where(event: @event).recent&.first ||
@user.plans.build(title: "My RubyKaigi #{@event.name} set list",
description: "Enjoy my RubyKaigi #{@event.name} set list",
public: true,
event: @event)
@plan = (@user && @user.plans.where(event: @event).recent&.first) ||
Plan.new(title: "My RubyKaigi #{@event.name} set list",
description: "Enjoy my RubyKaigi #{@event.name} set list",
public: true,
event: @event)
end

def not_found(err)
print_error_if_test(err)
Rails.logger.debug("#{err}\n#{err.backtrace.join("\n")}")
render template: 'errors/not_found', status: 404, layout: 'application', content_type: 'text/html'
end

def server_error(err)
print_error_if_test(err)
Rails.logger.error("#{err}\n#{err.backtrace.join("\n")}")
render template: 'errors/server_error', status: 500, layout: 'application', content_type: 'text/html'
end
Expand All @@ -60,11 +57,23 @@ def set_locale
session[:locale] = locale
end

def set_last_path
session[:last_path] = request.path
end

def with_time_zone(&)
if session[:locale]
Time.use_zone(session[:locale], &)
else
yield
end
end

def print_error_if_test(err)
return unless Rails.env.test?

pp params
puts err.message
puts err.backtrace.join("\n")
end
end
1 change: 1 addition & 0 deletions app/controllers/plans_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ def editable
end

def create
create_and_set_user unless @user
@plan = @user.plans.where(event: @event).create!(plan_params)
add_and_remove_plans if plan_add_or_remove?
redirect_to event_schedules_path(event_name: @plan.event.name)
Expand Down
7 changes: 7 additions & 0 deletions app/controllers/profiles_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# frozen_string_literal: true

class ProfilesController < ApplicationController
include EventRouting

def show; end
end
33 changes: 33 additions & 0 deletions app/controllers/sessions_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# frozen_string_literal: true

class SessionsController < ApplicationController
skip_before_action :set_plan
skip_before_action :set_locale
skip_before_action :set_last_path

def create
user_info = request.env['omniauth.auth']
profile = Profile.find_by(uid: user_info['uid'])

if profile
session[:user_id] = profile.user.id
else
create_and_set_user unless @user
@user.create_profile(
provider: user_info['provider'],
uid: user_info['uid'],
name: user_info['info']['name'],
email: user_info['info']['email'],
avatar_url: user_info['info']['image']
)
end

redirect_to session[:last_path] || root_path
end

def delete
session[:user_id] = nil

redirect_to root_path
end
end
4 changes: 4 additions & 0 deletions app/helpers/profiles_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# frozen_string_literal: true

module ProfilesHelper
end
4 changes: 4 additions & 0 deletions app/helpers/sessions_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# frozen_string_literal: true

module SessionsHelper
end
11 changes: 11 additions & 0 deletions app/models/profile.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# frozen_string_literal: true

class Profile < ApplicationRecord
belongs_to :user

validates :provider, presence: true
validates :uid, presence: true
validates :name, presence: true
validates :email, presence: true
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

emailとnameはGithub側で空欄で登録できるので、必須にしないほうが親切かも?と思いました!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

emailは以下をチェックしていてもnilになるみたいです!
スクリーンショット 2024-04-04 20 00 49

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

必須にする場合は、profile作成失敗時に適切にエラーメッセージを表示してあげると良さそうです!

Copy link
Collaborator

@e-ikuta e-ikuta Apr 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ちなみにアバター画像については、頑張って外そうと試みたのですが、gravatarの画像が勝手に設定されちゃってできませんでした...
docによると

アカウントにサインアップすると、GitHub はとりあえずランダムなアイデンティコンを生成します。

とあるので空になることはないのかもしれません。

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

emailはもしかしたら、と思っていたんですがnameは想定外だったので、チェックしていただいて助かりました。
ちょっと修正を入れます

validates :avatar_url, presence: true
end
1 change: 1 addition & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# frozen_string_literal: true

class User < ApplicationRecord
has_one :profile
has_many :plans
end
18 changes: 16 additions & 2 deletions app/views/layouts/_header.html.erb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<nav>
<div class="flex items-center direction-row h-[50px] bg-[var(--mainColor)]">
<div class="flex flex-row items-center mx-4 my-0 text-white">
<div class="flex items-center justify-end direction-row h-[50px] bg-[var(--mainColor)]">
<div class="flex flex-row flex-grow items-center mx-4 my-0 text-white">
<% unless Rails.env.test? %>
<img class="h-6" src="<%= asset_path("#{@event.name}/rubykaigi_logo.svg") %>">
<% end %>
Expand All @@ -20,6 +20,11 @@
</div>
</div>
</div>
<div class="flex items-center">
<% if @user&.profile %>
<img src="<%= @user.profile.avatar_url %>" class="rounded-full h-8 w-8 mr-4" >
<% end %>
</div>
</div>

<div data-controller="navigation" class="flex items-center min-w-max bg-white pr-6 pl-6 shadow-[rgba(3,3,2,0.3)_0_1px_2px_0] px-6">
Expand Down Expand Up @@ -64,6 +69,15 @@
<%= I18n.t('nav.plan') %></a>
</li>
<% end %>
<li>
<a
href="<%= event_profile_path %>"
class="flex items-center gap-2 h-max box-border m-0 boder-none bg-transparent px-2 py-3 <%= current_path?(event_profile_path) ? 'nav-current' : '' %>"
<%= sanitize current_path?(event_path) ? 'aria-current="page"' : '' %>
>
<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 512 512" width="1em" height="1em" class="" role="img" aria-hidden="true" focusable="false" xmlns="http://www.w3.org/2000/svg" style="color: rgb(112, 109, 101);"><path d="M256 288A144 144 0 1 0 256 0a144 144 0 1 0 0 288zm-94.7 32C72.2 320 0 392.2 0 481.3c0 17 13.8 30.7 30.7 30.7H481.3c17 0 30.7-13.8 30.7-30.7C512 392.2 439.8 320 350.7 320H161.3z"></path></svg>
<%= I18n.t('nav.profile') %></a>
</li>
</ul>
<div class="ml-auto">
<label class="flex items-center justify-start gap-2">
Expand Down
37 changes: 37 additions & 0 deletions app/views/profiles/show.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<% if @user && @user.profile %>
<div class="flex justify-center">
<div class="w-1/2">
<div class="w-full min-w-[400px] h-fit p-4 shadow-[0_1px_2px_0_rgba(3,3,2,0.3)] rounded-md bg-white">
<div class="flex gap-4">
<img class="w-36 h-36 rounded-full" src="<%= @user.profile.avatar_url %>">
<div class="flex flex-col gap-2 w-full">
<div class="flex-grow flex flex-col gap-2">
<h1 class="text-4xl"><%= @user.profile.name %></h1>
<h2><%= @user.profile.email %></h2>
</div>
<div class="self-end">
<%= form_with(url: '/session', method: :delete) do |f| %>
<%= f.submit I18n.t('button.signout'), class: "p-2 text-sm m-h-[calc(0.857143rem+18px)] normal-button" %>
<% end %>
</div>
</div>
</div>
</div>
</div>
</div>
<% else %>
<div class="flex items-center justify-center h-96">
<div class="h-auto">
<%= form_tag('/auth/github', method: 'post' , data: {turbo: false}) do %>
<button type='submit' class="p-2 border border-black border-solid rounded-md">
<div class="flex items-center gap-2">
<img src="/icons/github-mark.svg" class="w-6 h-6">
<span class="font-bold">
Sign up with GitHub
</span>
</div>
</button>
<% end %>
</div>
</div>
<% end %>
5 changes: 5 additions & 0 deletions config/initializers/omniauth.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# frozen_string_literal: true

Rails.application.config.middleware.use OmniAuth::Builder do
provider :github, ENV.fetch('GITHUB_KEY', nil), ENV.fetch('GITHUB_SECRET', nil), scope: 'read:user'
end
2 changes: 2 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ en:
root: "Top"
schedule: "Schedule"
plan: "My Plans"
profile: "Profile"
info:
create_plan_title: "Create your RubyKaigi Plans"
create_plan_text: "Create your RubyKaigi Plans with RubyKaigi mie.ru kun. Agree to Terms of service and press create button."
Expand Down Expand Up @@ -94,6 +95,7 @@ en:
accept_to_add: "Accept and add to Plans"
make_editable: "Make editable"
check_password: "Take edit permission"
signout: "Sign out"
default_vales:
plan_title: "My plans"

Expand Down
Loading
Loading