Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into aws-eb-test
Browse files Browse the repository at this point in the history
  • Loading branch information
tbhi committed Jan 29, 2025
2 parents d053f27 + 9b4e9dc commit eac4bc7
Show file tree
Hide file tree
Showing 13 changed files with 155 additions and 151 deletions.
48 changes: 8 additions & 40 deletions app/controllers/admin/reports/engaged_schools_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,52 +4,20 @@ module Admin
module Reports
class EngagedSchoolsController < AdminController
def index
@previous_year = params.key?(:previous_year)
@engaged_schools = ::Schools::EngagedSchoolService
.list_engaged_schools(previous_year: @previous_year)
@engaged_schools_count = ::Schools::EngagedSchoolService.engaged_schools_count
@visible_schools = School.visible.count
@percentage = percentage_engaged
return unless request.post?

respond_to do |format|
format.html do
@visible_schools = School.visible.count
@percentage = percentage_engaged
end
format.csv do
send_data csv_report(@engaged_schools),
filename: "engaged-schools-report-#{Time.zone.now.iso8601.parameterize}" \
"#{@previous_year ? '-previous-year' : ''}.csv"
end
end
EngagedSchoolsReportJob.perform_later(current_user.email, params[:previous], params[:school_group_id])
redirect_back fallback_location: admin_reports_engaged_schools_path,
notice: "Report sent to #{current_user.email}"
end

private

def percentage_engaged
format('%.2f', @engaged_schools.size / @visible_schools.to_f * 100)
end

def csv_report(engaged_schools)
CSV.generate(headers: true) do |csv|
csv << ['School Group', 'School', 'Funder', 'Country', 'Activities', 'Actions',
'Programmes', 'Target?', 'Transport survey?', 'Temperatures?', 'Audit?',
'Active users', 'Last visit']
engaged_schools.each do |service|
csv << [
service.school_group.name,
service.school.name,
service.school.funder.present? ? service.school.funder.name : nil,
service.school.country.humanize,
service.recent_activity_count,
service.recent_action_count,
service.recently_enrolled_programme_count,
service.active_target? ? 'Y' : 'N',
service.transport_surveys? ? 'Y' : 'N',
service.temperature_recordings? ? 'Y' : 'N',
service.audits? ? 'Y' : 'N',
service.recently_logged_in_user_count,
service.most_recent_login.present? ? service.most_recent_login.iso8601 : nil
]
end
end
format('%.2f', @engaged_schools_count / @visible_schools.to_f * 100)
end
end
end
Expand Down
42 changes: 42 additions & 0 deletions app/jobs/engaged_schools_report_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# frozen_string_literal: true

class EngagedSchoolsReportJob < ApplicationJob
def perform(to, previous_year, school_group_id)
AdminMailer.with(to:, csv: csv_report(previous_year, school_group_id)).engaged_schools_report.deliver
end

private

def format_bool(bool)
bool ? 'Y' : 'N'
end

def row
{ school_group: ->(service) { service.school_group.name },
school: ->(service) { service.school.name },
funder: ->(service) { service.school.funder&.name },
country: ->(service) { service.school.country.humanize },
active: ->(service) { format_bool(service.school.active) },
data_visible: ->(service) { format_bool(service.school.data_visible?) },
admin: ->(service) { service.school.default_issues_admin_user&.name },
activities: ->(service) { service.recent_activity_count },
actions: ->(service) { service.recent_action_count },
programmes: ->(service) { service.recently_enrolled_programme_count },
target?: ->(service) { format_bool(service.active_target?) },
transport_survey?: ->(service) { format_bool(service.transport_surveys?) },
temperatures?: ->(service) { format_bool(service.temperature_recordings?) },
audit?: ->(service) { format_bool(service.audits?) },
active_users: ->(service) { service.recently_logged_in_user_count },
last_visit: ->(service) { service.most_recent_login&.iso8601 } }
end

def csv_report(previous_year, school_group_id)
engaged_schools = Schools::EngagedSchoolService.list_schools(previous_year:, school_group_id:)
CSV.generate(headers: true) do |csv|
csv << row.keys.map { |header| header.to_s.titleize }
engaged_schools.each do |service|
csv << row.values.map { |lambda| lambda.call(service) }
end
end
end
end
8 changes: 8 additions & 0 deletions app/mailers/admin_mailer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ def funder_allocation_report
mail(to: to, subject: subject(title))
end

def engaged_schools_report
now = Time.zone.now.iso8601
attachments["engaged-schools-report-#{now.tr(':', '-')}#{params[:previous_year] ? '-previous-year' : ''}.csv"] = \
{ mime_type: 'text/csv', content: params[:csv] }

mail(to: params[:to], subject: subject("Engaged schools report #{now}"))
end

private

