Skip to content

Commit

Permalink
invitations part 2
Browse files Browse the repository at this point in the history
  • Loading branch information
bolandrm committed Apr 14, 2014
1 parent f15a595 commit f8d4cc0
Show file tree
Hide file tree
Showing 19 changed files with 249 additions and 25 deletions.
5 changes: 4 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ gem 'sass-rails', '~> 4.0.0'
gem 'uglifier', '>= 1.3.0'
gem 'coffee-rails', '~> 4.0.0'
gem 'jquery-rails'
gem 'devise', '~> 3.1.0'
gem 'devise', '~> 3.2.0'
gem 'devise_invitable', '~> 1.3.4'
gem 'apartment', '~> 0.22.1'
gem 'simple_form', '~> 3.0.0', github: 'plataformatec/simple_form', branch: 'master'

Expand All @@ -23,4 +24,6 @@ group :development, :test do
gem 'factory_girl_rails'
gem 'database_cleaner'
gem 'shoulda-matchers'
gem 'letter_opener'
gem 'email_spec'
end
24 changes: 19 additions & 5 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,13 @@ GEM
multi_json (~> 1.3)
thread_safe (~> 0.1)
tzinfo (~> 0.3.37)
addressable (2.3.6)
apartment (0.22.1)
activerecord (>= 3.1.2)
rack (>= 1.3.6)
arel (4.0.0)
atomic (1.1.14)
bcrypt-ruby (3.1.2)
bcrypt (3.1.7)
bootstrap-sass (3.1.1.0)
sass (~> 3.2)
bourne (1.4.0)
Expand All @@ -61,16 +62,22 @@ GEM
execjs
coffee-script-source (1.6.3)
database_cleaner (1.0.1)
devise (3.1.0)
bcrypt-ruby (~> 3.0)
devise (3.2.4)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 3.2.6, < 5)
thread_safe (~> 0.1)
warden (~> 1.2.3)
devise_invitable (1.3.4)
actionmailer (>= 3.2.6, < 5)
devise (>= 3.2.0)
diff-lcs (1.2.4)
em-websocket (0.5.0)
eventmachine (>= 0.12.9)
http_parser.rb (~> 0.5.3)
email_spec (1.5.0)
launchy (~> 2.1)
mail (~> 2.2)
erubis (2.7.0)
eventmachine (1.0.3)
execjs (2.0.1)
Expand Down Expand Up @@ -100,6 +107,10 @@ GEM
jquery-rails (3.0.4)
railties (>= 3.0, < 5.0)
thor (>= 0.14, < 2.0)
launchy (2.4.2)
addressable (~> 2.3)
letter_opener (1.1.2)
launchy (~> 2.2)
listen (1.2.2)
rb-fsevent (>= 0.9.3)
rb-inotify (>= 0.9)
Expand All @@ -118,7 +129,7 @@ GEM
multi_json (1.8.0)
nokogiri (1.6.0)
mini_portile (~> 0.5.0)
orm_adapter (0.4.0)
orm_adapter (0.5.0)
pg (0.17.0)
polyglot (0.3.3)
pry (0.9.12.2)
Expand Down Expand Up @@ -211,12 +222,15 @@ DEPENDENCIES
capybara
coffee-rails (~> 4.0.0)
database_cleaner
devise (~> 3.1.0)
devise (~> 3.2.0)
devise_invitable (~> 1.3.4)
email_spec
factory_girl_rails
guard
guard-livereload
guard-rspec
jquery-rails
letter_opener
pg
rails (= 4.0.0)
rails-erd
Expand Down
3 changes: 2 additions & 1 deletion app/assets/stylesheets/application.css.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
@import "bootstrap";

