Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Form submission refactor #1244

Merged
merged 22 commits into from
Dec 15, 2024
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
15dafa1
remove broadcast as it throws redis missing error in production; add …
kasugaijin Dec 11, 2024
2c8d684
Update associations and add migration to move adopter applications to…
kasugaijin Dec 11, 2024
08d5ca1
Update AdopterApplication to use Person; update seeds for new associa…
kasugaijin Dec 11, 2024
b5bc2dd
refactor models, controllers, views, tests to handle new associations
kasugaijin Dec 11, 2024
263a92f
remove creation of form submission on adopter sign up
kasugaijin Dec 12, 2024
1c21e17
implemenet routs, controllers, views and policies for staff to review…
kasugaijin Dec 12, 2024
3b5d6fb
lint
kasugaijin Dec 12, 2024
a5951d8
appease brakeman
kasugaijin Dec 12, 2024
704fa5c
add tests; add form answer header
kasugaijin Dec 13, 2024
6c100df
update tests
kasugaijin Dec 13, 2024
285ca2c
lint
kasugaijin Dec 13, 2024
efcaf6b
remove handling the nil person case, this should fail loudly as it sh…
kasugaijin Dec 13, 2024
efb41ff
remove partial as I am not using it
kasugaijin Dec 13, 2024
e8af96c
move empty state text to translation file
kasugaijin Dec 13, 2024
efc7508
fix
kasugaijin Dec 13, 2024
0fa6693
update foster links to fosterer data
kasugaijin Dec 13, 2024
022d69e
Update to show csv_timestamp and import date and show HH MM on the su…
kasugaijin Dec 14, 2024
9bade6c
Merge branch 'main' into form-submission-refactor
kasugaijin Dec 14, 2024
3ef2127
merge main
kasugaijin Dec 14, 2024
8806b4c
remove creation of formsubmission on creation of adopter user in seeds
kasugaijin Dec 14, 2024
85b50fc
lint
kasugaijin Dec 14, 2024
ba38ff4
add remaining translations
kasugaijin Dec 14, 2024
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
6 changes: 3 additions & 3 deletions app/controllers/organizations/adoptable_pets_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,14 @@ def index
def show
@adoptable_pet_info = CustomPage.first&.adoptable_pet_info

if current_user&.latest_form_submission
if current_user
@adoption_application =
AdopterApplication.find_by(
pet_id: @pet.id,
form_submission_id: current_user.latest_form_submission.id
person_id: current_user.person.id
) ||
@pet.adopter_applications.build(
form_submission: current_user.latest_form_submission
person: current_user.person
)
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def index
context: {organization: Current.organization}

@q = authorized_scope(
Pet.includes(adopter_applications: [form_submission: [:person]])
Pet.includes(adopter_applications: [:person])
.where.not(adopter_applications: {id: nil}).references(:person)
).ransack(params[:q])
@pets_with_applications = @q.result.includes(:adopter_applications)
Expand Down Expand Up @@ -41,13 +41,6 @@ def update
end
end

def show
authorize! AdopterApplication,
context: {organization: Current.organization}

@form_answers = @application.person.latest_form_submission.form_answers
end

private

def application_params
Expand Down
24 changes: 24 additions & 0 deletions app/controllers/organizations/staff/form_answers_controller.rb
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an endpoint we hit with turbo frame to load the form answers. I figured the policy is exactly the same as FormSubmission, so re-used that policy instead of creating a separate policy.

Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
module Organizations
module Staff
class FormAnswersController < Organizations::BaseController
before_action :context_authorize!, only: %i[index]
before_action :set_form_submission

def index
@form_answers = @form_submission.form_answers.order(created_at: :desc)
end

private

def set_form_submission
@form_submission = FormSubmission.find_by(id: params[:form_submission_id])
end

def context_authorize!
authorize! FormAnswer,
context: {organization: Current.organization},
with: Organizations::FormSubmissionPolicy
end
end
end
end
25 changes: 25 additions & 0 deletions app/controllers/organizations/staff/form_submissions_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
module Organizations
module Staff
class FormSubmissionsController < Organizations::BaseController
layout "dashboard"

