Skip to content

Commit

Permalink
Merge branch 'master' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
luciegrau authored Sep 18, 2024
2 parents 2c04227 + 40338a1 commit d609ab2
Show file tree
Hide file tree
Showing 10 changed files with 161 additions and 6 deletions.
6 changes: 6 additions & 0 deletions .env-example
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,14 @@ DECIDIM_ADMIN_PASSWORD_STRONG="false"
# VAPID_PRIVATE_KEY

# NOTIFICATIONS_SENDING_FREQUENCY=daily
## SMS Gateway Service (eg: decidim-half_signup)
# SMS_GATEWAY_SERVICE="Decidim::SmsGatewayService"
# SMS_GATEWAY_URL="https://sms.gateway.service/api"
# SMS_GATEWAY_BULK_URL="https://sms.gateway.service/api/bulk"
# SMS_GATEWAY_USERNAME=
# SMS_GATEWAY_PASSWORD=
## Set to replace the organization name
# SMS_GATEWAY_PLATFORM="hashimoto.local"

# Delay until a user is considered inactive and receive a warning email (in days)
DECIDIM_CLEANER_INACTIVE_USERS_MAIL=
Expand Down
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ gem "faker", "~> 2.14"
gem "fog-aws"
gem "foundation_rails_helper", git: "https://github.com/sgruhier/foundation_rails_helper.git"
gem "letter_opener_web", "~> 1.3"
gem "multipart-post"
gem "nokogiri", "1.13.4"
gem "omniauth-rails_csrf_protection", "~> 1.0"
gem "puma", ">= 5.5.1"
Expand Down
2 changes: 2 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -740,6 +740,7 @@ GEM
msgpack (1.7.2)
multi_json (1.15.0)
multi_xml (0.6.0)
multipart-post (2.4.1)
mustache (1.1.1)
net-http (0.4.1)
uri
Expand Down Expand Up @@ -1161,6 +1162,7 @@ DEPENDENCIES
letter_opener_web (~> 1.3)
listen (~> 3.1)
lograge
multipart-post
nokogiri (= 1.13.4)
omniauth-france_connect!
omniauth-publik!
Expand Down
22 changes: 17 additions & 5 deletions app/services/decidim/sms_gateway_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@ module Decidim
class SmsGatewayService
attr_reader :mobile_phone_number, :code

def initialize(mobile_phone_number, code)
def initialize(mobile_phone_number, code, sms_gateway_context = {})
Rails.logger.debug { "#{mobile_phone_number} - #{code}" }

@mobile_phone_number = mobile_phone_number
@code = code
@url = "https://ssl.etoilediese.fr/envoi/sms/envoi.php"
@username = ENV.fetch("SMS_GATEWAY_USERNAME", nil)
@password = ENV.fetch("SMS_GATEWAY_PASSWORD", nil)
@organization_name = sms_gateway_context[:organization]&.name
@url = fetch_configuration(:url)
@username = fetch_configuration(:username)
@password = fetch_configuration(:password)
@message = sms_message
@type = "sms"
end
Expand All @@ -33,7 +34,18 @@ def deliver_code
def sms_message
return code if code.to_s.length > Decidim::HalfSignup.auth_code_length

I18n.t("sms_verification_workflow.message", code: code)
platform = fetch_configuration(:platform, required: false).presence || @organization_name
I18n.t("sms_verification_workflow.message", code: code, platform: platform)
end

def fetch_configuration(key, required: true)
value = Rails.application.secrets.dig(:decidim, :sms_gateway, key.to_sym)
if required && value.blank?
Rails.logger.error "Decidim::SmsGatewayService is missing a configuration value for :#{key}, " \
"please check Rails.application.secrets.dig(:decidim, :sms_gateway, :#{key}) " \
"or environment variable SMS_GATEWAY_#{key.to_s.upcase}"
end
value
end
end
end
2 changes: 1 addition & 1 deletion config/initializers/decidim.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
Decidim.configure do |config|
config.application_name = "OSP Agora"
config.mailer_sender = "OSP Agora <[email protected]>"
config.sms_gateway_service = "Decidim::SmsGatewayService"
config.sms_gateway_service = Rails.application.secrets.dig(:decidim, :sms_gateway, :service)

# Change these lines to set your preferred locales
if Rails.env.production?
Expand Down
2 changes: 2 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ en:
osp_authorization_workflow:
name: Authorization procedure
budgets:
order_reminder:
text_message: Your vote for my ideas for my neighborhood is not over. To finish it, go to %{organization_host} to confirm it
projects:
count:
projects_count:
Expand Down
2 changes: 2 additions & 0 deletions config/locales/fr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ fr:
osp_authorization_workflow:
name: Procédure d'autorisation
budgets:
order_reminder:
text_message: Votre vote pour mes idées pour mon quartier n'est pas terminé. Pour le terminer, rendez-vous sur %{organization_host}
projects:
count:
projects_count:
Expand Down
7 changes: 7 additions & 0 deletions config/secrets.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@ default: &default
throttle:
max_requests: <%= ENV["THROTTLING_MAX_REQUESTS"]&.to_i || 100 %>
period: <%= ENV["THROTTLING_PERIOD"]&.to_i || 60 %>
sms_gateway:
service: <%= ENV.fetch("SMS_GATEWAY_SERVICE", "Decidim::Verifications::Sms::ExampleGateway") %>
url: <%= ENV["SMS_GATEWAY_URL"] %>
bulk_url: <%= ENV["SMS_GATEWAY_BULK_URL"] %>
username: <%= ENV["SMS_GATEWAY_USERNAME"] %>
password: <%= ENV["SMS_GATEWAY_PASSWORD"] %>
platform: <%= ENV["SMS_GATEWAY_PLATFORM"] %>
modules:
gallery:
enable_animation: <%= ENV.fetch("GALLERY_ANIMATION_ENABLE", "0") == "1" %>
Expand Down
68 changes: 68 additions & 0 deletions lib/tasks/decidim_app.rake
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# frozen_string_literal: true