@import "layout";
@import "signin";
@import "signin";
@import "typography";
2 changes: 2 additions & 0 deletions app/assets/stylesheets/typography.css.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.color-success { color: #3C763D; }
.extra-margin-top { margin-top: 40px; }
21 changes: 19 additions & 2 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception

before_filter :load_schema, :authenticate_user!
before_filter :load_schema, :authenticate_user!, :set_mailer_host
before_filter :configure_permitted_parameters, if: :devise_controller?

protected

def configure_permitted_parameters
devise_parameter_sanitizer.for(:accept_invitation).concat([:name])
end

private

private
def load_schema
Apartment::Database.switch('public')
return unless request.subdomain.present?
Expand All @@ -20,7 +28,16 @@ def current_account
end
helper_method :current_account

def set_mailer_host
subdomain = current_account ? "#{current_account.subdomain}." : ""
ActionMailer::Base.default_url_options[:host] = "#{subdomain}lvh.me:3000"
end

def after_sign_out_path_for(resource_or_scope)
new_user_session_path
end

def after_invite_path_for(resource)
users_path
end
end
2 changes: 1 addition & 1 deletion app/helpers/user_helper.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module UserHelper
def user_status(user)
if current_account.owner == user
if current_account.owner == user || user.invitation_accepted?
content_tag(:span, '', class: 'glyphicon glyphicon-ok color-success')
else
'Invitation Pending'
Expand Down
2 changes: 1 addition & 1 deletion app/models/user.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
class User < ActiveRecord::Base
devise :database_authenticatable, :recoverable, :rememberable, :validatable
devise :invitable, :database_authenticatable, :recoverable, :rememberable, :validatable

validates :name, presence: true
end
15 changes: 15 additions & 0 deletions app/views/devise/invitations/edit.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<div class="col-md-6 col-md-offset-3 panel panel-default">
<div class="panel-body">
<h2>Create an Account</h2>

<%= simple_form_for resource, :as => resource_name,
:url => invitation_path(resource_name),
:html => { :method => :put } do |f| %>
<%= f.input :invitation_token, as: :hidden %>
<%= f.input :name %>
<%= f.input :password %>
<%= f.input :password_confirmation %>
<%= f.button :submit, "Create Account", class: 'btn-primary' %>
<% end %>
</div>
</div>
12 changes: 12 additions & 0 deletions app/views/devise/invitations/new.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<div class="col-md-6 col-md-offset-3 panel panel-default">
<div class="panel-body">
<h2>Send Invitation</h2>

<%= simple_form_for resource, :as => resource_name,
:url => invitation_path(resource_name),
:html => {:method => :post} do |f| %>
<%= f.input :email %>
<%= f.button :submit, "Create Account", class: 'btn-primary' %>
<% end %>
</div>
</div>
8 changes: 8 additions & 0 deletions app/views/devise/mailer/invitation_instructions.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<p>Hello <%= @resource.email %>!</p>

<p>Someone has invited you to <%= root_url %>, you can accept it through the link below.</p>

<p><%= link_to 'Accept invitation', accept_invitation_url(@resource, :invitation_token => @token) %></p>

<p>If you don't want to accept the invitation, please ignore this email.<br />
Your account won't be created until you access the link above and set your password.</p>
14 changes: 7 additions & 7 deletions app/views/layouts/application.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@
<div class="navbar-header">
<%= link_to 'Time Tracker', root_path, class: 'navbar-brand' %>
</div>
<div class="pull-right right-buttons">
<% if user_signed_in? %>
<% if user_signed_in? %>
<div class="pull-right right-buttons">
<%= link_to 'Sign out', destroy_user_session_path, method: 'delete', class: 'btn btn-default navbar-btn' %>
<% end %>
</div>
<ul class="nav navbar-nav navbar-right">
<li><%= link_to 'Users', users_path %></li>
</ul>
</div>
<ul class="nav navbar-nav navbar-right">
<li><%= link_to 'Users', users_path %></li>
</ul>
<% end %>
</nav>
</header>

Expand Down
8 changes: 8 additions & 0 deletions app/views/users/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@
<% end %>
</tbody>
</table>

<h3 class="extra-margin-top">Invite User</h3>

<%= simple_form_for(User.new, url: user_invitation_path,
html: { class: 'form-inline' }) do |f| %>
<%= f.input :email, placeholder: 'Email', label: false %>
<%= f.button :submit, 'Invite User', class: 'btn-primary' %>
<% end %>
</div>
</div>
</div>
4 changes: 2 additions & 2 deletions config/environments/development.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
config.consider_all_requests_local = true
config.action_controller.perform_caching = false

# Don't care if the mailer can't send.
config.action_mailer.raise_delivery_errors = false
config.action_mailer.raise_delivery_errors = true
config.action_mailer.delivery_method = :letter_opener

# Print deprecation notices to the Rails logger.
config.active_support.deprecation = :log
Expand Down
39 changes: 39 additions & 0 deletions config/initializers/devise.rb
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,45 @@
# Setup a pepper to generate the encrypted password.
# config.pepper = '68e37fe61c0e6808c8bd6f6d79694bb3a465f183ebab9819284410137f998cc735fbe01ef468aed30042ae8ff9af7771946e4cd7862427645fd3daecc374bcab'

# ==> Configuration for :invitable
# The period the generated invitation token is valid, after
# this period, the invited resource won't be able to accept the invitation.
# When invite_for is 0 (the default), the invitation won't expire.
# config.invite_for = 2.weeks

# Number of invitations users can send.
# - If invitation_limit is nil, there is no limit for invitations, users can
# send unlimited invitations, invitation_limit column is not used.
# - If invitation_limit is 0, users can't send invitations by default.
# - If invitation_limit n > 0, users can send n invitations.
# You can change invitation_limit column for some users so they can send more
# or less invitations, even with global invitation_limit = 0
# Default: nil
# config.invitation_limit = 5

# The key to be used to check existing users when sending an invitation
# and the regexp used to test it when validate_on_invite is not set.
# config.invite_key = {:email => /\A[^@]+@[^@]+\z/}
# config.invite_key = {:email => /\A[^@]+@[^@]+\z/, :username => nil}

# Flag that force a record to be valid before being actually invited
# Default: false
# config.validate_on_invite = true

# Resend invitation if user with invited status is invited again
# Default: true
# config.resend_invitation = false

# The class name of the inviting model. If this is nil,
# the #invited_by association is declared to be polymorphic.
# Default: nil
# config.invited_by_class_name = 'User'

# The column name used for counter_cache column. If this is nil,
# the #invited_by association is declared without counter_cache.
# Default: nil
# config.invited_by_counter_cache = :invitations_count

# ==> Configuration for :confirmable
# A period that the user is allowed to access the website even without
# confirming his account. For instance, if set to 2.days, the user will be
Expand Down
17 changes: 17 additions & 0 deletions config/locales/devise_invitable.en.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
en:
devise:
invitations:
send_instructions: 'An invitation email has been sent to %{email}.'
invitation_token_invalid: 'The invitation token provided is not valid!'
updated: 'Your account was created successfully. You are now signed in.'
no_invitations_remaining: "No invitations remaining"
invitation_removed: 'Your invitation was removed.'
new:
header: "Send invitation"
submit_button: "Send an invitation"
edit:
header: "Set your password"
submit_button: "Set my password"
mailer:
invitation_instructions:
subject: 'Invitation instructions'
26 changes: 26 additions & 0 deletions db/migrate/20140414210524_devise_invitable_add_to_users.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
class DeviseInvitableAddToUsers < ActiveRecord::Migration
def up
change_table :users do |t|
t.string :invitation_token
t.datetime :invitation_created_at
t.datetime :invitation_sent_at
t.datetime :invitation_accepted_at
t.integer :invitation_limit
t.references :invited_by, :polymorphic => true
t.integer :invitations_count, default: 0
t.index :invitations_count
t.index :invitation_token, :unique => true # for invitable
t.index :invited_by_id
end

# And allow null encrypted_password and password_salt:
change_column_null :users, :encrypted_password, true
end

def down
change_table :users do |t|
t.remove_references :invited_by, :polymorphic => true
t.remove :invitations_count, :invitation_limit, :invitation_sent_at, :invitation_accepted_at, :invitation_token, :invitation_created_at
end
end
end
15 changes: 13 additions & 2 deletions db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema.define(version: 20130922162109) do
ActiveRecord::Schema.define(version: 20140414210524) do

# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
Expand All @@ -26,15 +26,26 @@
create_table "users", force: true do |t|
t.string "name"
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "encrypted_password", default: ""
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.datetime "created_at"
t.datetime "updated_at"
t.string "invitation_token"
t.datetime "invitation_created_at"
t.datetime "invitation_sent_at"
t.datetime "invitation_accepted_at"
t.integer "invitation_limit"
t.integer "invited_by_id"
t.string "invited_by_type"
t.integer "invitations_count", default: 0
end

add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
add_index "users", ["invitation_token"], name: "index_users_on_invitation_token", unique: true, using: :btree
add_index "users", ["invitations_count"], name: "index_users_on_invitations_count", using: :btree
add_index "users", ["invited_by_id"], name: "index_users_on_invited_by_id", using: :btree
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree

end
Loading

0 comments on commit f8d4cc0

Please sign in to comment.