mirror of
https://github.com/edcommonwealth/sqm-dashboards.git
synced 2026-03-07 13:38:18 -08:00
ECP-170 Remove login requirement for Trition. Switch to using predefined passwords stored in the database for district login.
This commit is contained in:
parent
72e38f5ee8
commit
2068758ae4
15 changed files with 146 additions and 16 deletions
|
|
@ -10,7 +10,7 @@ class SqmApplicationController < ApplicationController
|
|||
private
|
||||
|
||||
def authenticate_district
|
||||
authenticate(district_name, "#{district_name}!")
|
||||
authenticate(@district.username, @district.password)
|
||||
end
|
||||
|
||||
def district_name
|
||||
|
|
@ -35,6 +35,8 @@ class SqmApplicationController < ApplicationController
|
|||
end
|
||||
|
||||
def authenticate(username, password)
|
||||
return unless @district.login_required
|
||||
|
||||
authenticate_or_request_with_http_basic do |u, p|
|
||||
u == username && p == password
|
||||
end
|
||||
|
|
|
|||
|
|
@ -147,6 +147,10 @@ class Seeder
|
|||
EspLoader.load_data(filepath: esp_file)
|
||||
end
|
||||
|
||||
def seed_district_credentials(file:)
|
||||
CredentialsLoader.load_credentials(file:)
|
||||
end
|
||||
|
||||
private
|
||||
def value_from(pattern:, row:)
|
||||
matches = row.headers.select do |header|
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
class District < ApplicationRecord
|
||||
has_many :schools
|
||||
encrypts :password
|
||||
|
||||
validates :name, presence: true
|
||||
|
||||
|
|
|
|||
45
app/services/credentials_loader.rb
Normal file
45
app/services/credentials_loader.rb
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
require "csv"
|
||||
|
||||
class CredentialsLoader
|
||||
def self.load_credentials(file:)
|
||||
credentials = []
|
||||
CSV.parse(file, headers: true) do |row|
|
||||
values = CredentialRowValues.new(row:)
|
||||
next unless values.district.present?
|
||||
|
||||
credentials << values.district
|
||||
end
|
||||
District.import(credentials, batch_size: 100, on_duplicate_key_update: [:username, :password, :login_required])
|
||||
end
|
||||
end
|
||||
|
||||
class CredentialRowValues
|
||||
attr_reader :row
|
||||
|
||||
def initialize(row:)
|
||||
@row = row
|
||||
end
|
||||
|
||||
def district
|
||||
@district ||= begin
|
||||
name = row["Districts"]&.strip
|
||||
district = District.find_or_initialize_by(name:)
|
||||
district.username = username
|
||||
district.password = password
|
||||
district.login_required = login_required?
|
||||
district
|
||||
end
|
||||
end
|
||||
|
||||
def username
|
||||
row["Username"]&.strip
|
||||
end
|
||||
|
||||
def password
|
||||
row["PW"]&.strip
|
||||
end
|
||||
|
||||
def login_required?
|
||||
row["Login Required"]&.strip == "Y"
|
||||
end
|
||||
end
|
||||
17
app/services/sftp/file.rb
Normal file
17
app/services/sftp/file.rb
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
require 'net/sftp'
|
||||
require 'uri'
|
||||
|
||||
module Sftp
|
||||
class File
|
||||
def self.open(filepath:, &block)
|
||||
sftp_url = ENV['SFTP_URL']
|
||||
uri = URI.parse(sftp_url)
|
||||
Net::SFTP.start(uri.host, uri.user, password: uri.password) do |sftp|
|
||||
sftp.file.open(filepath, 'r', &block)
|
||||
end
|
||||
rescue Net::SFTP::StatusException => e
|
||||
puts "Error opening file: #{e.message}"
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
||||
7
db/migrate/20250611181510_add_credentials_to_district.rb
Normal file
7
db/migrate/20250611181510_add_credentials_to_district.rb
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
class AddCredentialsToDistrict < ActiveRecord::Migration[8.0]
|
||||
def change
|
||||
add_column :districts, :username, :string, null: true, default: nil
|
||||
add_column :districts, :password, :string, null: true, default: nil
|
||||
add_column :districts, :login_required, :boolean, null: false, default: true
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
class AddNameSlugAndQualtricsCodeIndexesToDistrict < ActiveRecord::Migration[8.0]
|
||||
def change
|
||||
add_index :districts, :name, unique: true
|
||||
add_index :districts, :slug, unique: true
|
||||
add_index :districts, :qualtrics_code, unique: true
|
||||
end
|
||||
end
|
||||
|
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema[8.0].define(version: 2025_05_23_222834) do
|
||||
ActiveRecord::Schema[8.0].define(version: 2025_06_11_182208) do
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "pg_catalog.plpgsql"
|
||||
|
||||
|
|
@ -69,6 +69,12 @@ ActiveRecord::Schema[8.0].define(version: 2025_05_23_222834) do
|
|||
t.integer "qualtrics_code"
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.string "username"
|
||||
t.string "password"
|
||||
t.boolean "login_required", default: true, null: false
|
||||
t.index ["name"], name: "index_districts_on_name", unique: true
|
||||
t.index ["qualtrics_code"], name: "index_districts_on_qualtrics_code", unique: true
|
||||
t.index ["slug"], name: "index_districts_on_slug", unique: true
|
||||
end
|
||||
|
||||
create_table "ells", force: :cascade do |t|
|
||||
|
|
|
|||
|
|
@ -14,3 +14,7 @@ seeder.seed_staffing Rails.root.join("data", "staffing", "staffing.csv")
|
|||
seeder.seed_staffing Rails.root.join("data", "staffing", "nj_staffing.csv")
|
||||
seeder.seed_staffing Rails.root.join("data", "staffing", "wi_staffing.csv")
|
||||
seeder.seed_esp_counts Rails.root.join("data", "staffing", "esp_counts.csv")
|
||||
|
||||
Sftp::File.open(filepath: "/ecp/district_credentials.csv") do |file|
|
||||
seeder.seed_district_credentials file:
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ require 'rails_helper'
|
|||
describe CategoriesController, type: :controller do
|
||||
include BasicAuthHelper
|
||||
let(:school) { create(:school) }
|
||||
let(:district) { create(:district) }
|
||||
let(:district) { create(:district, username: 'maynard', password: 'maynard!', login_required: true) }
|
||||
let!(:categories) do
|
||||
[create(:category, name: 'Second', sort_index: 2), create(:category, name: 'First', sort_index: 1)]
|
||||
end
|
||||
|
|
|
|||
|
|
@ -4,11 +4,15 @@ include VarianceHelper
|
|||
describe OverviewController, type: :controller do
|
||||
include BasicAuthHelper
|
||||
let(:school) { create(:school) }
|
||||
let(:district) { create(:district) }
|
||||
let(:district) { create(:district, username: 'maynard', password: 'maynard!', login_required: true) }
|
||||
let!(:categories) do
|
||||
[create(:category, name: 'Second', sort_index: 2), create(:category, name: 'First', sort_index: 1)]
|
||||
end
|
||||
|
||||
before do
|
||||
district
|
||||
end
|
||||
|
||||
it 'fetches categories sorted by sort_index' do
|
||||
login_as district
|
||||
get :index, params: { school_id: school.to_param, district_id: district.to_param }
|
||||
|
|
|
|||
4
spec/fixtures/sample_district_credentials.csv
vendored
Normal file
4
spec/fixtures/sample_district_credentials.csv
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
Districts,Login Required,Username,PW
|
||||
Maynard Public Schools,Y,maynard_admin,password123
|
||||
Springfield Public Schools,N,springfield_admin,password456
|
||||
Boston Public Schools,Y,boston_admin,password789
|
||||
|
37
spec/services/credentials_loader_spec.rb
Normal file
37
spec/services/credentials_loader_spec.rb
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
require "rails_helper"
|
||||
require "fileutils"
|
||||
|
||||
RSpec.describe CredentialsLoader do
|
||||
let(:path) do
|
||||
Rails.root.join("spec", "fixtures", "credentials", "credentials.csv")
|
||||
end
|
||||
|
||||
context ".load_credentials" do
|
||||
before do
|
||||
create(:district, name: "Maynard Public Schools")
|
||||
create(:district, name: "Springfield Public Schools")
|
||||
create(:district, name: "Boston Public Schools")
|
||||
end
|
||||
|
||||
it "loads credentials from the CSV file into the database" do
|
||||
file = File.open(Rails.root.join("spec", "fixtures", "sample_district_credentials.csv"))
|
||||
# Seeder.new.seed_district_credentials(file:)
|
||||
expect { CredentialsLoader.load_credentials(file:) }.to change { District.count }.by(0)
|
||||
|
||||
district = District.find_by(name: "Maynard Public Schools")
|
||||
expect(district.username).to eq("maynard_admin")
|
||||
expect(district.password).to eq("password123")
|
||||
expect(district.login_required).to be true
|
||||
|
||||
district = District.find_by(name: "Springfield Public Schools")
|
||||
expect(district.username).to eq("springfield_admin")
|
||||
expect(district.password).to eq("password456")
|
||||
expect(district.login_required).to be false
|
||||
|
||||
district = District.find_by(name: "Boston Public Schools")
|
||||
expect(district.username).to eq("boston_admin")
|
||||
expect(district.password).to eq("password789")
|
||||
expect(district.login_required).to be true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
module BasicAuthHelper
|
||||
def login_as(district)
|
||||
user = district.short_name
|
||||
pw = "#{user}!"
|
||||
user = district.username
|
||||
pw = district.password
|
||||
request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials(user, pw)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
require "rails_helper"
|
||||
|
||||
describe "SQM Application" do
|
||||
let(:district) { create(:district) }
|
||||
let(:district) { create(:district, username: 'maynard', password: 'maynard!', login_required: true) }
|
||||
let(:school) { create(:school, district:) }
|
||||
let(:academic_year) { create(:academic_year) }
|
||||
let(:category) { create(:category) }
|
||||
|
|
@ -11,7 +11,7 @@ describe "SQM Application" do
|
|||
|
||||
before :each do
|
||||
driven_by :rack_test
|
||||
page.driver.browser.basic_authorize(username, password)
|
||||
page.driver.browser.basic_authorize(district.username, district.password)
|
||||
create(:respondent, school:, academic_year:)
|
||||
ResponseRate.create!(subcategory:, school:, academic_year:,
|
||||
student_response_rate: 0, teacher_response_rate: 0, meets_student_threshold: false, meets_teacher_threshold: false)
|
||||
|
|
@ -46,14 +46,6 @@ describe "SQM Application" do
|
|||
|
||||
private
|
||||
|
||||
def username
|
||||
district.short_name
|
||||
end
|
||||
|
||||
def password
|
||||
"#{username}!"
|
||||
end
|
||||
|
||||
def overview_path
|
||||
district_school_overview_index_path(district, school, year: academic_year.range)
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue