Merge pull request #4306 from betagouv/dev

2019-09-12-01
This commit is contained in:
LeSim 2019-09-12 09:57:26 +02:00 committed by GitHub
commit 6126641dc0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 66 additions and 76 deletions

View file

@ -26,7 +26,6 @@ gem 'delayed_job_web'
gem 'devise' # Gestion des comptes utilisateurs gem 'devise' # Gestion des comptes utilisateurs
gem 'devise-async' gem 'devise-async'
gem 'dotenv-rails', require: 'dotenv/rails-now' # dotenv should always be loaded before rails gem 'dotenv-rails', require: 'dotenv/rails-now' # dotenv should always be loaded before rails
gem 'flipflop'
gem 'flipper' gem 'flipper'
gem 'flipper-active_record' gem 'flipper-active_record'
gem 'flipper-ui' gem 'flipper-ui'

View file

@ -220,8 +220,6 @@ GEM
faraday (0.15.4) faraday (0.15.4)
multipart-post (>= 1.2, < 3) multipart-post (>= 1.2, < 3)
ffi (1.9.25) ffi (1.9.25)
flipflop (2.4.0)
activesupport (>= 4.0)
flipper (0.16.2) flipper (0.16.2)
flipper-active_record (0.16.2) flipper-active_record (0.16.2)
activerecord (>= 3.2, < 6) activerecord (>= 3.2, < 6)
@ -733,7 +731,6 @@ DEPENDENCIES
devise-async devise-async
dotenv-rails dotenv-rails
factory_bot factory_bot
flipflop
flipper flipper
flipper-active_record flipper-active_record
flipper-ui flipper-ui

View file

@ -13,7 +13,6 @@ class StatsController < ApplicationController
@satisfaction_usagers = satisfaction_usagers @satisfaction_usagers = satisfaction_usagers
@contact_percentage = contact_percentage @contact_percentage = contact_percentage
@contact_percentage_excluded_tags = Helpscout::UserConversationsAdapter::EXCLUDED_TAGS
@dossiers_states = dossiers_states @dossiers_states = dossiers_states
@ -177,7 +176,7 @@ class StatsController < ApplicationController
.map do |monthly_report| .map do |monthly_report|
start_date = monthly_report[:start_date].to_time.localtime start_date = monthly_report[:start_date].to_time.localtime
end_date = monthly_report[:end_date].to_time.localtime end_date = monthly_report[:end_date].to_time.localtime
replies_count = monthly_report[:conversations_count] replies_count = monthly_report[:replies_sent]
dossiers_count = Dossier.where(en_construction_at: start_date..end_date).count dossiers_count = Dossier.where(en_construction_at: start_date..end_date).count

View file