def build_issues_csv_for(issues)
Expand Down
4 changes: 4 additions & 0 deletions app/models/school.rb
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,10 @@ def self.school_list_for_login_form
'school_groups.name as school_group_name').where(visible: true).order(:name)
end

def data_visible?
data_enabled && visible
end

private

def valid_uk_postcode
Expand Down
10 changes: 8 additions & 2 deletions app/services/schools/engaged_school_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,21 @@ def initialize(school, date_range)
@date_range = date_range
end

def self.list_engaged_schools(previous_year: false)
def self.engaged_schools_count
School.engaged(AcademicYear.current.start_date..).count
end

def self.list_schools(previous_year:, school_group_id:)
current_year = AcademicYear.current
date_range = if previous_year
previous_year = current_year.previous_year
previous_year.start_date..previous_year.end_date
else
current_year.start_date..
end
School.engaged(date_range).joins(:school_group).order('school_groups.name asc, name asc').map do |school|
schools = School.joins(:school_group)
schools = schools.where(school_group_id: school_group_id) if school_group_id.present?
schools.order('school_groups.name asc, name asc').map do |school|
EngagedSchoolService.new(school, date_range)
end
end
Expand Down
79 changes: 15 additions & 64 deletions app/views/admin/reports/engaged_schools/index.html.erb
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<h1>Engaged Schools</h1>

<p>
The following report lists "engaged schools". An engaged school has done one of the following since the start of the
current academic year (<%= nice_dates(AcademicYear.current.start_date) %>):
The report generated below lists "engaged schools". An engaged school has done one of the following since the start of
the current academic year (<%= nice_dates(AcademicYear.current.start_date) %>):
</p>

<ul>
Expand Down Expand Up @@ -51,68 +51,19 @@
</ul>

<p>
Using the above measures, EnergySparks currently has <strong><%= @engaged_schools.count %></strong> engaged schools
Using the above measures, EnergySparks currently has <strong><%= @engaged_schools_count %></strong> engaged schools
out of <strong><%= @visible_schools %></strong> schools (<strong><%= @percentage %>%</strong>)
</p>

<div class="d-flex justify-content-end">
<% label, kwargs, csv_kwargs = if @previous_year
['Current Year', {}, { previous_year: true }]
else
['Previous Year', { previous_year: true }, {}]
end
classes = 'btn btn-default' %>
<%= link_to label, admin_reports_engaged_schools_path(**kwargs), class: "#{classes} mr-2" %>
<%= link_to 'Download as CSV', admin_reports_engaged_schools_path(**csv_kwargs.merge(format: :csv)),
class: classes %>
</div>

<table class="table table-sorted table-sm">
<thead>
<tr>
<th>School Group</th>
<th>School</th>
<th>Funder</th>
<th>Country</th>
<th>Activities</th>
<th>Actions</th>
<th>Programmes</th>
<th>Target?</th>
<th>Transport survey?</th>
<th>Temperatures?</th>
<th>Audit?</th>
<th>Active users</th>
<th>Last visit</th>
</tr>
</thead>
<tbody>
<% @engaged_schools.each do |service| %>
<tr>
<td><%= link_to service.school_group.name, school_group_path(service.school_group) %></td>
<td><%= link_to service.school.name, school_path(service.school) %></td>
<td><%= service.school.funder&.name %></td>
<td><%= service.school.country.humanize %></td>
<td><%= link_to service.recent_activity_count, school_timeline_path(service.school) %></td>
<td><%= link_to service.recent_action_count, school_timeline_path(service.school) %></td>
<td><%= service.recently_enrolled_programme_count %></td>
<td data-order="<%= service.active_target? ? '1' : '0' %>">
<%= checkmark(service.active_target?, off_class: 'text-muted') %></td>
<td data-order="<%= service.transport_surveys? ? '1' : '0' %>">
<%= checkmark(service.transport_surveys?, off_class: 'text-muted') %>
</td>
<td data-order="<%= service.temperature_recordings? ? '1' : '0' %>">
<%= checkmark(service.temperature_recordings?, off_class: 'text-muted') %>
</td>
<td data-order="<%= service.audits? ? '1' : '0' %>">
<%= checkmark(service.audits?, off_class: 'text-muted') %>
</td>
<td>
<%= link_to service.recently_logged_in_user_count, admin_school_group_users_path(service.school_group) %>
</td>
<td data-order="<%= service.most_recent_login.present? ? service.most_recent_login.iso8601 : '' %>">
<%= nice_date_times(service.most_recent_login) %>
</td>
</tr>
<% end %>
</tbody>
<table>
<%= form_with url: admin_reports_engaged_schools_path, class: 'form-inline mt-5 mb-2' do %>
<div class="form-group">
<%= label_tag :school_group_id, 'School Group', class: 'mr-2' %>
<%= select_tag :school_group_id,
options_from_collection_for_select(SchoolGroup.by_name, :id, :name, params[:school_group_id]),
include_blank: 'All School Groups', class: 'form-control mr-2' %>
</div>
<div class="actions">
<%= submit_tag 'Email Current Year', class: 'btn btn-primary' %>
<%= submit_tag 'Email Previous Year', class: 'btn btn-primary', name: 'previous' %>
</div>
<% end %>
4 changes: 4 additions & 0 deletions app/views/admin_mailer/engaged_schools_report.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<h1>Engaged Schools</h1>
<p>
The report is attached to this email.
</p>
2 changes: 1 addition & 1 deletion config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -682,7 +682,7 @@
resources :activity_types, only: [:index, :show]
resources :dcc_status, only: [:index]
resources :solar_panels, only: [:index]
resources :engaged_schools, only: [:index]
match 'engaged_schools', to: "engaged_schools#index", via: [:get, :post]
resources :community_use, only: [:index]
resources :intervention_types, only: [:index, :show]
resources :missing_alert_contacts, only: [:index]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
require_relative 'context_extensions'
require_relative '../support/context_extensions'
require 'flipper'

