diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 00000000..4a9c19cb --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +v14.21.3 diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 00000000..974865fc --- /dev/null +++ b/.tool-versions @@ -0,0 +1 @@ +ruby 2.7.6 diff --git a/Gemfile b/Gemfile index d3e03f52..dadd465e 100644 --- a/Gemfile +++ b/Gemfile @@ -19,6 +19,7 @@ gem 'friendly_id', '~> 5.3.0' # 5.4.0 has a breaking change! https://github.com/ gem 'geocoder' gem 'groupdate' gem 'image_processing' +gem 'invisible_captcha', '~> 2.1' gem 'mailgun-ruby' gem 'mini_magick' gem 'omniauth-fablabs', github: 'academany/omniauth-fablabs' diff --git a/Gemfile.lock b/Gemfile.lock index 0248a422..c7be7fae 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -218,6 +218,8 @@ GEM has_scope (~> 0.6) railties (>= 5.2, < 6.2) responders (>= 2, < 4) + invisible_captcha (2.1.0) + rails (>= 5.2) jbuilder (2.10.0) activesupport (>= 5.0.0) jmespath (1.6.1) @@ -470,6 +472,7 @@ DEPENDENCIES guard-minitest i18n-tasks image_processing + invisible_captcha (~> 2.1) jbuilder (~> 2.7) listen (>= 3.0.5, < 3.2) mailgun-ruby diff --git a/README.md b/README.md index 26d5fdee..5d65b254 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,26 @@ Staging web server: - http://staging.make.works/ - https://staging-makeworks.herokuapp.com/ +### Getting started locally +- Install Ruby 2.7.6 with your version manager of choice: + `asdf install ruby 2.7.6; asdf local ruby 2.7.6` for asdf +- Install bundled gems: + `bundle install` +- Setup the database: + `bundle exec rake db:create && bundle exec rake db:schema:load` +- Install Node 14.21.2: + `nvm install 14.21.2; nvm use 14.21.2` for nvm +- Install Yarn dependencies: + `yarn install --check-files` +- Ensure ActionText is installed: + `bundle exec rails action_text install` +- Install chromedriver for system tests: + `brew install chromedriver` for homebrew on Mac OS X +- Run tests and check they pass: + `bundle exec rails test && bundle exec rails test:system` +- Run the development server: + `bundle exec rails server` + ### Development * Run tests with `rails test` diff --git a/app/controllers/users/registrations_controller.rb b/app/controllers/users/registrations_controller.rb new file mode 100644 index 00000000..dcf786f1 --- /dev/null +++ b/app/controllers/users/registrations_controller.rb @@ -0,0 +1,3 @@ +class Users::RegistrationsController < Devise::RegistrationsController + invisible_captcha only: [:create] +end \ No newline at end of file diff --git a/app/models/user.rb b/app/models/user.rb index eafa6aaf..74512321 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -2,7 +2,7 @@ class User < ApplicationRecord # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable and :omniauthable devise :database_authenticatable, :registerable, - :invitable, + :invitable, :confirmable, :recoverable, :rememberable, :validatable, :trackable, :omniauthable, diff --git a/app/views/devise/registrations/new.html.erb b/app/views/devise/registrations/new.html.erb index f39fcfb4..b66d3370 100644 --- a/app/views/devise/registrations/new.html.erb +++ b/app/views/devise/registrations/new.html.erb @@ -12,7 +12,7 @@ <%= simple_form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %> <%= f.error_notification %> - + <%= invisible_captcha %>
<%= f.input :email, required: true, diff --git a/app/views/devise/shared/_links.html.erb b/app/views/devise/shared/_links.html.erb index 201d6e79..210a9638 100644 --- a/app/views/devise/shared/_links.html.erb +++ b/app/views/devise/shared/_links.html.erb @@ -19,9 +19,13 @@ <% end %> <%- if devise_mapping.confirmable? && controller_name != 'confirmations' %> - <%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name), class: 'text-danger my-3' %>
+

+ <%= link_to "Didn't receive confirmation instructions?", new_user_confirmation_path(resource_name), class: 'text-danger my-3' %>
+

<% end %> <%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %> +

<%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name), class: 'btn btn-outline-dark my-3' %>
+

