-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #796 from pulibrary/airtable-job
Add an airtable staff list job and URL
- Loading branch information
Showing
6 changed files
with
187 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
# frozen_string_literal: true | ||
module AirTableStaff | ||
# This class is responsible for running and | ||
# recording the results of Airtable-based | ||
# CSV file generation | ||
class StaffListJob < LibJob | ||
def initialize(filename: nil) | ||
super(category: 'AirTableStaffDirectory') | ||
@report_filename = filename if filename | ||
end | ||
|
||
private | ||
|
||
def handle(data_set:) | ||
if Flipflop.air_table_staff_list? | ||
return most_recent_dataset if most_recent_dataset && recent_enough?(most_recent_dataset&.data_file) | ||
write_csv_to_disk | ||
data_set.data_file = report_filename | ||
else | ||
data_set.data = 'Airtable-based staff list is typically scheduled for this time, but it is turned off. Go to /features to turn it back on.' | ||
end | ||
data_set.report_time = Time.zone.now | ||
data_set | ||
end | ||
|
||
def write_csv_to_disk | ||
File.open(report_filename, 'w') { |file| file.write(CSVBuilder.new.to_csv) } | ||
end | ||
|
||
def report_filename | ||
@report_filename ||= begin | ||
date_str = Time.zone.now.strftime('%Y%m%d%H%M') | ||
File.join(Rails.configuration.staff_directory['report_directory'], "library_staff_#{date_str}.csv") | ||
end | ||
end | ||
|
||
def recent_enough?(filename) | ||
File.mtime(filename) > 2.hours.ago | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# Web Staff | ||
This generates the staff report from data in an Airtable. It | ||
creates a CSV that can then be used by the OIT WDS-hosted | ||
library website. | ||
|
||
## Sequence of events | ||
|
||
The steps to maintain this list, as illustrated in the sequence diagram below. | ||
1. Library Administration staff make updates in the Airtable UI. | ||
1. Lib jobs requests a staff list from the Airtable API | ||
1. The Airtable API returns a paginated JSON response | ||
1. Lib-jobs publishes a CSV of the Airtable data | ||
1. Drupal downloads the CSV | ||
1. Drupal displays the staff list | ||
|
||
```mermaid | ||
--- | ||
title: Airtable-based Staff Report Generation by lib-jobs | ||
--- | ||
sequenceDiagram | ||
actor Library Administration | ||
Library Administration->>Airtable UI: make updates | ||
Lib jobs->>Airtable API: request staff list | ||
Airtable API-->+Lib jobs: return paginated json | ||
Lib jobs->>Lib jobs: publish a CSV of the Airtable data | ||
Drupal->>Lib jobs: download the CSV | ||
Drupal->>Drupal: display the staff list | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'rails_helper' | ||
|
||
RSpec.describe AirTableStaff::StaffListJob, type: :model do | ||
before do | ||
stub_request(:get, 'https://api.airtable.com/v0/appv7XA5FWS7DG9oe/Synchronized%20Staff%20Directory%20View?view=Grid%20view') | ||
.with( | ||
headers: { | ||
'Authorization' => 'Bearer FAKE_AIRTABLE_TOKEN' | ||
} | ||
) | ||
.to_return(status: 200, body: File.read(file_fixture('air_table/records_no_offset.json')), headers: {}) | ||
end | ||
|
||
context 'job is turned off' do | ||
before do | ||
allow(Flipflop).to receive(:air_table_staff_list?).and_return(true) | ||
end | ||
describe('CSV file generation') do | ||
let(:file_path) { Pathname.new(Rails.root.join('tmp', "airtable_staff.csv")) } | ||
let(:first_row) do | ||
[ | ||
'123', 'ab123', '(123) 123-1234', 'Phillip Librarian', 'Librarian', 'Phillip', '[email protected]', '123 Stokes', 'Stokes', 'Stokes', nil, nil, nil, 'Virtual Reality' | ||
] | ||
end | ||
|
||
around do |example| | ||
File.delete(file_path) if File.exist?(file_path) | ||
example.run | ||
File.delete(file_path) if File.exist?(file_path) | ||
end | ||
|
||
it 'creates a CSV file' do | ||
job = described_class.new(filename: file_path) | ||
job.run | ||
expect(File.exist?(file_path)).to be true | ||
end | ||
|
||
it 'the CSV file has a header row and a data row' do | ||
job = described_class.new(filename: file_path) | ||
job.run | ||
expect(CSV.read(file_path).length).to eq(2) | ||
end | ||
|
||
it 'the first row of data is correct' do | ||
job = described_class.new(filename: file_path) | ||
job.run | ||
expect(CSV.read(file_path).second).to eq(first_row) | ||
end | ||
|
||
context 'when run at a particular time' do | ||
let(:run_time) { Time.zone.local(2022, 3, 14, 15, 9, 26) } | ||
before do | ||
allow(Time).to receive(:now).and_return(run_time) | ||
end | ||
it 'records that time in the database' do | ||
job = described_class.new(filename: file_path) | ||
job.run | ||
expect(DataSet.order('created_at').last.report_time).to eq(run_time) | ||
end | ||
end | ||
|
||
context 'when the process has already been run in the past hour' do | ||
let(:original_data_set) do | ||
FactoryBot.create(:data_set, | ||
category: 'AirTableStaffDirectory', | ||
data_file: 'library_staff_20221109.csv') | ||
end | ||
before do | ||
original_data_set.save | ||
allow(File).to receive(:exist?).and_return true | ||
allow(File).to receive(:mtime).and_return 1.minute.ago | ||
end | ||
|
||
it 'returns the existing dataset' do | ||
job = described_class.new(filename: file_path) | ||
expect { job.run }.not_to change { DataSet.count } | ||
end | ||
end | ||
end | ||
end | ||
|
||
context 'job is turned off' do | ||
before do | ||
allow(Flipflop).to receive(:air_table_staff_list?).and_return(false) | ||
end | ||
it 'logs that it is turned off' do | ||
stafflist_job = described_class.new(filename: 'should_not_exist.csv') | ||
stafflist_job.run | ||
data_set = DataSet.last | ||
expect(data_set.data).to eq('Airtable-based staff list is typically scheduled for this time, but it is turned off. Go to /features to turn it back on.') | ||
end | ||
it 'does not create a CSV file' do | ||
stafflist_job = described_class.new(filename: 'should_not_exist.csv') | ||
stafflist_job.run | ||
|
||
expect(File.exist?('should_not_exist.csv')).to be false | ||
end | ||
end | ||
end |