diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 09705d1..37ba566 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -1,2 +1,10 @@
class ApplicationController < ActionController::Base
+ before_action :configure_devise_parameters, if: :devise_controller?
+
+ protected
+
+ def configure_devise_parameters
+ devise_parameter_sanitizer.permit(:sign_up, keys: [:tos_accepted])
+ devise_parameter_sanitizer.permit(:account_update, keys: [:notifications_enabled])
+ end
end
diff --git a/app/javascript/packs/src/components/users.scss b/app/javascript/packs/src/components/users.scss
index dc42ca4..05ae08f 100644
--- a/app/javascript/packs/src/components/users.scss
+++ b/app/javascript/packs/src/components/users.scss
@@ -1,5 +1,3 @@
-.new_user {
- .form-check-label.boolean {
- color: inherit;
- }
+.form-check-label.optional.boolean {
+ color: inherit;
}
diff --git a/app/models/user.rb b/app/models/user.rb
index 791ed72..a398135 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -12,10 +12,12 @@
# encrypted_password :string(255) default(""), not null
# last_sign_in_at :datetime
# last_sign_in_ip :string(255)
+# notifications_enabled :boolean default(TRUE), not null
# remember_created_at :datetime
# reset_password_sent_at :datetime
# reset_password_token :string(255)
# sign_in_count :integer default(0), not null
+# tos_accepted :boolean default(FALSE), not null
# unconfirmed_email :string(255)
# created_at :datetime not null
# updated_at :datetime not null
@@ -32,4 +34,6 @@ class User < ApplicationRecord
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable, :confirmable
+
+ validates :tos_accepted, acceptance: true
end
diff --git a/app/views/devise/registrations/edit.html.erb b/app/views/devise/registrations/edit.html.erb
index 9d99eb0..4ab2468 100644
--- a/app/views/devise/registrations/edit.html.erb
+++ b/app/views/devise/registrations/edit.html.erb
@@ -1,7 +1,6 @@
<%= devise_form_container do %>
<%= t('.title', resource: resource_name.to_s.humanize) %>
-
<%= simple_form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
<%= f.input :email, autofocus: true, autocomplete: "email" %>
@@ -25,6 +24,7 @@
<%= f.input :password_confirmation, autocomplete: "off" %>
+ <%= f.input :notifications_enabled %>
<%= f.button :submit, t('.update'), class: "btn-primary" %>
<% end %>
diff --git a/app/views/devise/registrations/new.html.erb b/app/views/devise/registrations/new.html.erb
index ed81d21..69a0e09 100644
--- a/app/views/devise/registrations/new.html.erb
+++ b/app/views/devise/registrations/new.html.erb
@@ -9,6 +9,8 @@
<%= f.input :password_confirmation, autocomplete: "off" %>
+ <%= f.input :tos_accepted, label: t('.tos_acceptance_html') %>
+
<%= f.button :submit, t('.sign_up'), class: "btn-primary" %>
<% end %>
diff --git a/config/locales/en.yml b/config/locales/en.yml
index d6fe953..c7c3395 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -1,4 +1,15 @@
en:
+ activerecord:
+ attributes:
+ user:
+ tos_accepted: "Terms of service"
+ notifications_enabled: "Notifications enabled"
+
+ devise:
+ registrations:
+ new:
+ tos_acceptance_html: "You must accept our Terms of service"
+
shared:
navbar:
sign_up: "Sign up"
diff --git a/db/migrate/20180523145630_devise_create_users.rb b/db/migrate/20180523145630_devise_create_users.rb
index 4ba28dc..b0c5e73 100644
--- a/db/migrate/20180523145630_devise_create_users.rb
+++ b/db/migrate/20180523145630_devise_create_users.rb
@@ -32,7 +32,6 @@ class DeviseCreateUsers < ActiveRecord::Migration[5.2]
# t.string :unlock_token # Only if unlock strategy is :email or :both
# t.datetime :locked_at
-
t.timestamps null: false
end
diff --git a/db/migrate/20180524205809_add_custom_fields_to_users.rb b/db/migrate/20180524205809_add_custom_fields_to_users.rb
new file mode 100644
index 0000000..2864b70
--- /dev/null
+++ b/db/migrate/20180524205809_add_custom_fields_to_users.rb
@@ -0,0 +1,6 @@
+class AddCustomFieldsToUsers < ActiveRecord::Migration[5.2]
+ def change
+ add_column :users, :tos_accepted, :boolean, null: false, default: false
+ add_column :users, :notifications_enabled, :boolean, null: false, default: true
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index da6be3d..8483285 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 2018_05_23_145630) do
+ActiveRecord::Schema.define(version: 2018_05_24_205809) do
create_table "users", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
t.string "email", default: "", null: false
@@ -29,6 +29,8 @@ ActiveRecord::Schema.define(version: 2018_05_23_145630) do
t.string "unconfirmed_email"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
+ t.boolean "tos_accepted", default: false, null: false
+ t.boolean "notifications_enabled", default: true, null: false
t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml
index 5f2b5ad..b6f3831 100644
--- a/test/fixtures/users.yml
+++ b/test/fixtures/users.yml
@@ -12,10 +12,12 @@
# encrypted_password :string(255) default(""), not null
# last_sign_in_at :datetime
# last_sign_in_ip :string(255)
+# notifications_enabled :boolean default(TRUE), not null
# remember_created_at :datetime
# reset_password_sent_at :datetime
# reset_password_token :string(255)
# sign_in_count :integer default(0), not null
+# tos_accepted :boolean default(FALSE), not null
# unconfirmed_email :string(255)
# created_at :datetime not null
# updated_at :datetime not null
@@ -37,3 +39,4 @@ user1:
email: user@chexpire.org
encrypted_password: <%= User.new.send(:password_digest, 'password') %>
confirmed_at: <%= 1.minute.ago %>
+ tos_accepted: true
diff --git a/test/models/user_test.rb b/test/models/user_test.rb
index 469c567..11697d6 100644
--- a/test/models/user_test.rb
+++ b/test/models/user_test.rb
@@ -12,10 +12,12 @@
# encrypted_password :string(255) default(""), not null
# last_sign_in_at :datetime
# last_sign_in_ip :string(255)
+# notifications_enabled :boolean default(TRUE), not null
# remember_created_at :datetime
# reset_password_sent_at :datetime
# reset_password_token :string(255)
# sign_in_count :integer default(0), not null
+# tos_accepted :boolean default(FALSE), not null
# unconfirmed_email :string(255)
# created_at :datetime not null
# updated_at :datetime not null
diff --git a/test/system/users_test.rb b/test/system/users_test.rb
index 3031785..03e456a 100644
--- a/test/system/users_test.rb
+++ b/test/system/users_test.rb
@@ -11,6 +11,7 @@ class UsersTest < ApplicationSystemTestCase
fill_in("user[email]", with: email)
fill_in("user[password]", with: password)
fill_in("user[password_confirmation]", with: password)
+ check "user[tos_accepted]"
click_button I18n.t("devise.registrations.new.sign_up")
@@ -58,4 +59,52 @@ class UsersTest < ApplicationSystemTestCase
assert_equal root_path, page.current_path
assert page.has_content?(I18n.t("shared.navbar.sign_in"))
end
+
+ test "tos must be accepted at signup" do
+ visit new_user_registration_path
+
+ email = "user@example.org"
+ fill_in("user[email]", with: email)
+ fill_in("user[password]", with: "password")
+ fill_in("user[password_confirmation]", with: "password")
+
+ click_button I18n.t("devise.registrations.new.sign_up")
+
+ assert_nil User.find_by(email: email)
+
+ within ".user_tos_accepted" do
+ page.has_selector? ".invalid-feedback"
+ end
+
+ # email is prefilled
+ assert_equal email, find_field("user[email]").value
+
+ fill_in("user[password]", with: "password")
+ fill_in("user[password_confirmation]", with: "password")
+ check "user[tos_accepted]"
+
+ click_button I18n.t("devise.registrations.new.sign_up")
+
+ assert_equal root_path, page.current_path
+ assert_not_nil User.find_by!(email: email, tos_accepted: true)
+ end
+
+ test "an user can globally disable its notifications" do
+ user = users(:user1)
+ login_as user
+
+ visit edit_user_registration_path
+
+ assert_equal user.email, find_field("user[email]").value
+
+ assert find_field("user[notifications_enabled]").value
+ uncheck "user[notifications_enabled]"
+
+ fill_in("user[current_password]", with: "password")
+
+ click_button I18n.t("devise.registrations.edit.update")
+
+ user.reload
+ refute user.notifications_enabled
+ end
end