<% end %> diff --git a/config/environments/test.rb b/config/environments/test.rb index 93ed4f1b..6dd14aa9 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -7,6 +7,7 @@ Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. + config.assets.compile = true config.cache_classes = false config.action_view.cache_template_loading = true @@ -57,4 +58,6 @@ # Annotate rendered view with file names. # config.action_view.annotate_rendered_view_with_filenames = true + + Rails.application.routes.default_url_options[:host]= 'localhost:50500' end diff --git a/config/routes.rb b/config/routes.rb index 77631708..d4498f09 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -3,7 +3,8 @@ ActiveAdmin.routes(self) devise_for :users, controllers: { - omniauth_callbacks: 'omniauth_callbacks' + omniauth_callbacks: 'omniauth_callbacks', + registrations: 'users/registrations' } # Redirect rules to help the old web to new web migration diff --git a/db/migrate/20231201122728_add_confirmable_to_devise.rb b/db/migrate/20231201122728_add_confirmable_to_devise.rb new file mode 100644 index 00000000..be7647f6 --- /dev/null +++ b/db/migrate/20231201122728_add_confirmable_to_devise.rb @@ -0,0 +1,9 @@ +class AddConfirmableToDevise < ActiveRecord::Migration[6.1] + def change + add_column :users, :confirmation_token, :string + add_column :users, :confirmed_at, :datetime + add_column :users, :confirmation_sent_at, :datetime + add_column :users, :unconfirmed_email, :string + execute "UPDATE users SET confirmed_at = NOW()" + end +end diff --git a/db/schema.rb b/db/schema.rb index 8bc4db54..b61a859d 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: 2021_08_23_135033) do +ActiveRecord::Schema.define(version: 2023_12_01_122728) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -429,6 +429,10 @@ t.string "invited_by_type" t.bigint "invited_by_id" t.integer "invitations_count", default: 0 + t.string "confirmation_token" + t.datetime "confirmed_at" + t.datetime "confirmation_sent_at" + t.string "unconfirmed_email" 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" diff --git a/package.json b/package.json index 863b8bb0..74479c8d 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,6 @@ "webpack-dev-server": "^3.11.2" }, "engines" : { - "node": "14.21.2" + "node": "14.21.3" } } diff --git a/test/controllers/users_controller_test.rb b/test/controllers/users_controller_test.rb index dbb5d76b..30c5f3c1 100644 --- a/test/controllers/users_controller_test.rb +++ b/test/controllers/users_controller_test.rb @@ -40,8 +40,7 @@ class UsersControllerTest < ActionDispatch::IntegrationTest test "should update user" do patch user_url(@user), params: { user: { email: @user.email, first_name: @user.first_name, is_admin: @user.is_admin, last_name: @user.last_name, m_id: @user.m_id } } - assert_response :success - #assert_redirected_to user_url(@user) + assert_redirected_to user_url(@user) end test "should destroy user" do diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml index 32cec5a2..d32fec0d 100644 --- a/test/fixtures/users.yml +++ b/test/fixtures/users.yml @@ -3,9 +3,10 @@ one: m_id: MyString email: admin@admin.com - first_name: Admin + first_name: Administrator last_name: Adminson is_admin: true + confirmed_at: 2023-12-01T14:00:00Z two: m_id: MyString @@ -13,3 +14,4 @@ two: first_name: normal last_name: normalson is_admin: false + confirmed_at: 2023-12-01T14:00:00Z diff --git a/test/system/login_test.rb b/test/system/login_test.rb new file mode 100644 index 00000000..ad8dfb3f --- /dev/null +++ b/test/system/login_test.rb @@ -0,0 +1,40 @@ +require "application_system_test_case" + +class SignUpTest < ApplicationSystemTestCase + setup do + @user = users(:one) + @user.password = "password123" + @user.password_confirmation = "password123" + @user.save! + logout + end + + test "Confirmed user logs in" do + visit new_user_session_url + + fill_in "Email", with: @user.email + fill_in "Password", with: "password123" + + within "#new_user" do + click_on "Log in" + end + + assert_text "Signed in successfully." + end + + test "Unconfirmed user logs in" do + @user.confirmed_at = nil + @user.save! + + visit new_user_session_url + + fill_in "Email", with: @user.email + fill_in "Password", with: "password123" + + within "#new_user" do + click_on "Log in" + end + + assert_text "You have to confirm your email address before continuing." + end +end \ No newline at end of file diff --git a/test/system/sign_up_test.rb b/test/system/sign_up_test.rb new file mode 100644 index 00000000..6b68178d --- /dev/null +++ b/test/system/sign_up_test.rb @@ -0,0 +1,20 @@ +require "application_system_test_case" + +class SignUpTest < ApplicationSystemTestCase + test "Signing up" do + logout + visit new_user_registration_url + + fill_in "Email", with: "user@example.com" + fill_in "Password", with: "password123", match: :prefer_exact + fill_in "Password confirmation", with: "password123" + sleep 4 # The invisible_captcha bot protection will kick in if this is too quick + click_on "Get Started" + + user = User.last + assert_equal user.email, "user@example.com" + + visit user_confirmation_url(confirmation_token: user.confirmation_token) + assert_text "Your email address has been successfully confirmed." + end +end \ No newline at end of file