@ -26,7 +26,7 @@ class Helpscout::API
body = { body = {
subject: subject, subject: subject,
customer: customer(email), customer: customer(email),
mailboxId: mailbox_id, mailboxId: user_support_mailbox_id,
type: 'email', type: 'email',
status: 'active', status: 'active',
threads: [ threads: [
@ -44,7 +44,7 @@ class Helpscout::API
def add_phone_number(email, phone) def add_phone_number(email, phone)
query = URI.encode("(email:#{email})") query = URI.encode("(email:#{email})")
response = call_api(:get, "#{CUSTOMERS}?mailbox=#{mailbox_id}&query=#{query}") response = call_api(:get, "#{CUSTOMERS}?mailbox=#{user_support_mailbox_id}&query=#{query}")
if response.success? if response.success?
body = parse_response_body(response) body = parse_response_body(response)
if body[:page][:totalElements] > 0 if body[:page][:totalElements] > 0
@ -57,17 +57,18 @@ class Helpscout::API
end end
end end
def conversations_report(year, month) def productivity_report(year, month)
Rails.logger.info("[HelpScout API] Retrieving conversations report for #{month}-#{year}") Rails.logger.info("[HelpScout API] Retrieving productivity report for #{month}-#{year}")
params = { params = {
mailboxes: [user_support_mailbox_id].join(','),
start: Time.utc(year, month).iso8601, start: Time.utc(year, month).iso8601,
end: Time.utc(year, month).next_month.iso8601 end: Time.utc(year, month).next_month.iso8601
} }
response = call_api(:get, 'reports/conversations?' + params.to_query) response = call_api(:get, 'reports/productivity?' + params.to_query)
if !response.success? if !response.success?
raise StandardError, "Error while fetching conversation report: #{response.response_code} '#{response.body}'" raise StandardError, "Error while fetching productivity report: #{response.response_code} '#{response.body}'"
end end
parse_response_body(response) parse_response_body(response)
@ -107,7 +108,7 @@ class Helpscout::API
end end
def fetch_custom_fields def fetch_custom_fields
call_api(:get, "#{MAILBOXES}/#{mailbox_id}/#{FIELDS}") call_api(:get, "#{MAILBOXES}/#{user_support_mailbox_id}/#{FIELDS}")
end end
def call_api(method, path, body = nil) def call_api(method, path, body = nil)
@ -135,7 +136,7 @@ class Helpscout::API
JSON.parse(response.body, symbolize_names: true) JSON.parse(response.body, symbolize_names: true)
end end
def mailbox_id def user_support_mailbox_id
Rails.application.secrets.helpscout[:mailbox_id] Rails.application.secrets.helpscout[:mailbox_id]
end end

View file

@ -1,7 +1,5 @@
# Fetch and compute monthly reports about the users conversations on Helpscout # Fetch and compute monthly reports about the users conversations on Helpscout
class Helpscout::UserConversationsAdapter class Helpscout::UserConversationsAdapter
EXCLUDED_TAGS = ['openlab', 'bizdev', 'admin', 'webinaire']
def initialize(from, to) def initialize(from, to)
@from = from @from = from
@to = to @to = to
@ -23,19 +21,12 @@ class Helpscout::UserConversationsAdapter
private private
def report(year, month) def report(year, month)
report = fetch_conversations_report(year, month) report = fetch_productivity_report(year, month)
total_conversations = report.dig(:current, :totalConversations)
excluded_conversations = report
.dig(:tags, :top)
.select { |tag| tag[:name]&.in?(EXCLUDED_TAGS) }
.map { |tag| tag[:count] }
.sum
{ {
start_date: report.dig(:current, :startDate).to_datetime, start_date: report.dig(:current, :startDate).to_datetime,
end_date: report.dig(:current, :endDate).to_datetime, end_date: report.dig(:current, :endDate).to_datetime,
conversations_count: total_conversations - excluded_conversations replies_sent: report.dig(:current, :repliesSent)
} }
end end
@ -43,13 +34,13 @@ class Helpscout::UserConversationsAdapter
@api_client ||= Helpscout::API.new @api_client ||= Helpscout::API.new
end end
def fetch_conversations_report(year, month) def fetch_productivity_report(year, month)
if year == Date.today.year && month == Date.today.month if year == Date.today.year && month == Date.today.month
raise ArgumentError, 'The report for the current month will change in the future, and cannot be cached.' raise ArgumentError, 'The report for the current month will change in the future, and cannot be cached.'
end end
Rails.cache.fetch("helpscout-conversation-report-#{year}-#{month}") do Rails.cache.fetch("helpscout-productivity-report-#{year}-#{month}") do
api_client.conversations_report(year, month) api_client.productivity_report(year, month)
end end
end end
end end

View file

@ -1,4 +1,6 @@
class Administrateur < ApplicationRecord class Administrateur < ApplicationRecord
self.ignored_columns = ['features']
include EmailSanitizableConcern include EmailSanitizableConcern
include ActiveRecord::SecureToken include ActiveRecord::SecureToken

View file

@ -1,4 +1,5 @@
class Instructeur < ApplicationRecord class Instructeur < ApplicationRecord
self.ignored_columns = ['features']
include EmailSanitizableConcern include EmailSanitizableConcern
has_and_belongs_to_many :administrateurs has_and_belongs_to_many :administrateurs

View file

@ -31,7 +31,6 @@ class AdministrateurUsageStatisticsService
ds_created_at: administrateur.created_at, ds_created_at: administrateur.created_at,
ds_active: administrateur.active, ds_active: administrateur.active,
ds_id: administrateur.id, ds_id: administrateur.id,
ds_features: administrateur.features.to_json,
nb_services: nb_services_by_administrateur_id[administrateur.id], nb_services: nb_services_by_administrateur_id[administrateur.id],
nb_instructeurs: nb_instructeurs_by_administrateur_id[administrateur.id], nb_instructeurs: nb_instructeurs_by_administrateur_id[administrateur.id],

View file

@ -27,7 +27,7 @@
%li %li
%object %object
= link_to(instructeur_procedure_path(p, statut: 'suivis')) do = link_to(instructeur_procedure_path(p, statut: 'suivis')) do
- if current_instructeur.notifications_per_procedure[p.defaut_groupe_instructeur.id].present? - if current_instructeur.notifications_per_procedure[p.id].present?
%span.notifications{ 'aria-label': "notifications" } %span.notifications{ 'aria-label': "notifications" }
- followed_count = @followed_dossiers_count_per_groupe_instructeur[p.defaut_groupe_instructeur.id] || 0 - followed_count = @followed_dossiers_count_per_groupe_instructeur[p.defaut_groupe_instructeur.id] || 0
.stats-number .stats-number
@ -37,7 +37,7 @@
%li %li
%object %object
= link_to(instructeur_procedure_path(p, statut: 'traites')) do = link_to(instructeur_procedure_path(p, statut: 'traites')) do
- if current_instructeur.notifications_per_procedure(:termine)[p.defaut_groupe_instructeur.id].present? - if current_instructeur.notifications_per_procedure(:termine)[p.id].present?
%span.notifications{ 'aria-label': "notifications" } %span.notifications{ 'aria-label': "notifications" }
- termines_count = @dossiers_termines_count_per_groupe_instructeur[p.defaut_groupe_instructeur.id] || 0 - termines_count = @dossiers_termines_count_per_groupe_instructeur[p.defaut_groupe_instructeur.id] || 0
.stats-number .stats-number

View file

@ -34,16 +34,15 @@
.stat-card.stat-card-half.pull-left .stat-card.stat-card-half.pull-left
%span.stat-card-title %span.stat-card-title
Pourcentage de contact usager Pourcentage de contact utilisateur
.chart-container .chart-container
.chart .chart
= line_chart @contact_percentage = line_chart @contact_percentage
.stat-card-details .stat-card-details
%abbr{ title: "À lexception des conversations taggées #{@contact_percentage_excluded_tags.join(', ')}" } Nombre de réponses envoyées via HelpScout
Nombre de conversations actives dans HelpScout \/ nombre de dossiers déposés
%span / nombre de dossiers déposés
.stat-card.stat-card-half.pull-left .stat-card.stat-card-half.pull-left
%span.stat-card-title %span.stat-card-title

File diff suppressed because one or more lines are too long

View file

@ -15,9 +15,7 @@ describe Helpscout::UserConversationsAdapter do
context 'when all required secrets are present' do context 'when all required secrets are present' do
before do before do
Rails.application.secrets.helpscout[:mailbox_id] = '9999' mock_helpscout_secrets
Rails.application.secrets.helpscout[:client_id] = '1234'
Rails.application.secrets.helpscout[:client_secret] = '5678'
end end
it { expect(described_class.new(from, to).can_fetch_reports?).to be true } it { expect(described_class.new(from, to).can_fetch_reports?).to be true }
@ -25,7 +23,10 @@ describe Helpscout::UserConversationsAdapter do
end end
describe '#reports', vcr: { cassette_name: 'helpscout_conversations_reports' } do describe '#reports', vcr: { cassette_name: 'helpscout_conversations_reports' } do
before { Rails.cache.clear } before do
mock_helpscout_secrets
Rails.cache.clear
end
subject { described_class.new(from, to) } subject { described_class.new(from, to) }
@ -34,13 +35,19 @@ describe Helpscout::UserConversationsAdapter do
end end
it 'populates each report with data' do it 'populates each report with data' do
expect(subject.reports.first[:conversations_count]).to be > 0 expect(subject.reports.first[:replies_sent]).to be > 0
expect(subject.reports.first[:start_date]).to eq Time.utc(2017, 11) expect(subject.reports.first[:start_date]).to eq Time.utc(2017, 11)
expect(subject.reports.first[:end_date]).to eq Time.utc(2017, 12) expect(subject.reports.first[:end_date]).to eq Time.utc(2017, 12)
expect(subject.reports.last[:conversations_count]).to be > 0 expect(subject.reports.last[:replies_sent]).to be > 0
expect(subject.reports.last[:start_date]).to eq Time.utc(2017, 12) expect(subject.reports.last[:start_date]).to eq Time.utc(2017, 12)
expect(subject.reports.last[:end_date]).to eq Time.utc(2018, 01) expect(subject.reports.last[:end_date]).to eq Time.utc(2018, 01)
end end
end end
def mock_helpscout_secrets
Rails.application.secrets.helpscout[:mailbox_id] = '9999'
Rails.application.secrets.helpscout[:client_id] = '1234'
Rails.application.secrets.helpscout[:client_secret] = '5678'
end
end end

View file

@ -17,7 +17,6 @@ describe AdministrateurUsageStatisticsService do
ds_created_at: Time.zone.now, ds_created_at: Time.zone.now,
ds_active: false, ds_active: false,
ds_id: administrateur.id, ds_id: administrateur.id,
ds_features: "{}",
nb_services: 0, nb_services: 0,
nb_instructeurs: 0, nb_instructeurs: 0,
ds_nb_demarches_actives: 0, ds_nb_demarches_actives: 0,
@ -43,7 +42,6 @@ describe AdministrateurUsageStatisticsService do
current_sign_in_at: Time.zone.local(2019, 3, 7), current_sign_in_at: Time.zone.local(2019, 3, 7),
last_sign_in_at: Time.zone.local(2019, 2, 27), last_sign_in_at: Time.zone.local(2019, 2, 27),
active: true, active: true,
features: { holy_hand_grenade_of_antioch: true },
services: [create(:service)], services: [create(:service)],
instructeurs: [create(:instructeur)]) instructeurs: [create(:instructeur)])
end end
@ -56,7 +54,6 @@ describe AdministrateurUsageStatisticsService do
ds_created_at: Time.zone.now, ds_created_at: Time.zone.now,
ds_active: true, ds_active: true,
ds_id: administrateur.id, ds_id: administrateur.id,
ds_features: { holy_hand_grenade_of_antioch: true }.to_json,
nb_services: 1, nb_services: 1,
nb_instructeurs: 1 nb_instructeurs: 1
) )

View file

@ -10,7 +10,7 @@ RSpec.configure do |config|
end end
config.before(:each, js: true) do config.before(:each, js: true) do
DatabaseCleaner.strategy = :truncation, { except: expect_list } DatabaseCleaner.strategy = :deletion, { except: expect_list }
end end
config.before(:each) do config.before(:each) do

View file

@ -5398,9 +5398,9 @@ mississippi@^3.0.0:
through2 "^2.0.0" through2 "^2.0.0"
mixin-deep@^1.2.0: mixin-deep@^1.2.0:
version "1.3.1" version "1.3.2"
resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566"
integrity sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ== integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==
dependencies: dependencies:
for-in "^1.0.2" for-in "^1.0.2"
is-extendable "^1.0.1" is-extendable "^1.0.1"