require "net/http/post/multipart"
require "tempfile"
require "decidim_app/k8s/configuration_exporter"
require "decidim_app/k8s/organization_exporter"
require "decidim_app/k8s/manager"
Expand Down Expand Up @@ -78,4 +80,70 @@ namespace :decidim_app do
DecidimApp::K8s::Manager.run(ENV.fetch("path", nil))
end
end

namespace :budgets do
# This task is used to send a reminder by sms to voters who haven't finished their
# vote for a budget. When you launch the task, you have to pass the id of the budget
# in a variable in terminal
desc "send a reminder to vote for budget"
task send_sms_reminder: :environment do
if (budget_id = ENV.fetch("BUDGET_ID")).nil?
p "You need to provide a budget ID"
next
end

if (budget = Decidim::Budgets::Budget.find_by(id: budget_id)).nil?
p "Budget with id #{budget_id} not found"
next
end

organization = budget.organization

users_ids = Decidim::Budgets::Order.where(budget: budget)
.pending
&.pluck(:decidim_user_id)
if users_ids.empty?
p "no pending votes"
next
end
users = Decidim::User.where(id: users_ids).where.not(phone_number: nil, phone_country: nil)

if users.blank?
p "no pending votes from users with phone number"
next
end

filename = "send_sms_reminder_#{Time.current.year}_#{Time.current.month}_#{Time.current.day}_#{Time.current.min}.csv"
message = I18n.t("decidim.budgets.order_reminder.text_message", locale: organization.default_locale, organization_host: organization.host)

file = Tempfile.new(filename)
CSV.open(file, "w", col_sep: ";") do |csv|
users.each do |user|
csv << ["#{user.phone_country}#{user.phone_number}", message]
end
end
file.rewind

p "users ids: #{users.ids}"
p "csv done at #{filename}"
api_url = Rails.application.secrets.dig(:decidim, :sms_gateway, :bulk_url)
username = Rails.application.secrets.dig(:decidim, :sms_gateway, :username)
password = Rails.application.secrets.dig(:decidim, :sms_gateway, :password)

url = URI(api_url)
request = Net::HTTP::Post::Multipart.new(url, {
u: username,
p: password,
f: "sms",
c: "Reminder",
file: UploadIO.new(file, "text/csv", filename)
})

response = Net::HTTP.start(url.hostname, url.port, use_ssl: true) do |https| # pay attention to use_ssl if you need it
https.request(request)
end

p "API response is #{response.body}"
end
end
end
55 changes: 55 additions & 0 deletions spec/lib/tasks/decidim_app/sms_reminder_task_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# frozen_string_literal: true

require "spec_helper"

describe "rake decidim_app:budgets:send_sms_reminder", type: :task do
let(:task) { Rake::Task["decidim_app:budgets:send_sms_reminder"] }

it "preloads the Rails environment" do
expect(task.prerequisites).to include "environment"
end

context "when the budget does not exist" do
it "prints Budget with id not found" do
stub_const "ENV", ENV.to_h.merge("BUDGET_ID" => 0)
expect { task.execute }.to output("\"Budget with id 0 not found\"\n").to_stdout
end
end

context "when the budget exists" do
let!(:budget) { create(:budget) }

before do
stub_const "ENV", ENV.to_h.merge("BUDGET_ID" => budget.id)
end

context "and there are no users with pending vote" do
it "prints no pending votes" do
expect { task.execute }.to output("\"no pending votes\"\n").to_stdout
end
end

context "and there are users with pending votes but no phone number" do
let!(:user) { create(:user, :confirmed, organization: budget.organization) }

it "prints no pending votes from users with phone number" do
Decidim::Budgets::Order.create!(decidim_user_id: user.id, decidim_budgets_budget_id: budget.id, checked_out_at: nil)
expect { task.execute }.to output("\"no pending votes from users with phone number\"\n").to_stdout
end
end

context "and there are users with pending votes and phone number" do
let!(:user) { create(:user, :confirmed, organization: budget.organization, phone_number: "12345678", phone_country: "FR") }

it "performs an http request" do
# rubocop:disable RSpec/MessageChain
allow(Rails).to receive_message_chain(:application, :secrets, :dig).with(:decidim, :sms_gateway, :bulk_url).and_return("https://sms.gateway.service/api/bulk")
allow(Rails).to receive_message_chain(:application, :secrets, :dig).with(:decidim, :sms_gateway, :username).and_return("12345user")
allow(Rails).to receive_message_chain(:application, :secrets, :dig).with(:decidim, :sms_gateway, :password).and_return("password12345")
# rubocop:enable RSpec/MessageChain
Decidim::Budgets::Order.create!(decidim_user_id: user.id, decidim_budgets_budget_id: budget.id, checked_out_at: nil)
expect { task.execute }.to raise_error(WebMock::NetConnectNotAllowedError) # Real HTTP connections are disabled
end
end
end
end

0 comments on commit d609ab2

Please sign in to comment.