before_action :context_authorize!, only: %i[index]
before_action :set_person

def index
@form_submissions = @person.form_submissions.order(created_at: :desc)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

created_at will be different than csv_timestamp. Do we want to use the csv timestamp?

We will have to deal with form submissions without the csv timestamp(custom forms) as well.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes that makes sense!

Copy link
Collaborator Author

@kasugaijin kasugaijin Dec 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Second thoughts, I suppose it depends on how we want to define the FormSubmission. Is it a capture of when they filled out the Google Form, or when the staff imported the data? I think it would be more 'accurate' if I change the column name from Submitted to Imported, then use the created_at date. This will remove any ambiguity.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how valuable the date of import is. For example, when a new org does their first import they may have multiple submissions from one person on separate dates. The import date would be the same day for all submissions.

When our custom forms is fully functional, then yes the date the form submission is created would make sense because that is when the form is submitted.

Copy link
Collaborator Author

@kasugaijin kasugaijin Dec 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok if we go with the csv_timestamp, we have to assume it will always be available on FormSubmission, at least until we start using custom forms. We do not validate this attribute on the model or database. I think that now we create the FormSubmission in the CSV Import service, we should at least have a validation for csv_timestamp presence. When we start to use the custom forms, we can update this validation to only run on CSV imports. Thoughts?

Copy link
Collaborator Author

@kasugaijin kasugaijin Dec 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a presence validation on FormSubmission.

I also updated to show both the csv_timestamp and the import date just so it's clear what each date is for. I also decided to show the HHMM for the csv_timestamp in case someone submits twice in one day - then the staff can tell which set of answers they are checking.

image

Copy link
Collaborator

@jmilljr24 jmilljr24 Dec 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! We can always add a user sort-able feature in the future. FYI this isn't a blocker for me, I just haven't had a chance to fully review the whole pr yet.

My first thought on validating the csv_timestamp presence is that it makes sense. After thinking through the import more I'm not sure. I'm trying not to get too into the weeds on what people might do to their csv date, but as of right now the the import will work just fine if the timestamp column entry is nil (the header has to be present). So for example, the row could have valid data and a matching email but no timestamp ( maybe the row was added manually by someone?) I don't think I'd want to skip that row.

Maybe a simpler approach is to conditionally display the timestamp for each submission in the view. That resolves the current issue as well as when the custom form is live.

Edit: I would need to tweak the import service a tiny bit, Time.parse returns an error when nil. Also just saw the the validation that you added. No problem having it. I will update the csv_import.

end

private

def set_person
@person = Person.find_by(id: params[:person_id])
end

def context_authorize!
authorize! FormSubmission,
context: {organization: Current.organization}
end
end
end
end
1 change: 0 additions & 1 deletion app/controllers/registrations_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ def create
super do |resource|
if resource.persisted?
resource.add_role(:adopter, Current.organization)
resource.person.form_submissions.create
end
end
end
Expand Down
37 changes: 16 additions & 21 deletions app/models/adopter_application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,33 @@
#
# Table name: adopter_applications
#
# id :bigint not null, primary key
# notes :text
# profile_show :boolean default(TRUE)
# status :integer default("awaiting_review")
# created_at :datetime not null
# updated_at :datetime not null
# form_submission_id :bigint not null
# organization_id :bigint not null
# pet_id :bigint not null
# id :bigint not null, primary key
# notes :text
# profile_show :boolean default(TRUE)
# status :integer default("awaiting_review")
# created_at :datetime not null
# updated_at :datetime not null
# organization_id :bigint not null
# person_id :bigint not null
# pet_id :bigint not null
#
# Indexes
#
# index_adopter_applications_on_form_submission_id (form_submission_id)
# index_adopter_applications_on_organization_id (organization_id)
# index_adopter_applications_on_pet_id (pet_id)
# index_adopter_applications_on_pet_id_and_form_submission_id (pet_id,form_submission_id) UNIQUE
# index_adopter_applications_on_organization_id (organization_id)
# index_adopter_applications_on_person_id (person_id)
# index_adopter_applications_on_pet_id (pet_id)
#
# Foreign Keys
#
# fk_rails_... (form_submission_id => form_submissions.id)
# fk_rails_... (person_id => people.id)
# fk_rails_... (pet_id => pets.id)
#
class AdopterApplication < ApplicationRecord
acts_as_tenant(:organization)
belongs_to :pet, touch: true
belongs_to :form_submission
belongs_to :person

