diff --git a/Gemfile b/Gemfile index bb944a6b1..638506882 100644 --- a/Gemfile +++ b/Gemfile @@ -13,6 +13,7 @@ gem 'pg', '~> 1.4' gem 'json_translate', '~> 4.0.0' gem 'devise', '~> 4.9.1' gem 'devise-i18n', '~> 1.11.0' +gem 'invisible_captcha', '~> 2.3.0' gem 'http_accept_language', '~> 2.1.1' gem 'kaminari', '~> 1.2.1' gem 'simple_form', '~> 5.0.2' diff --git a/Gemfile.lock b/Gemfile.lock index dfe6a6612..c36831f54 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -183,6 +183,8 @@ GEM has_scope (>= 0.6) railties (>= 6.0) responders (>= 2) + invisible_captcha (2.3.0) + rails (>= 5.2) jmespath (1.6.2) jquery-rails (4.4.0) rails-dom-testing (>= 1, < 3) @@ -450,6 +452,7 @@ DEPENDENCIES has_scope (~> 0.7.2) http_accept_language (~> 2.1.1) image_processing (~> 1.12) + invisible_captcha (~> 2.3.0) jquery-rails (~> 4.4.0) json_translate (~> 4.0.0) kaminari (~> 1.2.1) diff --git a/README.md b/README.md index ea489cd52..8cc6d8fb0 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,7 @@ of it and is prepared to be able to accommodate several Time Banks in a single i for this account with three levels of privileges: superadmin, admin (only manages a bank) and members of a bank. -![Users list](docs/images/usuarios.png) -![Offers list](docs/images/ofertas.png) +![Demo UI](docs/images/demo_ui.jpeg) TimeOverflow is divided into 2 large blocks: diff --git a/app/admin/user.rb b/app/admin/user.rb index fe8ec828c..dc0de5e09 100644 --- a/app/admin/user.rb +++ b/app/admin/user.rb @@ -1,4 +1,6 @@ ActiveAdmin.register User do + config.batch_actions = true + action_item :upload_csv, only: :index do link_to I18n.t("active_admin.users.upload_from_csv"), action: "upload_csv" end @@ -15,6 +17,7 @@ end index do + selectable_column column do |user| link_to image_tag(avatar_url(user, 24)), admin_user_path(user) end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 689adef37..1f83741fe 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -3,6 +3,8 @@ class UsersController < ApplicationController before_action :user_should_be_confirmed, except: %i[signup create please_confirm] before_action :member_should_exist_and_be_active, except: %i[signup create edit show update please_confirm] + invisible_captcha only: :create, if: -> { params[:from_signup].present? } + has_scope :tagged_with, as: :tag def index diff --git a/app/jobs/organization_notifier_job.rb b/app/jobs/organization_notifier_job.rb index e8949bba6..e8d7ec650 100644 --- a/app/jobs/organization_notifier_job.rb +++ b/app/jobs/organization_notifier_job.rb @@ -1,7 +1,7 @@ # A weekly digest email. # # Strategy: go throught all organizations and take latest active posts from last week -# posted by active members. Send an email to all active and online members +# posted by active members. Send an email to all confirmed, active and online members # with the email notifications enabled with those posts. Group emails by user's locale. # Schedule defined in config/schedule.yml file. @@ -24,11 +24,11 @@ def perform private def users_by_locale(organization) - with_notifications = organization.users.online_active.actives.notifications - org_locales = with_notifications.pluck(:locale).uniq + org_users = organization.users.online_active.actives.confirmed.notifications + org_locales = org_users.pluck(:locale).uniq org_locales.each_with_object({}) do |locale, hash| - hash[locale] = with_notifications.where(locale: locale) + hash[locale] = org_users.where(locale: locale) end end end diff --git a/app/mailers/organization_notifier.rb b/app/mailers/organization_notifier.rb index 761ebaf34..5827711f5 100644 --- a/app/mailers/organization_notifier.rb +++ b/app/mailers/organization_notifier.rb @@ -2,7 +2,6 @@ class OrganizationNotifier < ActionMailer::Base default from: "\"TimeOverflow\" " def recent_posts(posts, locale, users) - # last 10 posts of offers and inquiries @offers = posts.where(type: "Offer").take(10) @inquiries = posts.where(type: "Inquiry").take(10) diff --git a/app/models/user.rb b/app/models/user.rb index 49f462f19..2877fb8e2 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -41,6 +41,7 @@ class User < ApplicationRecord scope :actives, -> { joins(:members).where(members: { active: true }) } scope :online_active, -> { where("sign_in_count > 0") } scope :notifications, -> { where(notifications: true) } + scope :confirmed, -> { where.not(confirmed_at: nil) } validates :username, presence: true validates :email, presence: true, uniqueness: true diff --git a/app/views/users/_form.html.erb b/app/views/users/_form.html.erb index 56118ff56..02a25a05b 100644 --- a/app/views/users/_form.html.erb +++ b/app/views/users/_form.html.erb @@ -1,6 +1,7 @@ <%= show_error_messages!(@user) %> <%= simple_form_for @user do |f| %> <%= f.hidden_field :locale, value: I18n.locale %> + <%= invisible_captcha %>
<%= f.input :username %> diff --git a/config/initializers/active_admin.rb b/config/initializers/active_admin.rb index 135f86fa6..7cfbf91f4 100644 --- a/config/initializers/active_admin.rb +++ b/config/initializers/active_admin.rb @@ -7,7 +7,6 @@ config.current_user_method = :current_user config.logout_link_path = :destroy_user_session_path config.logout_link_method = :delete - config.batch_actions = false config.comments = false config.namespace :admin do |admin| admin.build_menu :utility_navigation do |menu| diff --git a/config/initializers/invisible_captcha.rb b/config/initializers/invisible_captcha.rb new file mode 100644 index 000000000..30eeb9efc --- /dev/null +++ b/config/initializers/invisible_captcha.rb @@ -0,0 +1,4 @@ +InvisibleCaptcha.setup do |config| + config.timestamp_enabled = !Rails.env.test? + config.spinner_enabled = !Rails.env.test? +end diff --git a/docs/images/demo_ui.jpeg b/docs/images/demo_ui.jpeg new file mode 100644 index 000000000..4e07880b0 Binary files /dev/null and b/docs/images/demo_ui.jpeg differ diff --git a/docs/images/ofertas.png b/docs/images/ofertas.png deleted file mode 100644 index ce64f5afa..000000000 Binary files a/docs/images/ofertas.png and /dev/null differ diff --git a/docs/images/usuarios.png b/docs/images/usuarios.png deleted file mode 100644 index 0b8b82e2d..000000000 Binary files a/docs/images/usuarios.png and /dev/null differ diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb index b715a4f9a..ce5d6f76c 100644 --- a/spec/controllers/users_controller_spec.rb +++ b/spec/controllers/users_controller_spec.rb @@ -441,8 +441,8 @@ let(:uploaded_file) do Rack::Test::UploadedFile.new( - Rails.root.join("docs/images/ofertas.png"), - "image/png" + Rails.root.join("docs/images/demo_ui.jpeg"), + "image/jpeg" ) end diff --git a/spec/mailers/organization_notifier_spec.rb b/spec/mailers/organization_notifier_spec.rb index 039c0266f..89b85bd03 100644 --- a/spec/mailers/organization_notifier_spec.rb +++ b/spec/mailers/organization_notifier_spec.rb @@ -2,7 +2,7 @@ let(:test_organization) { Fabricate(:organization) } let!(:offer) { Fabricate(:offer, organization: test_organization) } let!(:inquiry) { Fabricate(:inquiry, organization: test_organization) } - let(:user) { Fabricate(:user, email: "user@example.com", locale: :en) } + let(:user) { Fabricate(:user, email: "user@timeoverflow.org", locale: :en) } let(:member) { Fabricate(:member, organization: test_organization, user: user) } describe "send an email" do @@ -17,7 +17,7 @@ let(:mail) { OrganizationNotifier.recent_posts(test_organization.posts, :en, [user]) } it "receive email only active and online users" do - expect(mail.bcc).to eql(["user@example.com"]) + expect(mail.bcc).to eql(["user@timeoverflow.org"]) end it "to should be null" do expect(mail.to).to be_nil