Skip to content

Commit

Permalink
added countdown for mobile confirmation
Browse files Browse the repository at this point in the history
  • Loading branch information
Oleg Hasjanov authored and Oleg Hasjanov committed Feb 12, 2024
1 parent c4b140c commit 8e79fcb
Show file tree
Hide file tree
Showing 16 changed files with 179 additions and 28 deletions.
21 changes: 0 additions & 21 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,15 +1,3 @@
# FROM internetee/ruby:3.0-buster

# RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install wkhtmltopdf -y > /dev/null

# RUN npm install -g yarn@latest
# WORKDIR /opt/webapps/app
# COPY Rakefile Gemfile Gemfile.lock ./
# RUN gem install bundler && bundle install --jobs 20 --retry 5
# COPY package.json yarn.lock ./
# RUN yarn install --check-files


FROM internetee/ruby:3.2.2

SHELL ["/bin/bash", "-o", "pipefail", "-c"]
Expand Down Expand Up @@ -69,15 +57,6 @@ RUN apt-get install -y --no-install-recommends > /dev/null \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

# RUN curl https://chromedriver.storage.googleapis.com/2.46/chromedriver_linux64.zip -o /chromedriver_linux64.zip
# RUN apt-get update > /dev/null \
# && apt-get install -yf --no-install-recommends > /dev/null unzip=* \
# && apt-get clean \
# && rm -rf /var/lib/apt/lists/*
# RUN unzip chromedriver_linux64.zip -d /usr/local/bin
# RUN rm /chromedriver_linux64.zip

# RUN npm install --global yarn
RUN npm install -g yarn@latest

RUN curl https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb -o /chrome.deb
Expand Down
3 changes: 3 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,8 @@ GEM
net-smtp (0.3.3)
net-protocol
nio4r (2.7.0)
nokogiri (1.15.2-arm64-darwin)
racc (~> 1.4)
nokogiri (1.15.2-x86_64-linux)
racc (~> 1.4)
noticed (1.6.3)
Expand Down Expand Up @@ -454,6 +456,7 @@ GEM
zeitwerk (2.6.8)

PLATFORMS
arm64-darwin-23
x86_64-linux

DEPENDENCIES
Expand Down
32 changes: 32 additions & 0 deletions app/controllers/phone_confirmations/send_sms_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
class PhoneConfirmations::SendSmsController < ApplicationController
before_action :authenticate_user!
before_action :set_phone_confirmation
before_action :authorize_user

include RecaptchaValidatable
recaptcha_action 'phone_confirmation'

def create
if current_user.allow_to_send_sms_again? && recaptcha_valid
PhoneConfirmationJob.perform_now(@phone_confirmation.user.id)

flash[:notice] = I18n.t('phone_confirmations.create.sms_sent')
else
flash[:alert] = I18n.t('phone_confirmations.create.sms_not_sent')
end

@show_checkbox_recaptcha = true unless @success

redirect_to new_user_phone_confirmation_path(@phone_confirmation.user.uuid), status: :see_other, turbo: false
end

private

def set_phone_confirmation
@phone_confirmation = PhoneConfirmation.new(current_user)
end

def authorize_user
authorize! :manage, PhoneConfirmation
end
end
5 changes: 3 additions & 2 deletions app/controllers/phone_confirmations_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ class PhoneConfirmationsController < ApplicationController
before_action :set_phone_confirmation
before_action :authorize_user

include RecaptchaValidatable
recaptcha_action 'phone_confirmation'

def new
if @phone_confirmation.confirmed?
redirect_to user_path(@phone_confirmation.user.uuid), notice: t('.already_confirmed')
elsif @phone_confirmation.user.not_phone_number_confirmed_unique?
redirect_to user_path(@phone_confirmation.user.uuid)
else
PhoneConfirmationJob.perform_later(@phone_confirmation.user.id)
end
end

Expand Down
5 changes: 5 additions & 0 deletions app/helpers/phone_confirmations_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module PhoneConfirmationsHelper
def render_send_in_button?
Setting.find_by(code: 'require_phone_confirmation').retrieve && current_user.mobile_phone_confirmed_at.nil? && current_user.mobile_phone.present?
end
end
5 changes: 4 additions & 1 deletion app/models/phone_confirmation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,20 @@
class PhoneConfirmation
attr_reader :user