has_one :person, through: :form_submission

validates :pet_id, uniqueness: {scope: :form_submission_id}

broadcasts_refreshes
kasugaijin marked this conversation as resolved.
Show resolved Hide resolved
validates :pet_id, uniqueness: {scope: :person_id}

enum :status, [:awaiting_review,
:under_review,
Expand All @@ -59,7 +54,7 @@ def self.retire_applications(pet_id:)
end

def applicant_name
form_submission.person.full_name.to_s
person.full_name.to_s
end

def withdraw
Expand Down
1 change: 1 addition & 0 deletions app/models/concerns/authorizable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ def staff?(organization)
manage_tasks
view_organization_dashboard
view_people
view_form_submissions
manage_faqs
]
).freeze
Expand Down
1 change: 0 additions & 1 deletion app/models/form_submission.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ class FormSubmission < ApplicationRecord
acts_as_tenant(:organization)
belongs_to :person

has_many :adopter_applications
has_many :form_answers, dependent: :destroy

delegate :user, to: :person
Expand Down
2 changes: 1 addition & 1 deletion app/models/match.rb
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ def belongs_to_same_organization_as_pet
end

def adopter_application
AdopterApplication.includes(:form_submission).find_by(pet:, form_submission: {person:})
AdopterApplication.find_by(pet: pet, person: person)
end

ransacker :status do
Expand Down
12 changes: 6 additions & 6 deletions app/models/organization.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,18 @@ class Organization < ApplicationRecord
# Rolify resource
resourcify

has_many :users
has_many :pets
has_many :default_pet_tasks
has_many :users, dependent: :destroy
has_many :pets, dependent: :destroy
has_many :default_pet_tasks, dependent: :destroy
has_many :forms, class_name: "CustomForm::Form", dependent: :destroy
has_many :faqs
has_many :faqs, dependent: :destroy

has_many :form_answers, dependent: :destroy
has_many :people
has_many :people, dependent: :destroy
has_one :form_submission, dependent: :destroy
has_one :custom_page, dependent: :destroy

has_many :locations, as: :locatable
has_many :locations, as: :locatable, dependent: :destroy
accepts_nested_attributes_for :locations

validates :phone_number, phone: {possible: true, allow_blank: true}
Expand Down
4 changes: 2 additions & 2 deletions app/models/person.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ class Person < ApplicationRecord
has_one :latest_form_submission, -> { order(created_at: :desc) }, class_name: "FormSubmission"
has_many :form_submissions, dependent: :destroy
has_many :form_answers, through: :form_submissions
has_many :adopter_applications, through: :form_submissions
has_many :adopter_applications, dependent: :destroy
has_many :likes, dependent: :destroy
has_many :liked_pets, through: :likes, source: :pet
has_one :location, as: :locatable
has_one :location, as: :locatable, dependent: :destroy
accepts_nested_attributes_for :location,
reject_if: ->(attributes) { attributes["city_town"].blank? }
has_many :matches # , dependent: :destroy
Expand Down
10 changes: 1 addition & 9 deletions app/policies/adopter_application_policy.rb
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
class AdopterApplicationPolicy < ApplicationPolicy
authorize :pet, optional: true

pre_check :verify_form_submission!, except: %i[index?]
pre_check :verify_pet_appliable!, only: %i[create?]

relation_scope do |relation|
return relation.none unless user.latest_form_submission

relation.where(form_submission_id: user.latest_form_submission.id)
relation.where(person_id: user.person.id)
end

def update?
Expand All @@ -34,10 +30,6 @@ def already_applied?
end
end

def verify_form_submission!
deny! unless user.latest_form_submission.present?
end

