Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,17 @@ jobs:
bundle exec rails db:create
bundle exec rails db:migrate

- name: Run tests
- name: Run Non-JS tests
env:
RAILS_ENV: test
DATABASE_URL: postgres://postgres:postgres@localhost:5432/access_pdf_test
run: bundle exec rspec
run: bundle exec rspec spec/models spec/requests

- name: Run JS tests
env:
RAILS_ENV: test
DATABASE_URL: postgres://postgres:postgres@localhost:5432/access_pdf_test
run: bundle exec rspec spec/features

- name: Keep screenshots from failed system tests
uses: actions/upload-artifact@v4
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/eval.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ on:
description: Inference Model
options:
- gemini-2.5-pro-preview-03-25
- gemini-1.5-pro-latest
- gemini-2.0-flash
- gemini-2.0-flash-lite
evaluation_model_name:
type: choice
description: Evaluation Model
options:
- gemini-2.5-flash
- gemini-2.5-pro-preview-03-25
- gemini-1.5-pro-latest
runs_per_document:
description: 'Number of times generate evaluations per document'
required: false
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/python_components.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ jobs:
python -m pip install --upgrade pip
if [ -f ./python_components/ci/requirements.txt ]; then pip install -r ./python_components/ci/requirements.txt; fi
pip install python_components/evaluation
pip install python_components/document_inference
python -m spacy download en_core_web_sm
- name: Run Linting
run: |
Expand Down
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ group :test do
gem "rails-controller-testing"
gem "factory_bot_rails", "~> 6.5"
gem "capybara"
gem "capybara-email"
gem "webdrivers"
end

Expand All @@ -62,6 +63,7 @@ gem "aws-sdk-s3", "~> 1.194" # For S3 versioning support
gem "aws-sdk-secretsmanager"
gem "aws-sdk-lambda"
gem "aws-sigv4"
gem "aws-sdk-ses"

# API and Documentation
gem "grape", "~> 2.4"
Expand Down
14 changes: 13 additions & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ GEM
aws-sdk-secretsmanager (1.117.0)
aws-sdk-core (~> 3, >= 3.227.0)
aws-sigv4 (~> 1.5)
aws-sdk-ses (1.85.0)
aws-sdk-core (~> 3, >= 3.225.0)
aws-sigv4 (~> 1.5)
aws-sigv4 (1.12.1)
aws-eventstream (~> 1, >= 1.0.2)
base64 (0.3.0)
Expand Down Expand Up @@ -131,6 +134,9 @@ GEM
rack-test (>= 0.6.3)
regexp_parser (>= 1.5, < 3.0)
xpath (~> 3.2)
capybara-email (3.0.2)
capybara (>= 2.4, < 4.0)
mail
cgi (0.5.0)
chartkick (5.2.0)
childprocess (5.1.0)
Expand Down Expand Up @@ -286,7 +292,11 @@ GEM
parser (3.3.8.0)
ast (~> 2.4.1)
racc
pg (1.5.9)
pg (1.6.0)
pg (1.6.0-aarch64-linux)
pg (1.6.0-arm64-darwin)
pg (1.6.0-x86_64-darwin)
pg (1.6.0-x86_64-linux)
pp (0.6.2)
prettyprint
prettyprint (0.2.0)
Expand Down Expand Up @@ -518,13 +528,15 @@ DEPENDENCIES
aws-sdk-lambda
aws-sdk-s3 (~> 1.194)
aws-sdk-secretsmanager
aws-sdk-ses
aws-sigv4
bcrypt (~> 3.1)
better_errors (~> 2.10)
bootsnap
brakeman (~> 7.1)
bundler-audit (~> 0.9.2)
capybara
capybara-email
chartkick
cssbundling-rails (~> 1.4.3)
csv
Expand Down
83 changes: 83 additions & 0 deletions app/controllers/admin/users_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
class Admin::UsersController < ApplicationController
include Access

before_action :ensure_user_is_user_admin

before_action :set_user, only: [:edit, :update]
before_action :site_list, only: [:new, :create, :edit, :update]
before_action :set_minimum_password_length, only: [:new, :edit, :update]

def index
@users = User.all
end

def new
@user = User.new
render :new
end

def create
@user = User.new(user_params)
if @user.is_invited?
temp_password = SecureRandom.hex(12)
@user.password = temp_password
@user.password_confirmation = temp_password
end
if @user.save
begin
msg = "User added successfully"
if @user.send_new_account_instructions?
msg = "User added successfully. Instructions were emailed to the user."
end
redirect_to admin_users_path, notice: msg
rescue Net::SMTPFatalError => e
redirect_to admin_users_path, alert: e.message
end
else
render :new, status: 422
end
end

def edit
render :edit
end

def update
if params[:user][:password].blank?
params[:user].delete(:password)
params[:user].delete(:password_confirmation)
params[:user].delete(:current_password)
success = @user.update_without_password(user_params)
elsif @user.id == current_user.id
success = @user.update_with_password(user_params)
bypass_sign_in @user, scope: "user"
else
success = @user.update(user_params)
end
if success
redirect_to admin_users_path, notice: "User updated successfully"
else
render :edit, status: 422
end
end

private

def site_list
@sites = Site.all.order(:location, :name).group_by(&:location).map do |location, sites|
[location, sites.map { |site| [site.name, site.id] }]
end
end

def set_user
@user = User.find(params[:id])
end

def user_params
params.require(:user).permit(:email, :password, :password_confirmation, :current_password, :is_site_admin, :is_user_admin, :site_id, :is_invited)
end

