Install devise invitable

Devise invitable gem is required to invite users.
This commit is contained in:
Rahul 2019-06-03 20:03:13 +05:30
parent a20c1bb882
commit 04c3859526
11 changed files with 171 additions and 3 deletions

View file

@ -37,6 +37,7 @@ gem 'rails-i18n'
# as authentification framework
gem 'devise'
gem 'devise_ichain_authenticatable'
gem 'devise_invitable'
# for openID authentication
gem 'omniauth'

View file

@ -161,6 +161,9 @@ GEM
warden (~> 1.2.3)
devise_ichain_authenticatable (0.3.2)
devise (>= 2.2)
devise_invitable (2.0.1)
actionmailer (>= 5.0)
devise (>= 4.6)
diff-lcs (1.3)
docile (1.3.1)
domain_name (0.5.20180417)
@ -646,6 +649,7 @@ DEPENDENCIES
delayed_job_active_record
devise
devise_ichain_authenticatable
devise_invitable
dotenv-rails
factory_bot_rails
faker

View file

@ -9,6 +9,8 @@ class ApplicationController < ActionController::Base
# Ensure every controller authorizes resource or skips authorization (skip_authorization_check)
check_authorization unless: :devise_controller?
before_action :devise_configure_permitted_parameters, if: :devise_controller?
def store_location
# store last url - this is needed for post-login redirect to whatever the user last visited.
return unless request.get?
@ -65,4 +67,8 @@ class ApplicationController < ActionController::Base
def not_found
raise ActionController::RoutingError.new('Not Found')
end
def devise_configure_permitted_parameters
devise_parameter_sanitizer.permit(:accept_invitation, keys: [:username])
end
end

View file

@ -49,8 +49,8 @@ class User < ApplicationRecord
[:ichain_authenticatable, :ichain_registerable, :omniauthable, omniauth_providers: []]
else
[:database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :confirmable,
:omniauthable, omniauth_providers: [:suse, :google, :facebook, :github]]
:recoverable, :rememberable, :trackable, :validatable, :invitable,
:confirmable, :omniauthable, omniauth_providers: [:suse, :google, :facebook, :github]]
end
devise(*devise_modules)

View file

@ -0,0 +1,20 @@
.container
.row
.col-md-6.col-md-offset-3
.panel.panel-default
.panel-heading
%h3.panel-title
%h2= t 'devise.invitations.edit.header'
.panel-body
= form_for(resource, as: resource_name, url: invitation_path(resource_name), html: { method: :put }) do |f|
= render 'devise/shared/error_messages', resource: resource
= f.hidden_field :invitation_token, readonly: true
- if f.object.class.require_password_on_accepting
= f.label :username
= f.text_field :username, class: 'form-control'
= f.label :password
= f.password_field :password, class: 'form-control'
= f.label :password_confirmation
= f.password_field :password_confirmation, class: 'form-control'
%br
= f.submit t('devise.invitations.edit.submit_button'), class: 'btn btn-default btn-primary'

View file

@ -0,0 +1,11 @@
<p><%= t("devise.mailer.invitation_instructions.hello", email: @resource.email) %></p>
<p><%= t("devise.mailer.invitation_instructions.someone_invited_you", url: root_url) %></p>
<p><%= link_to t("devise.mailer.invitation_instructions.accept"), accept_invitation_url(@resource, invitation_token: @token) %></p>
<% if @resource.invitation_due_at %>
<p><%= t("devise.mailer.invitation_instructions.accept_until", due_date: l(@resource.invitation_due_at, format: :'devise.mailer.invitation_instructions.accept_until_format')) %></p>
<% end %>
<p><%= t("devise.mailer.invitation_instructions.ignore") %></p>

View file

@ -0,0 +1,11 @@
<%= t("devise.mailer.invitation_instructions.hello", email: @resource.email) %>
<%= t("devise.mailer.invitation_instructions.someone_invited_you", url: root_url) %>
<%= accept_invitation_url(@resource, invitation_token: @token) %>
<% if @resource.invitation_due_at %>
<%= t("devise.mailer.invitation_instructions.accept_until", due_date: l(@resource.invitation_due_at, format: :'devise.mailer.invitation_instructions.accept_until_format')) %>
<% end %>
<%= t("devise.mailer.invitation_instructions.ignore") %>

View file

@ -96,6 +96,55 @@ Devise.setup do |config|
# Setup a pepper to generate the encrypted password.
# config.pepper = "9a89de1df41b08b48af904bbbc5b8d713addd9d14e2758f12dd14105acd8627fececa02f33f89c0e9764e74262d8874c4a52534b788f5aa4b1716522ae6888b1"
# ==> 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 }
# Ensure that invited record is valid.
# The invitation won't be sent if this check fails.
# 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 foreign key to the inviting model (if invited_by_class_name is set)
# Default: :invited_by_id
# config.invited_by_foreign_key = :invited_by_id
# 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
# Auto-login after the user accepts the invite. If this is false,
# the user will need to manually log in after accepting the invite.
# Default: true
# config.allow_insecure_sign_in_after_accept = false
# ==> 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

View file

@ -0,0 +1,31 @@
en:
devise:
failure:
invited: "You have a pending invitation, accept it to finish creating your account."
invitations:
send_instructions: "An invitation email has been sent to %{email}."
invitation_token_invalid: "The invitation token provided is not valid!"
updated: "Your password was set successfully. You are now signed in."
updated_not_active: "Your password was set successfully."
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"
hello: "Hello %{email}"
someone_invited_you: "Someone has invited you to %{url}, you can accept it through the link below."
accept: "Accept invitation"
accept_until: "This invitation will be due in %{due_date}."
ignore: "If you don't want to accept the invitation, please ignore this email. Your account won't be created until you access the link above and set your password."
time:
formats:
devise:
mailer:
invitation_instructions:
accept_until_format: "%B %d, %Y %I:%M %p"

View file

@ -0,0 +1,23 @@
class DeviseInvitableAddToUsers < ActiveRecord::Migration[5.1]
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
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

View file

@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20181113195810) do
ActiveRecord::Schema.define(version: 2019_06_03_143107) do
create_table "answers", force: :cascade do |t|
t.string "title"
@ -587,8 +587,20 @@ ActiveRecord::Schema.define(version: 20181113195810) do
t.boolean "is_admin", default: false
t.string "username"
t.boolean "is_disabled", default: false
t.string "invitation_token"
t.datetime "invitation_created_at"
t.datetime "invitation_sent_at"
t.datetime "invitation_accepted_at"
t.integer "invitation_limit"
t.string "invited_by_type"
t.integer "invited_by_id"
t.integer "invitations_count", default: 0
t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["invitation_token"], name: "index_users_on_invitation_token", unique: true
t.index ["invitations_count"], name: "index_users_on_invitations_count"
t.index ["invited_by_id"], name: "index_users_on_invited_by_id"
t.index ["invited_by_type", "invited_by_id"], name: "index_users_on_invited_by_type_and_invited_by_id"
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
t.index ["username"], name: "index_users_on_username", unique: true
end