RSpec.describe ContextExtensions do
Expand Down
4 changes: 4 additions & 0 deletions spec/rails_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@

config.include ActiveSupport::Testing::TimeHelpers
config.include ShowMeTheCookies, type: :system

config.expect_with :rspec do |expectations|
expectations.max_formatted_output_length = 500
end
end

Shoulda::Matchers.configure do |config|
Expand Down
19 changes: 11 additions & 8 deletions spec/services/schools/engaged_school_service_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,30 @@

let!(:school) { create(:school, :with_school_group) }

describe '.list_engaged_schools' do
let!(:inactive) { create(:school, :with_school_group, :with_points, active: false) }
describe '.list_schools' do
let!(:school) do
create(:school, :with_school_group, :with_points,
calendar: create(:calendar, :with_previous_and_next_academic_years))
end
let(:engaged_schools) { described_class.list_engaged_schools }
let(:schools) { described_class.list_schools(previous_year: false, school_group_id: nil) }

it 'returns active schools with recent activities' do
expect(engaged_schools.count).to eq 1
before { create(:school, :with_school_group, :with_points, active: false) }

it 'returns schools' do
expect(schools.count).to eq 2
expect(schools.find { |service| service.school.id = school.id }.recent_activity_count).to eq(1)
end

it 'wraps schools in the service' do
expect(engaged_schools.first.school).to eq school
expect(schools.first.school).to eq school
end

context 'with the previous year' do
let(:engaged_schools) { described_class.list_engaged_schools(previous_year: true) }
let(:schools) { described_class.list_schools(previous_year: true, school_group_id: nil) }

it 'returns active schools with recent activities' do
expect(engaged_schools.count).to eq 0
expect(schools.count).to eq 2
expect(schools.find { |service| service.school.id = school.id }.recent_activity_count).to eq(0)
end
end
end
Expand Down
49 changes: 49 additions & 0 deletions spec/system/admin/reports/engaged_schools_report_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# frozen_string_literal: true

require 'rails_helper'

describe 'Engaged Schools Report' do
include ActiveJob::TestHelper

let(:admin) { create(:admin) }
let!(:school) do
create(:school, :with_school_group, :with_points,
calendar: create(:calendar, :with_previous_and_next_academic_years))
end
let(:last_sign_in) { Time.zone.now }
let!(:user) { create(:school_admin, school: school, last_sign_in_at: last_sign_in) }

before do
sign_in(admin)
visit admin_reports_engaged_schools_path
end

def expect_email_with_report(activities: 1)
email = ActionMailer::Base.deliveries.last
expect(email.attachments.first.body.decoded.split("\r\n").map { |line| line.split(',') }).to eq(
[['School Group', 'School', 'Funder', 'Country', 'Active', 'Data Visible', 'Admin',
'Activities', 'Actions', 'Programmes', 'Target?', 'Transport Survey?', 'Temperatures?', 'Audit?',
'Active Users', 'Last Visit'],
[school.school_group.name, school.name, '', school.country.humanize, 'Y', 'Y', '',
activities.to_s, '0', '0', 'N', 'N', 'N', 'N',
'1', last_sign_in.iso8601]]
)
end

it 'all groups' do
perform_enqueued_jobs { click_on 'Email Current Year' }
expect_email_with_report
end

it 'previous year' do
perform_enqueued_jobs { click_on 'Email Previous Year' }
expect_email_with_report(activities: 0)
end

it 'filters school group' do
create(:school, :with_school_group, :with_points)
select school.school_group.name, from: 'School Group'
perform_enqueued_jobs { click_on 'Email Current Year' }
expect_email_with_report
end
end
Loading

0 comments on commit eac4bc7

Please sign in to comment.