@@ -53,6 +53,7 @@ gem 'bootstrap_form' |
||
53 | 53 |
gem 'friendly_id', '~> 5.0.0' |
54 | 54 |
gem 'devise' |
55 | 55 |
gem "devise-async" |
56 |
+gem 'devise_invitable', '~> 1.3.4' |
|
56 | 57 |
gem 'redcarpet' |
57 | 58 |
gem 'summernote-rails' |
58 | 59 |
gem 'figaro' |
@@ -81,6 +81,9 @@ GEM |
||
81 | 81 |
warden (~> 1.2.3) |
82 | 82 |
devise-async (0.9.0) |
83 | 83 |
devise (~> 3.2) |
84 |
+ devise_invitable (1.3.6) |
|
85 |
+ actionmailer (>= 3.2.6, < 5) |
|
86 |
+ devise (>= 3.2.0) |
|
84 | 87 |
diff-lcs (1.2.5) |
85 | 88 |
email_spec (1.6.0) |
86 | 89 |
launchy (~> 2.1) |
@@ -340,6 +343,7 @@ DEPENDENCIES |
||
340 | 343 |
database_cleaner |
341 | 344 |
devise |
342 | 345 |
devise-async |
346 |
+ devise_invitable (~> 1.3.4) |
|
343 | 347 |
email_spec |
344 | 348 |
factory_girl_rails (~> 4.0) |
345 | 349 |
figaro |
@@ -1,7 +1,7 @@ |
||
1 | 1 |
class User < ActiveRecord::Base |
2 | 2 |
# Include default devise modules. Others available are: |
3 | 3 |
# :confirmable, :lockable, :timeoutable and :omniauthable |
4 |
- devise :database_authenticatable, :async, :registerable, |
|
4 |
+ devise :invitable, :database_authenticatable, :async, :registerable, |
|
5 | 5 |
:recoverable, :rememberable, :trackable, :validatable |
6 | 6 |
|
7 | 7 |
validates :password, presence: true, length: {minimum: 5, maximum: 120}, on: :create |
@@ -0,0 +1,16 @@ |
||
1 |
+<h2><%= t 'devise.invitations.edit.header' %></h2> |
|
2 |
+<h2><%= t 'devise.invitations.edit.header' %></h2> |
|
3 |
+<h2><%= t 'devise.invitations.edit.header' %></h2> |
|
4 |
+<h2><%= t 'devise.invitations.edit.header' %></h2> |
|
5 |
+<h2><%= t 'devise.invitations.edit.header' %></h2> |
|
6 |
+<h2><%= t 'devise.invitations.edit.header' %></h2> |
|
7 |
+ |
|
8 |
+<%= simple_form_for resource, :as => resource_name, :url => invitation_path(resource_name), :html => { :method => :put } do |f| %> |
|
9 |
+ <%= devise_error_messages! %> |
|
10 |
+ <%= f.hidden_field :invitation_token %> |
|
11 |
+ |
|
12 |
+ <%= f.input :password %> |
|
13 |
+ <%= f.input :password_confirmation %> |
|
14 |
+ |
|
15 |
+ <%= f.submit t("devise.invitations.edit.submit_button") %> |
|
16 |
+<% end %> |
@@ -0,0 +1,11 @@ |
||
1 |
+<h2><%= t "devise.invitations.new.header" %></h2> |
|
2 |
+ |
|
3 |
+<%= simple_form_for resource, :as => resource_name, :url => invitation_path(resource_name), :html => {:method => :post} do |f| %> |
|
4 |
+ <%= devise_error_messages! %> |
|
5 |
+ |
|
6 |
+<% resource.class.invite_key_fields.each do |field| -%> |
|
7 |
+ <%= f.input field %> |
|
8 |
+<% end -%> |
|
9 |
+ |
|
10 |
+<%= f.submit t("devise.invitations.new.submit_button") %> |
|
11 |
+<% end %> |
@@ -0,0 +1,9 @@ |
||
1 |
+<p><%= I18n.t("devise.mailer.invitation_instructions.hello", email: @resource.email) %></p> |
|
2 |
+ |
|
3 |
+<p><%= I18n.t("devise.mailer.invitation_instructions.someone_invited_you", url: root_url) %></p> |
|
4 |
+ |
|
5 |
+<p><%= link_to I18n.t("devise.mailer.invitation_instructions.accept"), accept_invitation_url(@resource, :invitation_token => @token) %></p> |
|
6 |
+ |
|
7 |
+<p><%= I18n.t("devise.mailer.invitation_instructions.ignore").html_safe %></p> |
|
8 |
+ |
|
9 |
+<p><%= mission.title %></p> |
@@ -20,7 +20,7 @@ Devise.setup do |config| |
||
20 | 20 |
# :mongoid (bson_ext recommended) by default. Other ORMs may be |
21 | 21 |
# available as additional gems. |
22 | 22 |
require 'devise/orm/active_record' |
23 |
- |
|
23 |
+ require 'devise_invitable' |
|
24 | 24 |
# ==> Configuration for any authentication mechanism |
25 | 25 |
# Configure which keys are used when authenticating a user. The default is |
26 | 26 |
# just :email. You can configure it to use [:username, :subdomain], so for |
@@ -99,6 +99,45 @@ Devise.setup do |config| |
||
99 | 99 |
# Setup a pepper to generate the encrypted password. |
100 | 100 |
# config.pepper = 'db05f34b2f36e0e162d8f4006bc6d1dcb07508df7331a36ba79045b6635bdb39eb00b50754a454b42f399894aba335313b9f154f7027399d8e696dbbf739a47c' |
101 | 101 |
|
102 |
+ # ==> Configuration for :invitable |
|
103 |
+ # The period the generated invitation token is valid, after |
|
104 |
+ # this period, the invited resource won't be able to accept the invitation. |
|
105 |
+ # When invite_for is 0 (the default), the invitation won't expire. |
|
106 |
+ # config.invite_for = 2.weeks |
|
107 |
+ |
|
108 |
+ # Number of invitations users can send. |
|
109 |
+ # - If invitation_limit is nil, there is no limit for invitations, users can |
|
110 |
+ # send unlimited invitations, invitation_limit column is not used. |
|
111 |
+ # - If invitation_limit is 0, users can't send invitations by default. |
|
112 |
+ # - If invitation_limit n > 0, users can send n invitations. |
|
113 |
+ # You can change invitation_limit column for some users so they can send more |
|
114 |
+ # or less invitations, even with global invitation_limit = 0 |
|
115 |
+ # Default: nil |
|
116 |
+ # config.invitation_limit = 5 |
|
117 |
+ |
|
118 |
+ # The key to be used to check existing users when sending an invitation |
|
119 |
+ # and the regexp used to test it when validate_on_invite is not set. |
|
120 |
+ # config.invite_key = {:email => /\A[^@]+@[^@]+\z/} |
|
121 |
+ # config.invite_key = {:email => /\A[^@]+@[^@]+\z/, :username => nil} |
|
122 |
+ |
|
123 |
+ # Flag that force a record to be valid before being actually invited |
|
124 |
+ # Default: false |
|
125 |
+ # config.validate_on_invite = true |
|
126 |
+ |
|
127 |
+ # Resend invitation if user with invited status is invited again |
|
128 |
+ # Default: true |
|
129 |
+ # config.resend_invitation = false |
|
130 |
+ |
|
131 |
+ # The class name of the inviting model. If this is nil, |
|
132 |
+ # the #invited_by association is declared to be polymorphic. |
|
133 |
+ # Default: nil |
|
134 |
+ # config.invited_by_class_name = 'User' |
|
135 |
+ |
|
136 |
+ # The column name used for counter_cache column. If this is nil, |
|
137 |
+ # the #invited_by association is declared without counter_cache. |
|
138 |
+ # Default: nil |
|
139 |
+ # config.invited_by_counter_cache = :invitations_count |
|
140 |
+ |
|
102 | 141 |
# ==> Configuration for :confirmable |
103 | 142 |
# A period that the user is allowed to access the website even without |
104 | 143 |
# confirming their account. For instance, if set to 2.days, the user will be |
@@ -0,0 +1,21 @@ |
||
1 |
+en: |
|
2 |
+ devise: |
|
3 |
+ invitations: |
|
4 |
+ send_instructions: 'An invitation email has been sent to %{email}.' |
|
5 |
+ invitation_token_invalid: 'The invitation token provided is not valid!' |
|
6 |
+ updated: 'Your password was set successfully. You are now signed in.' |
|
7 |
+ no_invitations_remaining: "No invitations remaining" |
|
8 |
+ invitation_removed: 'Your invitation was removed.' |
|
9 |
+ new: |
|
10 |
+ header: "Send invitation" |
|
11 |
+ submit_button: "Send an invitation" |
|
12 |
+ edit: |
|
13 |
+ header: "Set your password" |
|
14 |
+ submit_button: "Set my password" |
|
15 |
+ mailer: |
|
16 |
+ invitation_instructions: |
|
17 |
+ subject: 'Invitation instructions' |
|
18 |
+ hello: 'Hello %{email}' |
|
19 |
+ someone_invited_you: 'Someone has invited you to %{url}, you can accept it through the link below.' |
|
20 |
+ accept: 'Accept invitation' |
|
21 |
+ ignore: "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." |
@@ -0,0 +1,27 @@ |
||
1 |
+class DeviseInvitableAddToUsers < ActiveRecord::Migration |
|
2 |
+ def up |
|
3 |
+ change_table :users do |t| |
|
4 |
+ t.string :invitation_token |
|
5 |
+ t.datetime :invitation_created_at |
|
6 |
+ t.datetime :invitation_sent_at |
|
7 |
+ t.datetime :invitation_accepted_at |
|
8 |
+ t.integer :invitation_limit |
|
9 |
+ t.references :invited_by, :polymorphic => true |
|
10 |
+ t.integer :invitations_count, default: 0 |
|
11 |
+ t.index :invitations_count |
|
12 |
+ t.index :invitation_token, :unique => true # for invitable |
|
13 |
+ t.index :invited_by_id |
|
14 |
+ end |
|
15 |
+ |
|
16 |
+ # And allow null encrypted_password and password_salt: |
|
17 |
+ change_column_null :users, :encrypted_password, true |
|
18 |
+ end |
|
19 |
+ |
|
20 |
+ def down |
|
21 |
+ change_table :users do |t| |
|
22 |
+ t.remove_references :invited_by, :polymorphic => true |
|
23 |
+ t.remove :invitations_count, :invitation_limit, :invitation_sent_at, :invitation_accepted_at, :invitation_token, :invitation_created_at |
|
24 |
+ end |
|
25 |
+ change_column_null :users, :encrypted_password, false |
|
26 |
+ end |
|
27 |
+end |
@@ -11,7 +11,7 @@ |
||
11 | 11 |
# |
12 | 12 |
# It's strongly recommended that you check this file into your version control system. |
13 | 13 |
|
14 |
-ActiveRecord::Schema.define(version: 20150317234308) do |
|
14 |
+ActiveRecord::Schema.define(version: 20150416214326) do |
|
15 | 15 |
|
16 | 16 |
# These are extensions that must be enabled in order to support this database |
17 | 17 |
enable_extension "plpgsql" |
@@ -251,7 +251,7 @@ ActiveRecord::Schema.define(version: 20150317234308) do |
||
251 | 251 |
|
252 | 252 |
create_table "users", force: true do |t| |
253 | 253 |
t.string "email", default: "", null: false |
254 |
- t.string "encrypted_password", default: "", null: false |
|
254 |
+ t.string "encrypted_password", default: "" |
|
255 | 255 |
t.string "reset_password_token" |
256 | 256 |
t.datetime "reset_password_sent_at" |
257 | 257 |
t.datetime "remember_created_at" |
@@ -270,9 +270,20 @@ ActiveRecord::Schema.define(version: 20150317234308) do |
||
270 | 270 |
t.boolean "avatar_processing", default: false, null: false |
271 | 271 |
t.string "bio" |
272 | 272 |
t.string "language" |
273 |
+ t.string "invitation_token" |
|
274 |
+ t.datetime "invitation_created_at" |
|
275 |
+ t.datetime "invitation_sent_at" |
|
276 |
+ t.datetime "invitation_accepted_at" |
|
277 |
+ t.integer "invitation_limit" |
|
278 |
+ t.integer "invited_by_id" |
|
279 |
+ t.string "invited_by_type" |
|
280 |
+ t.integer "invitations_count", default: 0 |
|
273 | 281 |
end |
274 | 282 |
|
275 | 283 |
add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree |
284 |
+ add_index "users", ["invitation_token"], name: "index_users_on_invitation_token", unique: true, using: :btree |
|
285 |
+ add_index "users", ["invitations_count"], name: "index_users_on_invitations_count", using: :btree |
|
286 |
+ add_index "users", ["invited_by_id"], name: "index_users_on_invited_by_id", using: :btree |
|
276 | 287 |
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree |
277 | 288 |
|
278 | 289 |
create_table "validation_texts", force: true do |t| |