def verify_pet_appliable!
deny! if pet.application_paused
deny! if already_applied?
Expand Down
12 changes: 12 additions & 0 deletions app/policies/organizations/form_submission_policy.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module Organizations
class FormSubmissionPolicy < ApplicationPolicy
pre_check :verify_organization!
pre_check :verify_active_staff!

alias_rule :index?, to: :manage?

def manage?
permission?(:view_form_submissions)
end
end
end
4 changes: 2 additions & 2 deletions app/views/organizations/adoptable_pets/show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -137,13 +137,13 @@
<h4 class="mb-4 mt-3"><%= t('.in_love') %></h4>
<%= form_with model: [:adopter_fosterer, @adoption_application] do |form| %>
<%= form.hidden_field :pet_id, value: @adoption_application.pet_id %>
<%= form.hidden_field :form_submission_id, value: @adoption_application.form_submission_id %>
<%= form.hidden_field :person_id, value: @adoption_application.person_id %>
<%= form.submit t(".apply_to_adopt"),
class: "btn btn-primary",
data: {turbo: false}
%>
<% end %>
<% elsif AdopterApplication.exists?(form_submission: current_user.latest_form_submission, pet: @pet) %>
<% elsif AdopterApplication.exists?(person: current_user.person, pet: @pet) %>
<div class='d-flex align-items-center mt-3'>
<h4 class="me-2 mb-0">
<%= "#{t('organizations.adoptable_pets.show.application_status')} #{@adoption_application.human_enum_name(:status) || t('.status.default')}" %>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
<%= turbo_refreshes_with method: :morph, scroll: :preserve %>

<% pet = application.pet %>
<div class="card card-hover mx-1 my-4 col-sm-5" style='"overflow: hidden'>
<%= link_to image_tag(pet.images.attached? ? pet.images.first : 'coming_soon.jpg', class: 'card-img-top pet-card'), adoptable_pet_path(pet) %>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
<%= turbo_refreshes_with method: :morph, scroll: :preserve %>

<!-- table -->
<div class="card">
<table class="table mb-0 text-nowrap table-hover table-centered">
Expand All @@ -15,7 +13,6 @@
<% if applications.present? %>

<% applications.each do |app| %>
<%= turbo_stream_from app %>
<% pet = app.pet %>
<tr>
<td>
Expand Down Expand Up @@ -57,7 +54,7 @@
<%= t("dashboard.applications.no_applications")%>
</td>
</tr>
<%end%>
<% end %>
</tbody>
</table>
</div>

This file was deleted.

18 changes: 18 additions & 0 deletions app/views/organizations/staff/form_answers/index.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<%= turbo_frame_tag :form_answers do %>
<h4>Form Answers (<%= @form_submission.created_at.strftime("%Y-%m-%d") %>)</h4>

<% @form_answers.each do |form_answer| %>
<div class="justify-content-md-between mb-2 gx-3">
<div class="card">
<div id="<%= dom_id form_answer %>"class="card-body d-flex flex-sm-row flex-column justify-content-between border-bottom">
<div class="d-flex align-items-center">
<div>
<strong class="fs-4" >Q: <%= form_answer.question_snapshot %></strong>
<p class="mb-0">A: <%= form_answer.value %> </p>
</div>
</div>
</div>
</div>
</div>
<% end %>
<% end %>
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<div class="card">
<!-- table -->
<div class="table-responsive overflow-y-hidden">
<table class="table mb-2 text-nowrap table-hover table-centered">
<thead>
<tr>
<th scope="col">Submitted</th>
<th scope="col">Action</th>
</tr>
</thead>

<tbody>
<% form_submissions.each do |form_submission| %>
<tr>
<td>
<p class="mb-0"><%= form_submission.created_at.strftime("%Y-%m-%d") %></p>
</td>
<td>
<%= link_to "View Submission", staff_form_submission_form_answers_path(form_submission), data: { turbo_frame: "form_answers" } %>
</td>
</tr>
<% end %>
</tbody>
</table>
</div>
</div>
Loading
Loading