diff --git a/app/controllers/emails_controller.rb b/app/controllers/emails_controller.rb index 5418289a8..d9b35a46e 100644 --- a/app/controllers/emails_controller.rb +++ b/app/controllers/emails_controller.rb @@ -21,7 +21,7 @@ class EmailsController < ApplicationController end if @user.errors.none? - flash[:notice] = "Email updated" + flash[:notice] = "Email updated. Check your email to confirm your new address" UserMailer.email_change_confirmation(@user).deliver_later respond_with(@user, location: settings_url) else @@ -31,10 +31,27 @@ class EmailsController < ApplicationController end def verify - @email_address = authorize EmailAddress.find_by_user_id!(params[:user_id]) - @email_address.update!(is_verified: true) + @user = User.find(params[:user_id]) + @email_address = @user.email_address - flash[:notice] = "Email address verified" - redirect_to @email_address.user + if @email_address.blank? + redirect_to edit_user_email_path(@user) + elsif params[:email_verification_key].present? + authorize @email_address + @email_address.update!(is_verified: true) + flash[:notice] = "Email address verified" + redirect_to @email_address.user + else + authorize @email_address + respond_with(@user) + end + end + + def send_confirmation + @user = authorize User.find(params[:user_id]), policy_class: EmailAddressPolicy + UserMailer.welcome_user(@user).deliver_later + + flash[:notice] = "Confirmation email sent to #{@user.email_address.address}. Check your email to confirm your address" + redirect_to @user end end diff --git a/app/javascript/src/javascripts/common.js b/app/javascript/src/javascripts/common.js index 03563a2f9..04e2af233 100644 --- a/app/javascript/src/javascripts/common.js +++ b/app/javascript/src/javascripts/common.js @@ -15,6 +15,12 @@ $(function() { e.preventDefault(); }); + $("#hide-verify-account-notice").on("click.danbooru", function(e) { + $("#verify-account-notice").hide(); + Cookie.put('hide_verify_account_notice', '1', 3); + e.preventDefault(); + }); + $("#close-notice-link").on("click.danbooru", function(e) { $('#notice').fadeOut("fast"); e.preventDefault(); diff --git a/app/models/user.rb b/app/models/user.rb index 89ab85e6e..be3db085d 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -267,6 +267,10 @@ class User < ApplicationRecord name.match?(/\Auser_[0-9]+~*\z/) end + def is_restricted? + requires_verification? && !is_verified? + end + def is_anonymous? level == Levels::ANONYMOUS end diff --git a/app/policies/email_address_policy.rb b/app/policies/email_address_policy.rb index 7122fa1f7..cd92232d1 100644 --- a/app/policies/email_address_policy.rb +++ b/app/policies/email_address_policy.rb @@ -9,6 +9,15 @@ class EmailAddressPolicy < ApplicationPolicy end def verify? - record.valid_key?(request.params[:email_verification_key]) + if request.params[:email_verification_key].present? + record.valid_key?(request.params[:email_verification_key]) + else + record.user_id == user.id + end + end + + def send_confirmation? + # XXX record is a user, not the email address. + record.id == user.id end end diff --git a/app/views/emails/edit.html.erb b/app/views/emails/edit.html.erb index aac9b0704..e2e0c311b 100644 --- a/app/views/emails/edit.html.erb +++ b/app/views/emails/edit.html.erb @@ -1,14 +1,26 @@ -<% page_title "Change Email" %> -
-
-

Change Email

+
+ <% if @user.email_address.present? %> + <% page_title "Change Email" %> +

Change Email

-

You must confirm your password in order to change your email address.

+

Your current email address is <%= @user.email_address.address %>. You must re-enter your password in order to update your email address.

+ <% else %> + <% page_title "Add Email" %> +

Add Email

+ +

Add a new email address below. You must re-enter your password in order to update your email address.

+ <% end %> + + <% if @user.is_restricted? %> +

Your account is restricted because you signed up from a VPN or proxy. + You can still use the site, but you won't be able to leave comments, edit + tags, or upload posts until you add a verified email address to your account.

+ <% end %> <%= edit_form_for(@user, url: user_email_path(@user)) do |f| %> + <%= f.input :email, as: :email, label: "New Email", input_html: { value: "" } %> <%= f.input :password %> - <%= f.input :email, as: :email, input_html: { value: "" } %> <%= f.submit "Save" %> <% end %>
diff --git a/app/views/emails/verify.html.erb b/app/views/emails/verify.html.erb new file mode 100644 index 000000000..5790b4f57 --- /dev/null +++ b/app/views/emails/verify.html.erb @@ -0,0 +1,20 @@ +<% page_title "Verify account" %> + +
+
+

Verify account

+ + <% if @user.is_restricted? %> +

Your account is restricted because you signed up from a VPN or proxy. + You can still use the site, but you won't be able to leave comments, edit + tags, or upload posts until you verify your account.

+ <% end %> + +

Click below to send an email to <%= @email_address.address %> + to verify your account.

+ + <%= edit_form_for(@user, method: :post, url: send_confirmation_user_email_path(@user)) do |f| %> + <%= f.submit "Send confirmation email" %> + <% end %> +
+
diff --git a/app/views/layouts/default.html.erb b/app/views/layouts/default.html.erb index d09e51a01..02268ee5a 100644 --- a/app/views/layouts/default.html.erb +++ b/app/views/layouts/default.html.erb @@ -68,6 +68,8 @@
+ <%= render "users/verification_notice" %> + <% if !CurrentUser.is_anonymous? && !CurrentUser.is_gold? && cookies[:hide_upgrade_account_notice].blank? && params[:action] != "upgrade_information" %> <%= render "users/upgrade_notice" %> <% end %> diff --git a/app/views/users/_verification_notice.html.erb b/app/views/users/_verification_notice.html.erb new file mode 100644 index 000000000..bd8ee22a4 --- /dev/null +++ b/app/views/users/_verification_notice.html.erb @@ -0,0 +1,10 @@ +<% if CurrentUser.user.is_restricted? && (params[:controller] == "users" || cookies[:hide_verify_account_notice].blank?) %> +
+

Your account is restricted.

+
+ You must verify your account because you signed up from a proxy or a VPN. + <%= link_to "Verify your account now", verify_user_email_path(CurrentUser.user) %>. +
+
<%= link_to "Close this", "#", id: "hide-verify-account-notice" %>
+
+<% end %> diff --git a/app/views/users/edit.html.erb b/app/views/users/edit.html.erb index 427004e6b..d77d82038 100644 --- a/app/views/users/edit.html.erb +++ b/app/views/users/edit.html.erb @@ -27,14 +27,14 @@

<% if @user.email_address.present? %> <%= @user.email_address.address %> - <% if !@user.email_address.is_verified %> - (unverified) - <% end %> - <% else %> - blank - <% end %> - - <%= link_to "Change your email", edit_user_email_path(@user) %> + (<%= link_to "Change email", edit_user_email_path(@user) %> + <% if !@user.email_address.is_verified %> + | <%= link_to "Verify email", verify_user_email_path(@user) %> + <% end %>) + <% else %> + <%= link_to "Add email", edit_user_email_path(@user) %> + <% end %>

diff --git a/config/routes.rb b/config/routes.rb index 38b8a87e7..94b6878d6 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -246,6 +246,7 @@ Rails.application.routes.draw do resources :favorite_groups, controller: "favorite_groups", only: [:index], as: "favorite_groups" resource :email, only: [:show, :edit, :update] do get :verify + post :send_confirmation end resource :password, only: [:edit, :update] resource :api_key, :only => [:show, :view, :update, :destroy], :controller => "maintenance/user/api_keys" do diff --git a/test/functional/emails_controller_test.rb b/test/functional/emails_controller_test.rb index 787857c30..ea42321fa 100644 --- a/test/functional/emails_controller_test.rb +++ b/test/functional/emails_controller_test.rb @@ -7,6 +7,7 @@ class EmailsControllerTest < ActionDispatch::IntegrationTest setup do @user = create(:user, email_address: build(:email_address, { address: "bob@ogres.net", is_verified: false })) @other_user = create(:user, email_address: build(:email_address, { address: "alice@ogres.net", is_verified: false })) + @restricted_user = create(:user, requires_verification: true, is_verified: false) end context "#show" do @@ -22,9 +23,36 @@ class EmailsControllerTest < ActionDispatch::IntegrationTest end context "#edit" do - should "render" do - get_auth edit_user_email_path(@user), @user - assert_response :success + context "for a user with an email address" do + should "render" do + get_auth edit_user_email_path(@user), @user + assert_equal true, @user.email_address.present? + assert_response :success + end + end + + context "for a user without an email address" do + should "render" do + @user.email_address.destroy! + get_auth edit_user_email_path(@user), @user + + assert_equal false, @user.email_address.present? + assert_response :success + end + end + + context "for a restricted user" do + should "render" do + get_auth edit_user_email_path(@restricted_user), @restricted_user + assert_response :success + end + end + + context "for an unauthorized user" do + should "render" do + get_auth edit_user_email_path(@user), @other_user + assert_response 403 + end end end @@ -109,6 +137,48 @@ class EmailsControllerTest < ActionDispatch::IntegrationTest assert_equal(false, @user.is_verified) end end + + context "for a user without an email address" do + should "redirect to the add email page" do + @user.email_address.destroy! + get_auth verify_user_email_path(@user), @user + assert_redirected_to edit_user_email_path(@user) + end + end + + context "for a user with an unverified email address" do + should "show the resend confirmation email page" do + get_auth verify_user_email_path(@user), @user + assert_response :success + end + end + + context "for an unauthorized user" do + should "fail" do + get_auth verify_user_email_path(@user), @other_user + assert_response 403 + end + end + end + + context "#send_confirmation" do + context "for an authorized user" do + should "resend the confirmation email" do + post_auth send_confirmation_user_email_path(@user), @user + + assert_redirected_to @user + assert_enqueued_emails 1 + end + end + + context "for an unauthorized user" do + should "fail" do + post_auth send_confirmation_user_email_path(@user), @other_user + + assert_response 403 + assert_no_enqueued_emails + end + end end end end