TIME_LIMIT = 1.minutes

def initialize(user)
@user = user
end

def generate_and_send_code
return unless user.valid?
return if user.mobile_phone_confirmed_sms_send_at.present? && user.mobile_phone_confirmed_sms_send_at > TIME_LIMIT.ago

number = SecureRandom.random_number(10_000)
padded_number = format('%04d', number)

user.update!(mobile_phone_confirmation_code: padded_number)
user.update!(mobile_phone_confirmation_code: padded_number, mobile_phone_confirmed_sms_send_at: Time.zone.now)
message_sender = Messente::Omnimessage.new(
user.mobile_phone,
I18n.t('phone_confirmations.instructions', code: padded_number)
Expand Down
6 changes: 6 additions & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -225,4 +225,10 @@ def participated_in_english_auction?(auction)

auction.offers.any? { |offer| offer.user == self } || auction.domain_participate_auctions.any? { |p| p.user == self }
end

def allow_to_send_sms_again?
return true if mobile_phone_confirmed_sms_send_at.blank?

mobile_phone_confirmed_sms_send_at < PhoneConfirmation::TIME_LIMIT.ago
end
end
2 changes: 2 additions & 0 deletions app/packs/entrypoints/controllers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,5 @@ import CookieController from "./cookie_controller"
application.register("cookie", CookieController)
import AuctionTimezoneController from "./auction_timezone_controller"
application.register("auction-timezone", AuctionTimezoneController)
import TimeleftController from "./timeleft_controller"
application.register("timeleft", TimeleftController)
74 changes: 74 additions & 0 deletions app/packs/entrypoints/controllers/timeleft_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
static values = {
date: String,
refreshInterval: { type: Number, default: 1000 },
messageTimer: String,
defaultMessageTimer: String
}

static targets = [ "button" ]

connect() {
this.update = this.update.bind(this);

if (this.dateValue) {
this.endTime = new Date(this.dateValue).getTime();

this.update();

this.timer = setInterval(() => {
this.update();
}, this.refreshIntervalValue);
} else {
console.log("Missing data-timeleft-date-value attribute", this.element);
}
}

disconnect() {
this.stopTimer();
}

stopTimer() {
if(this.timer) {
clearInterval(this.timer);
}
}

update() {
let difference = this.timeDifference();

if (difference < 0) {
var expiredMsg = $("#timer_message").data("expiredMessage");
$("#timer_message").html(expiredMsg);
this.stopTimer();
this.buttonTarget.removeAttribute("disabled");
this.buttonTarget.innerHTML = this.defaultMessageTimerValue;
} else {
this.buttonTarget.setAttribute("disabled", "disabled");

let minutes = Math.floor((difference % (1000 * 60 * 60)) / (1000 * 60));
let seconds = Math.floor((difference % (1000 * 60)) / 1000);

this.buttonTarget.innerHTML = `${this.messageTimerValue} ${minutes}:${seconds}`
}
}

timeDifference() {
const convertedToTimeZone = this.convertDateToTimeZone(new Date().getTime(), 'Europe/Tallinn');
return this.endTime - new Date(convertedToTimeZone).getTime();
}

convertDateToTimeZone(date, timeZone) {
return new Intl.DateTimeFormat('en-US', {
timeZone: timeZone,
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
}).format(date);
}
}
27 changes: 25 additions & 2 deletions app/views/phone_confirmations/new.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,34 @@
</div>
<% end %>

<div class="u-container">
<div class="u-container" data-controller='timeleft'
data-timeleft-date-value="<%= I18n.l(current_user.mobile_phone_confirmed_sms_send_at + PhoneConfirmation::TIME_LIMIT) %>"
data-timeleft-refresh-interval-value="500" data-timeleft-message-timer-value="<%= I18n.t('phone_confirmations.new.send_again') %>"
data-timeleft-default-message-timer-value="<%= I18n.t('phone_confirmations.new.send_code') %>">
<div class="u-container margin-block">
<h3><%= t('.subheader' , number: @phone_confirmation.user.mobile_phone )%></h3>
<p><%= t('.instructions', number: @phone_confirmation.user.mobile_phone )%></p>

<%= render 'form', phone_confirmation: @phone_confirmation, url: user_phone_confirmations_path %>
<%= render 'form', phone_confirmation: @phone_confirmation, url: user_phone_confirmations_path %><br />