def set_minimum_password_length
@minimum_password_length = User.password_length.min
end
end
14 changes: 10 additions & 4 deletions app/controllers/concerns/access.rb
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
module Access
def ensure_user_admin
unless current_user.is_admin?
def ensure_user_site_admin
unless current_user.present? && current_user.is_site_admin?
redirect_to sites_path, alert: "You don't have permission to access that page."
end
end

def ensure_user_is_user_admin
unless current_user.present? && current_user.is_user_admin?
redirect_to sites_path, alert: "You don't have permission to access that page."
end
end

def ensure_user_site_access
if !current_user.is_admin? && (current_user.site.nil? || current_user.site.id != @site.id)
if current_user.nil? || !current_user.is_site_admin? && (current_user.site.nil? || current_user.site.id != @site.id)
redirect_to sites_path, alert: "You don't have permission to access that site."
end
end

def ensure_user_document_access
if !current_user.is_admin? && (current_user.site.nil? || current_user.site.documents.find(@document.id).nil?)
if current_user.nil? || !current_user.is_site_admin? && (current_user.site.nil? || current_user.site.documents.find(@document.id).nil?)
redirect_to sites_path, alert: "You don't have permission to perform that action on document."
end
end
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/configurations_controller.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
class ConfigurationsController < AuthenticatedController
include Access

before_action :ensure_user_admin
before_action :ensure_user_site_admin

ASAP_API_USER = "/asap-pdf/production/RAILS_API_USER-20250613220933079900000001"
ASAP_API_PASSWORD = "/asap-pdf/production/RAILS_API_PASSWORD-20250613220933080000000003"
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/sites_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class SitesController < AuthenticatedController
before_action :ensure_user_site_access, only: [:insights, :show, :edit, :update, :destroy]

def index
@sites = if current_user.is_admin?
@sites = if current_user.is_site_admin?
Site.all
else
current_user.site.nil? ? [] : [current_user.site]
Expand Down
40 changes: 12 additions & 28 deletions app/controllers/users/passwords_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,18 @@

class Users::PasswordsController < Devise::PasswordsController
layout "centered"
# GET /resource/password/new
# def new
# super
# end

# POST /resource/password
# def create
# super
# end
def create
self.resource = resource_class.send_reset_password_instructions(resource_params)
set_flash_message! :notice, :send_paranoid_instructions
resource.email = nil
redirect_back(fallback_location: new_password_path(resource_name))
end

# GET /resource/password/edit?reset_password_token=abcdef
# def edit
# super
# end

# PUT /resource/password
# def update
# super
# end

# protected

# def after_resetting_password_path_for(resource)
# super(resource)
# end

# The path used after sending reset password instructions
# def after_sending_reset_password_instructions_path_for(resource_name)
# super(resource_name)
# end
def edit
@is_invitation = params[:is_invitation] == "1"
self.resource = resource_class.new
set_minimum_password_length
resource.reset_password_token = params[:reset_password_token]
end
end
64 changes: 6 additions & 58 deletions app/controllers/users/registrations_controller.rb
Original file line number Diff line number Diff line change
@@ -1,63 +1,11 @@
# frozen_string_literal: true

class Users::RegistrationsController < Devise::RegistrationsController
layout "centered"
# before_action :configure_sign_up_params, only: [:create]
# before_action :configure_account_update_params, only: [:update]
def new
redirect_to root_path
end

# GET /resource/sign_up
# def new
# super
# end

# POST /resource
# def create
# super
# end

# GET /resource/edit
# def edit
# super
# end

# PUT /resource
# def update
# super
# end

# DELETE /resource
# def destroy
# super
# end

# GET /resource/cancel
# Forces the session data which is usually expired after sign
# in to be expired now. This is useful if the user wants to
# cancel oauth signing in/up in the middle of the process,
# removing all OAuth session data.
# def cancel
# super
# end

# protected

# If you have extra params to permit, append them to the sanitizer.
# def configure_sign_up_params
# devise_parameter_sanitizer.permit(:sign_up, keys: [:attribute])
# end

# If you have extra params to permit, append them to the sanitizer.
# def configure_account_update_params
# devise_parameter_sanitizer.permit(:account_update, keys: [:attribute])
# end

# The path used after sign up.
# def after_sign_up_path_for(resource)
# super(resource)
# end

# The path used after sign up for inactive accounts.
# def after_inactive_sign_up_path_for(resource)
# super(resource)
# end
def create
redirect_to root_path
end
end
4 changes: 3 additions & 1 deletion app/javascript/controllers/modal_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ export default class extends Controller {

connect() {
super.connect();
this.wrapperTarget.addEventListener('close', this.onModalClose.bind(this))
if (this.hasWrapperTarget) {
this.wrapperTarget.addEventListener('close', this.onModalClose.bind(this))
}
}

submitAndClose(event) {
Expand Down
11 changes: 9 additions & 2 deletions app/mailers/application_mailer.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
class ApplicationMailer < ActionMailer::Base
default from: "from@example.com"
class ApplicationMailer < Devise::Mailer
default from: "Code for America <admin@demo.codeforamerica.ai>"

layout "mailer"

def new_account_instructions(record, token)
@token = token
@resource = record
mail(to: @resource.email, subject: "Welcome! Set up your account", template_path: "users/mailer")
end
end
2 changes: 1 addition & 1 deletion app/models/document.rb
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ def inference_summary!
api_host = "https://demo.codeforamerica.ai"
end
payload = {
model_name: "gemini-1.5-pro-latest",
model_name: "gemini-2.0-flash",
documents: [{id: id, title: file_name, url: normalized_url, purpose: document_category}],
page_limit: 7,
inference_type: "summary",
Expand Down
Loading