<% if current_user.allow_to_send_sms_again? %>
<%= button_to I18n.t('phone_confirmations.new.send_code'), send_sms_user_phone_confirmations_path, class: "ui button primary", data: { timeleft_target: 'button' } %>
<% else %>
<%= button_to I18n.t('phone_confirmations.new.send_again'), send_sms_user_phone_confirmations_path, class: "ui button primary", data: { timeleft_target: 'button' }, disabled: true %>
<% end if render_send_in_button? %>

<div class="column">
<% if @captcha_required %>
<% if @show_checkbox_recaptcha %>
<div class="field">
<br>
<%= recaptcha_tags id: 'english_offer', site_key: @recaptcha2_site_key %>
</div>
<% else %>
<%= recaptcha_v3(action: 'english_offer', site_key: @recaptcha3_site_key, turbolinks: true) %>
<% end %>
<% end %>
</div>

</div>
</div>
2 changes: 2 additions & 0 deletions config/customization.yml.sample
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ default: &default
vapid_public: "BGgFbsalgk-emt7f0f279JsxF15NOfEJKQ-7w04FmXseeWt4pRvCaD7EMl6PqS-BHrwO3QWsPUOGkAjNWNBOVLY="
vapid_private: "2xl1lvaQARjFHRCKrPo2B-MbTAc1IZ3UrfugDh6cJiE="

mobile_sms_sent_time_limit_in_minutes: 5

mailer:
# Host to which links from emails should redirect to
host: 'https://auction.example.test'
Expand Down
5 changes: 5 additions & 0 deletions config/locales/phone_confirmations.en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ en:
Enter it below and click submit to confirm your mobile phone.
It can take up to a few minutes for the code to be delivered.
already_confirmed: "Your phone number has already been confirmed."
send_again: Send the code via
send_code: Send the code

create:
confirmed: "Your phone number has been confirmed. You can now submit offers."

sms_sent: The code was sent to your phone number.
sms_not_sent: The code was not sent, please try again.
5 changes: 5 additions & 0 deletions config/locales/phone_confirmations.et.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ et:
Sisesta kood siia ja klõpsa „esita“ mobiilinumbri kinnitamiseks.
Koodi saatmine võib võtta mitu minutit
already_confirmed: "Sinu telefoninumber on juba kinnitatud."
send_again: Saada kood läbi.
send_code: Saada kood.

create:
confirmed: "Sinu telefoninumber on kinnitatud. Võid esitada pakkumusi."

sms_sent: Kood saadeti teie telefoninumbrile.
sms_not_sent: Koodi ei saadetud, palun proovige uuesti.
6 changes: 5 additions & 1 deletion config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,11 @@
resources :results, only: :show, param: :uuid

resources :users, param: :uuid do
resources :phone_confirmations, only: %i[new create]
resources :phone_confirmations, only: %i[new create] do
scope module: :phone_confirmations do
post :send_sms, to: 'send_sms#create', on: :collection
end
end
end

resources :wishlist_items, param: :uuid, only: %i[index edit create destroy update]
Expand Down
5 changes: 5 additions & 0 deletions db/migrate/20240209111309_add_sms_send_timestamp_to_users.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddSmsSendTimestampToUsers < ActiveRecord::Migration[7.0]
def change
add_column :users, :mobile_phone_confirmed_sms_send_at, :datetime
end
end
4 changes: 3 additions & 1 deletion db/structure.sql
Original file line number Diff line number Diff line change
Expand Up @@ -1632,6 +1632,7 @@ CREATE TABLE public.users (
daily_summary boolean DEFAULT false NOT NULL,
jti character varying,
reference_no character varying,
mobile_phone_confirmed_sms_send_at timestamp(6) without time zone,
CONSTRAINT users_roles_are_known CHECK ((roles <@ ARRAY['participant'::character varying, 'administrator'::character varying]))
);

Expand Down Expand Up @@ -3192,6 +3193,7 @@ INSERT INTO "schema_migrations" (version) VALUES
('20231031122216'),
('20231116093310'),
('20231222074427'),
('20231222085647');
('20231222085647'),
('20240209111309');


0 comments on commit 8e79fcb

Please sign in to comment.